fuel-library/utils/jenkins/fuel_noop_tests.rb
Vladimir Kuklin 2cd8c10151 Add noop tests for files injection
1) Add test to check whether catalog contains
injection of files which actually should be
installed as packages
2) Add more fixtures with astute yamls
3) Shared examples structure refactoring
4) Remove File.exists? checks from install_ssh_keys
5) Add rspec and puppet debug options
6) Misc fixes to make rspec actually work

Change-Id: I8217594cd9f2c0f19c840c0abed37d94ff80eb75
blueprint: package-fuel-components
2015-05-13 21:30:25 +03:00

480 lines
14 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
require 'rubygems'
require 'find'
require 'optparse'
module NoopTests
GLOBALS_SPEC = 'globals/globals_spec.rb'
RSPEC_OPTIONS = '--format documentation --color --tty --backtrace'
ASTUTE_YAML_VAR = 'SPEC_ASTUTE_FILE_NAME'
BUNDLE_DIR = '.bundled_gems'
BUNDLE_VAR = 'GEM_HOME'
GLOBALS_PREFIX = 'globals_yaml_for_'
PUPPET_GEM_VERSION = '~> 3.4.0'
TEST_LIBRARY_DIR = 'spec/hosts'
def self.options
return @options if @options
@options = {}
optparse = OptionParser.new do|opts|
opts.separator 'Main options:'
opts.on('-b', '--bundle', 'Use bundle to setup environment') do
@options[:bundle] = true
end
opts.on('-m', '--missing', 'Find missing spec files') do
@options[:missing_specs] = true
end
opts.on('-i', '--individually', 'Run each spec individually') do
@options[:run_individually] = true
end
opts.on('-g', '--purge_globals', 'Purge globals yaml files') do
@options[:purge_globals] = true
end
opts.on('-a', '--astute_yaml_dir DIR', 'Path to astute_yaml folder') do |dir|
@options[:astute_yaml_dir] = dir
ENV['SPEC_YAML_DIR'] = dir
end
opts.on('-Y', '--list_yamls', 'List all astute yaml files') do
@options[:list_yamls] = true
end
opts.on('-S', '--list_specs', 'List all noop spec files') do
@options[:list_specs] = true
end
opts.separator 'Filter options:'
opts.on('-s', '--specs SPEC1,SPEC2', Array, 'Run only these specs. Example: "hosts/hosts_spec.rb"') do |specs|
@options[:filter_specs] = specs
end
opts.on('-y', '--yamls YAML1,YAML2', Array, 'Run only these yamls. Example: "novanet-primary-controller.yaml"') do |yamls|
@options[:filter_yamls] = yamls
end
opts.on('-e', '--examples STR1,STR2', Array, 'Run only these exemples. Example: "should compile"') do |examples|
@options[:filter_examples] = examples
end
opts.separator 'Debug options:'
opts.on('-c', '--console', 'Run PRY console') do
@options[:console] = true
end
opts.on('-d', '--debug', 'Show debug') do
@options[:debug] = true
end
opts.separator 'Spec options:'
opts.on('-F', '--file_resources DIR', 'Save file resources to this dir') do |dir|
ENV['SPEC_SAVE_FILE_RESOURCES'] = dir
end
opts.on('-P', '--package_resources DIR', 'Save package resources to this dir') do |dir|
ENV['SPEC_SAVE_PACKAGE_RESOURCES'] = dir
end
opts.on('-C', '--catalog_debug', 'Show catalog debug output') do
ENV['SPEC_CATALOG_DEBUG'] = 'YES'
end
opts.on('-G', '--spec_generate', 'Generate specs for catalogs') do
ENV['SPEC_SPEC_GENERATE'] = 'YES'
end
opts.on('-T', '--spec_status', 'Show spec status blocks') do
ENV['SPEC_SHOW_STATUS'] = 'YES'
end
opts.on('-O', '--spec_coverage', 'Show spec coverage statistics') do
ENV['SPEC_COVERAGE'] = 'YES'
end
opts.on('-D', '--test_ubuntu', 'Run tests for Ubuntu facts') do
ENV['SPEC_TEST_UBUNTU'] = 'YES'
end
opts.on('-R', '--test_centos', 'Run tests for CentOS facts') do
ENV['SPEC_TEST_CENTOS'] = 'YES'
end
opts.on('-r', '--rspec_debug', 'Show debug messages in rspec tests') do
ENV['SPEC_RSPEC_DEBUG'] = 'YES'
end
opts.on('-p', '--puppet_debug', 'Show Puppet debug messages') do
ENV['SPEC_PUPPET_DEBUG'] = 'YES'
end
opts.on('-B', '--puppet_binary_files', 'Check if Puppet installs binary files') do
ENV['SPEC_PUPPET_BINARY_FILES'] = 'YES'
end
opts.on('-L', '--puppet_logs_dir DIR', 'Save Puppet logs in this directory') do |dir|
ENV['SPEC_PUPPET_LOGS_DIR'] = dir
@options[:puppet_logs_dir] = dir
end
end
optparse.parse!
@options
end
# PATHS #
# workspace directory where gem bundle will be created
# is passed from Jenkins or default value is used
# @@return [String]
def self.workspace
workspace = ENV['WORKSPACE']
unless workspace
workspace = '/tmp/noop'
Dir.mkdir workspace unless File.directory? workspace
end
unless File.directory? workspace
raise "Workspace '#{workspace}' is not a directory!"
end
workspace
end
# the root directory of noop tests
# @return [String]
def self.noop_tests_directory
return @noop_tests_directory if @noop_tests_directory
@noop_tests_directory = File.expand_path File.absolute_path File.join File.dirname(__FILE__), '..', '..', 'tests', 'noop'
end
# the folder where astute yaml files are found
# can be overridden by options
# @return [String]
def self.astute_yaml_directory
return options[:astute_yaml_dir] if options[:astute_yaml_dir] and File.directory? options[:astute_yaml_dir]
File.join noop_tests_directory, 'astute.yaml'
end
# the directory where actual tests library is found
# @return [String]
def self.test_spec_directory
File.join noop_tests_directory, TEST_LIBRARY_DIR
end
# the directory where the library of modular tasks can be found
# @return [String]
def self.modular_tasks_directory
File.expand_path File.join File.dirname(__FILE__), '..', '..', 'deployment', 'puppet', 'osnailyfacter', 'modular'
end
# LISTERS #
# find all modular task files
# @return [Array<String>]
def self.modular_puppet_task_files
files = []
Find.find(modular_tasks_directory) do |file|
next unless File.file? file
next unless file.end_with? '.pp'
file.gsub! modular_tasks_directory + '/', ''
files << file
end
files
end
# find all astute yaml files
# @return [Array<String>]
def self.astute_yaml_files
files = []
Dir.new(astute_yaml_directory).each do |file|
next if file.start_with? GLOBALS_PREFIX
next unless file.end_with? '.yaml'
files << file
end
files
end
# find all noop spec files
# @return [Array<String>]
def self.noop_spec_files
files = []
Find.find(test_spec_directory) do |file|
next unless File.file? file
next unless file.end_with? '_spec.rb'
file.gsub! test_spec_directory + '/', ''
files << file
end
files
end
# ACTIONS #
# run the code block inside the tests directory
# and then return back
def self.inside_noop_tests_directory
current_directory = Dir.pwd
Dir.chdir noop_tests_directory
result = yield
Dir.chdir current_directory if current_directory
result
end
# find all modular tasks that have no corresponding specs
# @return [Array<String>]
def self.puppet_tasks_without_specs
tasks = []
modular_puppet_task_files.each do |task|
spec = task.gsub '.pp', '_spec.rb'
spec_path = File.join test_spec_directory, spec
tasks << task unless File.exist? spec_path
end
tasks
end
# append relative path prefix to a spec name
# @param [String] spec Spec name
# @return [String]
def self.spec_path(spec)
"'#{File.join TEST_LIBRARY_DIR, spec}'"
end
# run the rspec commands with some options
# return: [ success, report ]
# @param [String] spec Spec file or pattern
# @return [Array<TrueClass,FalseClass,NilClass>] success and empty report array
def self.rspec(spec)
inside_noop_tests_directory do
command = "rspec #{RSPEC_OPTIONS} #{spec}"
command = 'bundle exec ' + command if options[:bundle]
if options[:filter_examples]
options[:filter_examples].each do |example|
command = command + " -e #{example}"
end
end
if options[:puppet_logs_dir]
command = command + " --deprecation-out #{File.join options[:puppet_logs_dir], 'deprecations.log'}"
end
debug "RUN: #{command}"
system command
[ $?.exitstatus == 0, nil ]
end
end
# run all specs together using pattern
# return: [ success, report ]
# @return [Array<TrueClass,FalseClass,NilClass>] success and empty report array
def self.run_all_specs
include_prefix = '--pattern'
exclude_prefix = '--exclude-pattern'
exclude_pattern = "#{exclude_prefix} #{spec_path GLOBALS_SPEC}"
if options[:filter_specs]
include_pattern = "#{include_prefix} #{options[:filter_specs].map { |s| spec_path s }.join ','}"
else
include_pattern = "#{include_prefix} #{spec_path '**/*_spec.rb'}"
end
rspec "#{exclude_pattern} #{include_pattern}"
end
# run the globals task for the given yaml file
# if there is no globals yaml already present
# @param [String] astute_yaml YAML file
def self.globals(astute_yaml)
globals_file = File.join astute_yaml_directory, GLOBALS_PREFIX + astute_yaml
return true if File.file? globals_file
rspec spec_path(GLOBALS_SPEC)
end
# output a debug line is debug is enabled
# @param [String] msg The message line
def self.debug(msg)
puts msg if options[:debug]
end
# decide if this spec should be included
# @param [String] spec Spec file
# @return [TrueClass,FalseClass]
def self.filter_specs(spec)
return false if spec == GLOBALS_SPEC
return true unless options[:filter_specs]
options[:filter_specs].include? spec
end
# decide if this yaml should be included
# @param [String] yaml Yaml file
# @return [TrueClass,FalseClass]
def self.filter_yamls(yaml)
return true unless options[:filter_yamls]
options[:filter_yamls].map { |y| y.gsub('.yaml', '') }.include? yaml.gsub('.yaml', '')
end
# trigger skip of the current yaml file
# when individual run is enabled
# second trigger forces exit
def self.skip
raise SystemExit if @skip
@skip = true
end
# run the code block for every astute yaml file
# return [ global success, Hash of reports for every yaml ]
# @return [Array<TrueClass,FalseClass,Hash>]
def self.for_every_astute_yaml
prepare_bundle if options[:bundle]
results = {}
errors = 0
astute_yaml_files.each do |astute_yaml|
next unless filter_yamls astute_yaml
ENV[ASTUTE_YAML_VAR] = astute_yaml
debug "=== YAML: '#{astute_yaml}' ==="
globals astute_yaml
success, report = yield
errors += 1 unless success
results[astute_yaml] = {
:success => success,
:report => report,
}
end
[ errors == 0, results ]
end
# run every spec file individually
# return report for every spec
# return [ global success, Hash of reports for every spec ]
# @return [Array<TrueClass,FalseClass,Hash>]
def self.run_all_specs_individually
results = {}
errors = 0
# trap('SIGINT') do
# skip
# end
noop_spec_files.each do |spec|
if @skip
@skip = false
debug color(31, 'Skipping current yaml file!')
return [ errors == 0, results ]
end
next if spec == GLOBALS_SPEC
next unless filter_specs spec
debug "--- SPEC: '#{spec}' ---"
success, report = rspec spec_path(spec)
errors += 1 unless success
results[spec] = {
:success => success,
:report => report,
}
end
[ errors == 0, results ]
end
# setup the bundle directory
def self.prepare_bundle
ENV['PUPPET_GEM_VERSION'] = PUPPET_GEM_VERSION unless ENV['PUPPET_GEM_VERSION']
inside_noop_tests_directory do
`bundle --version`
raise 'Bundle is not installed!' if $?.exitstatus != 0
ENV[BUNDLE_VAR] = File.join workspace, BUNDLE_DIR
system 'bundle update'
raise 'Could not prepare bundle environment!' if $?.exitstatus != 0
end
end
# add color codes to a line
# @param [Integer] code Color code
# @param [String] string Text string
def self.color(code, string)
"\033[#{code}m#{string}\033[0m"
end
def self.status_string(success)
if success
color 32, 'OK'
else
color 31, 'FAIL'
end
end
# calculate the maximum length of the hash keys
# used to align columns
# @param [Hash]
# @return [Integer]
def self.max_key_length(hash)
hash.keys.inject(0) do |ml, key|
key = key.to_s
ml = key.size if key.size > ml
ml
end
end
# output the test results
# @param [Hash]
def self.show_results(results)
max_astute_yaml_length = max_key_length results
results.each do |astute_yaml, yaml_result|
puts "-> #{astute_yaml.ljust max_astute_yaml_length} #{status_string yaml_result[:success]}"
if yaml_result[:report].is_a? Hash
max_spec_length = max_key_length yaml_result[:report]
yaml_result[:report].each do |spec, spec_result|
puts " * #{spec.ljust max_spec_length} #{status_string spec_result[:success]}"
end
end
end
end
# remove all globals yaml files
def self.purge_globals
Dir.new(astute_yaml_directory).each do |file|
path = File.join astute_yaml_directory, file
next unless File.file? path
next unless file.start_with? GLOBALS_PREFIX
next unless file.end_with? '.yaml'
debug "Remove: '#{path}'"
File.unlink path
end
end
# the main function
def self.main
if options[:console]
require 'pry'
self.pry
exit 0
end
if options[:missing_specs]
missing_specs = puppet_tasks_without_specs
if missing_specs.any?
puts color(31, "Missing specs for tasks: #{missing_specs.join ', '}")
exit missing_specs.length
end
end
if options[:list_yamls]
astute_yaml_files.each do |file|
puts file
end
exit 0
end
if options[:list_specs]
noop_spec_files.each do |file|
puts file
end
exit 0
end
if options[:purge_globals]
purge_globals
exit 0
end
success, result = for_every_astute_yaml do
if options[:run_individually]
run_all_specs_individually
else
run_all_specs
end
end
show_results result
exit 1 unless success
end
end
NoopTests.main if __FILE__ == $0