lib/puppet-catalog-test/test_runner.rb
require "yaml"
require "parallel"
require "puppet-catalog-test/test_case"
require "puppet-catalog-test/stdout_reporter"
require "puppet-catalog-test/puppet_adapter_factory"
module PuppetCatalogTest
class TestRunner
attr_accessor :exit_on_fail
attr_accessor :reporter
attr_reader :test_cases
attr_reader :total_duration
def initialize(puppet_config, stdout_target = $stdout)
if !puppet_config
raise ArgumentError, "No puppet_config hash supplied"
end
@test_cases = []
@exit_on_fail = true
@out = stdout_target
@puppet_adapter = PuppetAdapterFactory.create_adapter(puppet_config)
if puppet_config[:xml]
require 'puppet-catalog-test/junit_xml_reporter'
@reporter = PuppetCatalogTest::JunitXmlReporter.new("puppet-catalog-test", "puppet_catalogs.xml")
else
@reporter = StdoutReporter.new(stdout_target)
end
@total_duration = nil
end
def load_scenario_yaml(yaml_file, filter = nil)
scenarios = YAML.load_file(yaml_file)
scenarios.each do |tc_name, facts|
next if tc_name =~ /^__/
if filter
next if filter.exclude_pattern && tc_name.match(filter.exclude_pattern)
next if filter.include_pattern && !tc_name.match(filter.include_pattern)
end
add_test_case(tc_name, facts)
end
end
def load_all(filter = Filter.new, facts = {})
nodes = collect_puppet_nodes(filter)
nodes.each do |n|
node_facts = facts.dup
if !node_facts.has_key?('fqdn')
node_facts['fqdn'] = n
end
add_test_case(n, node_facts)
end
end
def add_test_case(tc_name, facts)
tc = TestCase.new
tc.name = tc_name
tc.facts = facts
@test_cases << tc
end
def compile_catalog(node_fqdn, facts = {})
hostname = node_fqdn.split('.').first
facts['hostname'] = hostname
node = @puppet_adapter.create_node(hostname, facts)
@puppet_adapter.compile(node)
end
def collect_puppet_nodes(filter)
nodes = @puppet_adapter.nodes
if filter.exclude_pattern
nodes.delete_if { |node| node.match(filter.exclude_pattern) }
end
if filter.include_pattern
nodes.delete_if { |node| !node.match(filter.include_pattern) }
end
nodes
end
def run_tests!
@out.puts "[INFO] Using puppet #{@puppet_adapter.version}"
run_start = Time.now
proc_count = Parallel.processor_count
processed_test_cases = Parallel.map(@test_cases, :in_processes => proc_count) do |tc|
begin
tc_start_time = Time.now
if tc.facts['fqdn'].nil?
raise "fact 'fqdn' must be defined"
else
compile_catalog(tc.facts['fqdn'], tc.facts)
tc.duration = Time.now - tc_start_time
tc.passed = true
@reporter.report_passed_test_case(tc)
end
rescue => error
if $DEBUG
p error
puts e.backtrace
end
tc.duration = Time.now - tc_start_time
tc.error = error.message
tc.passed = false
@reporter.report_failed_test_case(tc)
end
tc
end
@test_cases = processed_test_cases
@total_duration = Time.now - run_start
@reporter.summarize(self)
if test_cases.any? { |tc| tc.passed == false }
exit 1 if @exit_on_fail
return false
end
true
end
end
end