cem_acpt 0.8.8 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +0 -3
  3. data/Gemfile.lock +9 -1
  4. data/README.md +95 -13
  5. data/cem_acpt.gemspec +2 -1
  6. data/lib/cem_acpt/action_result.rb +8 -2
  7. data/lib/cem_acpt/actions.rb +153 -0
  8. data/lib/cem_acpt/bolt/cmd/base.rb +174 -0
  9. data/lib/cem_acpt/bolt/cmd/output.rb +315 -0
  10. data/lib/cem_acpt/bolt/cmd/task.rb +59 -0
  11. data/lib/cem_acpt/bolt/cmd.rb +22 -0
  12. data/lib/cem_acpt/bolt/errors.rb +49 -0
  13. data/lib/cem_acpt/bolt/helpers.rb +52 -0
  14. data/lib/cem_acpt/bolt/inventory.rb +62 -0
  15. data/lib/cem_acpt/bolt/project.rb +38 -0
  16. data/lib/cem_acpt/bolt/summary_results.rb +96 -0
  17. data/lib/cem_acpt/bolt/tasks.rb +181 -0
  18. data/lib/cem_acpt/bolt/tests.rb +415 -0
  19. data/lib/cem_acpt/bolt/yaml_file.rb +74 -0
  20. data/lib/cem_acpt/bolt.rb +142 -0
  21. data/lib/cem_acpt/cli.rb +6 -0
  22. data/lib/cem_acpt/config/base.rb +4 -0
  23. data/lib/cem_acpt/config/cem_acpt.rb +7 -1
  24. data/lib/cem_acpt/core_ext.rb +25 -0
  25. data/lib/cem_acpt/goss/api/action_response.rb +4 -0
  26. data/lib/cem_acpt/goss/api.rb +23 -25
  27. data/lib/cem_acpt/logging/formatter.rb +3 -3
  28. data/lib/cem_acpt/logging.rb +17 -1
  29. data/lib/cem_acpt/test_data.rb +2 -0
  30. data/lib/cem_acpt/test_runner/log_formatter/base.rb +73 -0
  31. data/lib/cem_acpt/test_runner/log_formatter/bolt_error_formatter.rb +65 -0
  32. data/lib/cem_acpt/test_runner/log_formatter/bolt_output_formatter.rb +54 -0
  33. data/lib/cem_acpt/test_runner/log_formatter/bolt_summary_results_formatter.rb +64 -0
  34. data/lib/cem_acpt/test_runner/log_formatter/goss_action_response.rb +17 -30
  35. data/lib/cem_acpt/test_runner/log_formatter/goss_error_formatter.rb +31 -0
  36. data/lib/cem_acpt/test_runner/log_formatter/standard_error_formatter.rb +35 -0
  37. data/lib/cem_acpt/test_runner/log_formatter.rb +17 -5
  38. data/lib/cem_acpt/test_runner/test_results.rb +150 -0
  39. data/lib/cem_acpt/test_runner.rb +153 -53
  40. data/lib/cem_acpt/utils/files.rb +189 -0
  41. data/lib/cem_acpt/utils/finalizer_queue.rb +73 -0
  42. data/lib/cem_acpt/utils/shell.rb +13 -4
  43. data/lib/cem_acpt/version.rb +1 -1
  44. data/sample_config.yaml +13 -0
  45. metadata +41 -5
  46. data/lib/cem_acpt/test_runner/log_formatter/error_formatter.rb +0 -33
@@ -1,53 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'base'
4
+
3
5
  module CemAcpt
4
6
  module TestRunner
5
7
  module LogFormatter
6
8
  # Formats the results of a Goss action
7
- class GossActionResponse
8
- INDENT = ' '
9
-
10
- def initialize(config, instance_names_ips)
9
+ class GossActionResponse < Base
10
+ def initialize(config, instance_names_ips, subject: nil)
11
+ super(subject)
11
12
  @config = config
12
13
  @instance_names_ips = instance_names_ips
13
14
  end
14
15
 
15
- def inspect
16
- to_s
17
- end
18
-
19
- def to_s
20
- "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
21
- end
22
-
23
- def summary(response)
24
- new_summary_message(response)
16
+ def summary(response = nil)
17
+ super(response)
18
+ new_summary_message(log_subject)
25
19
  end
26
20
 
27
- def results(response)
28
- new_results_message(response.results)
21
+ def results(response = nil)
22
+ super(response)
23
+ new_results_message(log_subject.results)
29
24
  end
30
25
 
31
- def host_name(response)
32
- name_from_ip(response.host)
26
+ def host_name(response = nil)
27
+ super(response)
28
+ name_from_ip(log_subject.host)
33
29
  end
34
30
 
35
- def test_name(response)
36
- test_from_ip(response.host)
31
+ def test_name(response = nil)
32
+ super(response)
33
+ test_from_ip(log_subject.host)
37
34
  end
38
35
 
39
36
  private
40
37
 
41
- def normalize_whitespace(str)
42
- raise ArgumentError, 'str must be a String' unless str.is_a?(String)
43
-
44
- str.gsub(%r{(\n|\r|\t)}, ' ').gsub(%r{\s{2,}}, ' ').strip
45
- end
46
-
47
- def success_str(success)
48
- success ? 'passed' : 'failed'
49
- end
50
-
51
38
  def name_from_ip(ip)
52
39
  @instance_names_ips.each do |name, val|
53
40
  return name if val['ip'] == ip
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module CemAcpt
6
+ module TestRunner
7
+ module LogFormatter
8
+ class GossErrorFormatter < Base
9
+ def summary(subject = nil)
10
+ super(subject)
11
+ "Error: #{log_subject.summary}"
12
+ end
13
+
14
+ def results(response = nil)
15
+ super(response)
16
+ [log_subject.summary, log_subject.results.join("\n")]
17
+ end
18
+
19
+ def host_name(response = nil)
20
+ super(response)
21
+ "Error: #{log_subject.error.class.name}"
22
+ end
23
+
24
+ def test_name(response = nil)
25
+ super(response)
26
+ "Error: #{log_subject.error.class.name}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module CemAcpt
6
+ module TestRunner
7
+ module LogFormatter
8
+ class StandardErrorFormatter < Base
9
+ def summary(subject = nil)
10
+ super(subject)
11
+ "Error: #{log_subject.detailed_message}"
12
+ end
13
+
14
+ def results(response = nil)
15
+ super(response)
16
+ [
17
+ "Error: #{log_subject.class.name}",
18
+ log_subject.detailed_message,
19
+ log_subject.backtrace.join("\n"),
20
+ ]
21
+ end
22
+
23
+ def host_name(response = nil)
24
+ super(response)
25
+ "Error: #{log_subject.class.name}"
26
+ end
27
+
28
+ def test_name(response = nil)
29
+ super(response)
30
+ "Error: #{log_subject.class.name}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,17 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'log_formatter/bolt_summary_results_formatter'
4
+ require_relative 'log_formatter/bolt_output_formatter'
3
5
  require_relative 'log_formatter/goss_action_response'
4
- require_relative 'log_formatter/error_formatter'
6
+ require_relative 'log_formatter/goss_error_formatter'
7
+ require_relative 'log_formatter/standard_error_formatter'
5
8
 
6
9
  module CemAcpt
7
10
  module TestRunner
8
11
  # Holds classes for formatting test runner results
9
12
  module LogFormatter
10
- def self.new_formatter(result, *args, **kwargs)
11
- if result.error?
12
- ErrorFormatter.new
13
+ def self.new_formatter(result, *args, **_kwargs)
14
+ case result
15
+ when CemAcpt::Goss::Api::ActionResponse
16
+ if result.error?
17
+ GossErrorFormatter.new(result)
18
+ else
19
+ GossActionResponse.new(*args, subject: result)
20
+ end
21
+ when CemAcpt::Bolt::SummaryResults
22
+ BoltSummaryResultsFormatter.new(*args, subject: result)
23
+ when StandardError
24
+ StandardErrorFormatter.new(result)
13
25
  else
14
- GossActionResponse.new(*args)
26
+ raise ArgumentError, "result must be a CemAcpt::Goss::Api::ActionResponse, CemAcpt::Bolt::SummaryResults, or StandardError, got #{result.class}"
15
27
  end
16
28
  end
17
29
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'log_formatter'
4
+
5
+ module CemAcpt
6
+ module TestRunner
7
+ # Namespace for all test result classes and methods
8
+ module TestResults
9
+ def self.new(config = nil, instance_names_ips = nil)
10
+ Results.new(config, instance_names_ips)
11
+ end
12
+
13
+ # Class that manages test results
14
+ class Results
15
+ attr_accessor :config, :instance_names_ips
16
+
17
+ def initialize(config = nil, instance_names_ips = nil)
18
+ @results_queue = Queue.new
19
+ @config = config
20
+ @instance_names_ips = instance_names_ips
21
+ end
22
+
23
+ def combine(other)
24
+ new_res_queue_data = (to_a + other.to_a).compact.uniq
25
+ @results_queue = Queue.new(new_res_queue_data)
26
+
27
+ self
28
+ end
29
+
30
+ def <<(result)
31
+ case result
32
+ when CemAcpt::Goss::Api::ActionResponse, CemAcpt::Bolt::SummaryResults
33
+ @results_queue << TestActionResult.new(result, new_formatter(result))
34
+ when StandardError
35
+ @results_queue << TestErrorActionResult.new(result, new_formatter(result))
36
+ else
37
+ raise ArgumentError, "result must be a CemAcpt::Goss::Api::ActionResponse, CemAcpt::Bolt::SummaryResults, or StandardError, got #{result.class}"
38
+ end
39
+ end
40
+
41
+ def to_a
42
+ results = []
43
+ @results_queue.close unless @results_queue.closed?
44
+ while (r = @results_queue.pop)
45
+ results << r
46
+ end
47
+ @results_queue = Queue.new(results)
48
+ results
49
+ end
50
+
51
+ def method_missing(method_name, *args, **kwargs, &block)
52
+ @results_queue.send(method_name, *args, **kwargs, &block)
53
+ end
54
+
55
+ def respond_to_missing?(method_name, include_private = false)
56
+ @results_queue.respond_to?(method_name, include_private) || super
57
+ end
58
+
59
+ private
60
+
61
+ def new_formatter(result)
62
+ CemAcpt::TestRunner::LogFormatter.new_formatter(result, @config, @instance_names_ips)
63
+ end
64
+ end
65
+
66
+ # Wrapper class for the result of an action. Provides a common interface for
67
+ # getting reportable data from the result.
68
+ class TestActionResult
69
+ attr_reader :result, :log_formatter
70
+
71
+ def initialize(result, log_formatter = nil)
72
+ @result = result
73
+ @log_formatter = log_formatter
74
+ end
75
+
76
+ def error?
77
+ (@result.respond_to?(:error?) && @result.error?) || false
78
+ end
79
+
80
+ def method_missing(method_name, *args, **kwargs, &block)
81
+ if @result.respond_to?(method_name)
82
+ @result.send(method_name, *args, **kwargs, &block)
83
+ else
84
+ super
85
+ end
86
+ end
87
+
88
+ def respond_to_missing?(method_name, include_private = false)
89
+ @result.respond_to?(method_name, include_private) || super
90
+ end
91
+ end
92
+
93
+ # Wrapper class for an error raised during an action.
94
+ class TestErrorActionResult
95
+ attr_reader :error, :log_formatter
96
+
97
+ def initialize(error, log_formatter = nil)
98
+ @error = error
99
+ @log_formatter = log_formatter
100
+ end
101
+ alias result error
102
+
103
+ def error?
104
+ true
105
+ end
106
+
107
+ def success?
108
+ false
109
+ end
110
+
111
+ def to_s
112
+ "#<#{@error.class.name}:0x#{@error.object_id.to_s(16)}>"
113
+ end
114
+
115
+ def inspect
116
+ to_s
117
+ end
118
+
119
+ def to_h
120
+ {
121
+ class: @error.class.name,
122
+ message: @error.message,
123
+ backtrace: @error.backtrace,
124
+ }
125
+ end
126
+
127
+ def status
128
+ 1
129
+ end
130
+ alias http_status status
131
+
132
+ def results
133
+ [summary, "Class: #{@error.class.name}", @error.backtrace.join("\n")]
134
+ end
135
+
136
+ def results?
137
+ true
138
+ end
139
+
140
+ def summary
141
+ @error.message
142
+ end
143
+
144
+ def summary?
145
+ true
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -2,7 +2,8 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'securerandom'
5
- require_relative 'action_result'
5
+ require_relative 'actions'
6
+ require_relative 'bolt'
6
7
  require_relative 'goss'
7
8
  require_relative 'logging'
8
9
  require_relative 'platform'
@@ -11,6 +12,7 @@ require_relative 'test_data'
11
12
  require_relative 'utils'
12
13
  require_relative 'version'
13
14
  require_relative 'test_runner/log_formatter'
15
+ require_relative 'test_runner/test_results'
14
16
 
15
17
  module CemAcpt
16
18
  # Namespace for all Runner-related classes and modules
@@ -19,6 +21,8 @@ module CemAcpt
19
21
  class Runner
20
22
  include CemAcpt::Logging
21
23
 
24
+ SUCCESS_STATUS = [200, 0].freeze
25
+
22
26
  attr_reader :duration, :exit_code
23
27
  attr_accessor :run_data # This is opened up mainly for windows use.
24
28
 
@@ -27,8 +31,9 @@ module CemAcpt
27
31
  @run_data = {}
28
32
  @duration = 0
29
33
  @exit_code = 0
30
- @results = []
31
- @http_statuses = []
34
+ @bolt_test_runner = nil
35
+ @results = CemAcpt::TestRunner::TestResults.new
36
+ @statuses = []
32
37
  @provisioned = false
33
38
  @destroyed = false
34
39
  end
@@ -42,23 +47,14 @@ module CemAcpt
42
47
  end
43
48
 
44
49
  def run
45
- @run_data = {}
46
50
  @start_time = Time.now
47
51
  module_dir = config.get('module_dir')
48
52
  @old_dir = Dir.pwd
49
53
  Dir.chdir(module_dir)
54
+ configure_actions
50
55
  logger.start_ci_group("CemAcpt v#{CemAcpt::VERSION} run started at #{@start_time}")
51
56
  logger.info('CemAcpt::TestRunner') { "Using module directory: #{module_dir}..." }
52
- @run_data[:private_key], @run_data[:public_key], @run_data[:known_hosts] = new_ephemeral_ssh_keys
53
- logger.info('CemAcpt::TestRunner') { 'Created ephemeral SSH key pair...' }
54
- @run_data[:module_package_path] = build_module_package
55
- logger.info('CemAcpt::TestRunner') { "Created module package: #{@run_data[:module_package_path]}..." }
56
- @run_data[:test_data] = new_test_data
57
- logger.info('CemAcpt::TestRunner') { 'Created test data...' }
58
- logger.verbose('CemAcpt::TestRunner') { "Test data: #{@run_data[:test_data]}" }
59
- @run_data[:nodes] = new_node_data
60
- logger.info('CemAcpt::TestRunner') { 'Created node data...' }
61
- logger.verbose('CemAcpt::TestRunner') { "Node data: #{@run_data[:nodes]}" }
57
+ pre_provision_test_nodes
62
58
  provision_test_nodes
63
59
  @instance_names_ips = provisioner_output
64
60
  logger.info('CemAcpt::TestRunner') { "Instance names and IPs class: #{@instance_names_ips.class}" }
@@ -79,18 +75,17 @@ module CemAcpt
79
75
  win_node.run
80
76
  end
81
77
  end
82
- @results = run_tests(@instance_names_ips.map { |_, v| v['ip'] },
83
- config.get('actions.only'),
84
- config.get('actions.except'))
78
+ @hosts = @instance_names_ips.map { |_, v| v['ip'] }
79
+ run_tests
85
80
  rescue StandardError => e
86
81
  logger.error('CemAcpt::TestRunner') { 'Run failed due to error...' }
87
- @results << ActionResult.new(e)
82
+ @results << e
88
83
  ensure
89
84
  logger.end_ci_group
90
85
  clean_up
91
86
  process_test_results
92
87
  Dir.chdir(@old_dir) if @old_dir
93
- @results
88
+ @results.to_a
94
89
  end
95
90
 
96
91
  def clean_up(_trap_context = false)
@@ -117,13 +112,36 @@ module CemAcpt
117
112
 
118
113
  attr_reader :config
119
114
 
115
+ # Configures the actions to run based on the config
116
+ def configure_actions
117
+ logger.info('CemAcpt::TestRunner') { 'Configuring and registering actions...' }
118
+ goss_actions = CemAcpt::Goss::Api::ACTIONS.keys
119
+ CemAcpt::Actions.configure(config) do |c|
120
+ c.register_group(:goss, order: 0).register_action(goss_actions.first) do |context|
121
+ run_goss_tests(context)
122
+ end
123
+ goss_actions[1..-1].each { |a| c[:goss].register_action(a) }
124
+ c.register_group(:bolt, order: 1).register_action(:bolt) do |context|
125
+ run_bolt_tests(context)
126
+ end
127
+ end
128
+ logger.debug('CemAcpt::TestRunner') { "All actions #{CemAcpt::Actions.config.action_names}" }
129
+ logger.debug('CemAcpt::TestRunner') { "Only actions: #{CemAcpt::Actions.config.only}" }
130
+ logger.debug('CemAcpt::TestRunner') { "Except actions: #{CemAcpt::Actions.config.except}" }
131
+ logger.info('CemAcpt::TestRunner') do
132
+ "Configured and registered actions, will run actions: #{CemAcpt::Actions.config.action_names.join(', ')}"
133
+ end
134
+ end
135
+
120
136
  # @return [String] The path to the module package
121
137
  def build_module_package
122
- if config.get('tests').first.include? 'windows'
123
- CemAcpt::Utils.package_win_module(config.get('module_dir'))
124
- else
125
- CemAcpt::Utils::Puppet.build_module_package(config.get('module_dir'))
126
- end
138
+ pkg_path = if config.get('tests').first.include? 'windows'
139
+ CemAcpt::Utils.package_win_module(config.get('module_dir'))
140
+ else
141
+ CemAcpt::Utils::Puppet.build_module_package(config.get('module_dir'))
142
+ end
143
+ logger.info('CemAcpt::TestRunner') { "Created module package: #{pkg_path}..." }
144
+ pkg_path
127
145
  end
128
146
 
129
147
  # @return [Array<String>] The paths to the ssh private key, public key, and known hosts file
@@ -131,7 +149,9 @@ module CemAcpt
131
149
  return [nil, nil, nil] if config.get('no_ephemeral_ssh_key')
132
150
 
133
151
  logger.info('CemAcpt::TestRunner') { 'Creating ephemeral SSH keys...' }
134
- CemAcpt::Utils::SSH::Ephemeral.create
152
+ pri, pub, kh = CemAcpt::Utils::SSH::Ephemeral.create
153
+ logger.info('CemAcpt::TestRunner') { 'Created ephemeral SSH key pair...' }
154
+ [pri, pub, kh]
135
155
  end
136
156
 
137
157
  def clean_ephemeral_ssh_keys
@@ -143,12 +163,45 @@ module CemAcpt
143
163
 
144
164
  def new_test_data
145
165
  logger.debug('CemAcpt::TestRunner') { 'Creating new test data...' }
146
- CemAcpt::TestData.acceptance_test_data(config)
166
+ tdata = CemAcpt::TestData.acceptance_test_data(config)
167
+ logger.info('CemAcpt::TestRunner') { 'Created test data...' }
168
+ logger.verbose('CemAcpt::TestRunner') { "Test data:\n#{tdata}" }
169
+ tdata
147
170
  end
148
171
 
149
172
  def new_node_data
150
173
  logger.debug('CemAcpt::TestRunner') { 'Creating new node data...' }
151
- CemAcpt::Platform.use(config.get('platform.name'), config, @run_data)
174
+ ndata = CemAcpt::Platform.use(config.get('platform.name'), config, @run_data)
175
+ logger.info('CemAcpt::TestRunner') { 'Created node data...' }
176
+ logger.verbose('CemAcpt::TestRunner') { "Node data:\n#{ndata}" }
177
+ ndata
178
+ end
179
+
180
+ # Runs all methods that are needed to prep data and environment for the provision_test_nodes method
181
+ def pre_provision_test_nodes
182
+ logger.info('CemAcpt::TestRunner') { 'Pre-provisioning test nodes...' }
183
+ logger.info('CemAcpt::TestRunner') { 'Creating initial run data...' }
184
+ @run_data = {}
185
+ @run_data[:private_key], @run_data[:public_key], @run_data[:known_hosts] = new_ephemeral_ssh_keys
186
+ @run_data[:module_package_path] = build_module_package
187
+ @run_data[:test_data] = new_test_data
188
+ @run_data[:nodes] = new_node_data
189
+ logger.verbose('CemAcpt::TestRunner') { "Initial run data:\n#{@run_data}" }
190
+ logger.info('CemAcpt::TestRunner') { 'Created initial run data...' }
191
+ setup_bolt
192
+ end
193
+
194
+ def setup_bolt
195
+ logger.info('CemAcpt::TestRunner') { 'Setting up Bolt...' }
196
+ @bolt_test_runner = CemAcpt::Bolt::TestRunner.new(config, run_data: @run_data)
197
+ @bolt_test_runner.setup!
198
+ return unless @bolt_test_runner.tests.to_a.empty?
199
+
200
+ if !only_actions.empty? && only_actions.include?('bolt')
201
+ raise 'No Bolt tests to run and only bolt action was specified'
202
+ end
203
+
204
+ logger.warn('CemAcpt::TestRunner') { 'No Bolt tests to run' }
152
205
  end
153
206
 
154
207
  def provision_test_nodes
@@ -194,20 +247,60 @@ module CemAcpt
194
247
  logger.info('CemAcpt') { "Test SSH Keys:\n Private Key: #{@run_data[:private_key]}\n Public Key:#{@run_data[:public_key]}" }
195
248
  end
196
249
 
197
- def run_tests(hosts, only_actions, except_actions)
198
- logger.info('CemAcpt::TestRunner') { 'Running tests...' }
199
- logger.verbose('CemAcpt::TestRunner') { "Hosts: #{hosts}" }
200
- logger.verbose('CemAcpt::TestRunner') { "Only actions: #{only_actions}" }
201
- logger.verbose('CemAcpt::TestRunner') { "Except actions: #{except_actions}" }
202
- api_results = CemAcpt::Goss::Api.run_actions_async(hosts,
203
- only: only_actions || [],
204
- except: except_actions || [])
205
- res = []
206
- api_results.close unless api_results.closed?
207
- while (r = api_results.pop)
208
- res << ActionResult.new(r)
250
+ def run_tests
251
+ logger.info('CemAcpt::TestRunner') { 'Preparing to run tests...' }
252
+ logger.verbose('CemAcpt::TestRunner') { "Hosts: #{@hosts}" }
253
+ logger.verbose('CemAcpt::TestRunner') { "Only actions: #{CemAcpt::Actions.only}" }
254
+ logger.verbose('CemAcpt::TestRunner') { "Except actions: #{CemAcpt::Actions.except}" }
255
+ @results = CemAcpt::TestRunner::TestResults.new(config, @instance_names_ips)
256
+ CemAcpt::Actions.execute
257
+ end
258
+
259
+ def run_goss_tests(context = {})
260
+ logger.info('CemAcpt::TestRunner') { 'Running goss tests...' }
261
+ context[:hosts] = @hosts
262
+ context[:results] = @results
263
+ CemAcpt::Goss::Api.run_actions_async(context)
264
+ end
265
+
266
+ def run_bolt_tests(_context = {})
267
+ logger.info('CemAcpt::TestRunner') { 'Running Bolt tests...' }
268
+ # If the Bolt config has tests:only or tests:ignore lists, we need to filter the hosts
269
+ # based on their associated tests.
270
+ @bolt_test_runner.hosts = filtered_bolt_hosts
271
+ @bolt_test_runner.run
272
+ @results << @bolt_test_runner.results
273
+ end
274
+
275
+ def filtered_bolt_hosts
276
+ tests_only = config.get('bolt.tests.only')
277
+ tests_only_unset = tests_only.nil? || tests_only.empty?
278
+ logger.debug('CemAcpt::TestRunner') { "Bolt tests only: #{tests_only}" } unless tests_only_unset
279
+ tests_ignore = config.get('bolt.tests.ignore')
280
+ tests_ignore_unset = tests_ignore.nil? || tests_ignore.empty?
281
+ logger.debug('CemAcpt::TestRunner') { "Bolt tests ignore: #{tests_ignore}" } unless tests_ignore_unset
282
+ return @instance_names_ips.map { |_, v| v['ip'] } if tests_only_unset && tests_ignore_unset
283
+
284
+ logger.debug('CemAcpt::TestRunner') { 'Filtering Bolt hosts...' }
285
+ filtered_hosts = []
286
+ @instance_names_ips.each do |_, v|
287
+ host = v['ip']
288
+ test_name = v['test_name']
289
+ in_only = !tests_only_unset && tests_only.include?(test_name)
290
+ in_ignore = !tests_ignore_unset && tests_ignore.include?(test_name)
291
+ if in_only || !in_ignore
292
+ filtered_hosts << host
293
+ logger.debug('CemAcpt::TestRunner') { "Added host #{host} to filtered hosts" }
294
+ else
295
+ logger.debug('CemAcpt::TestRunner') do
296
+ "Not adding host #{host} to filtered hosts. In only? #{in_only}; In ignore? #{in_ignore}"
297
+ end
298
+ end
209
299
  end
210
- res
300
+ filtered_hosts.compact!
301
+ filtered_hosts.uniq!
302
+ logger.debug('CemAcpt::TestRunner') { "Filtered hosts: #{filtered_hosts}" }
303
+ filtered_hosts
211
304
  end
212
305
 
213
306
  def process_test_results
@@ -218,14 +311,14 @@ module CemAcpt
218
311
  logger.info('CemAcpt::TestRunner') { "Processing #{@results.size} test result(s)..." }
219
312
  until @results.empty?
220
313
  result = @results.pop
221
- @http_statuses << result.http_status
314
+ @statuses << result.status
222
315
  log_test_result(result)
223
316
  end
224
- if @http_statuses.empty?
317
+ if @statuses.empty?
225
318
  logger.error('CemAcpt::TestRunner') { 'No test results to process' }
226
319
  @exit_code = 1
227
320
  else
228
- @exit_code = (@http_statuses.any? { |s| s.to_i != 200 }) ? 1 : 0
321
+ @exit_code = (@statuses.any? { |s| SUCCESS_STATUS.include?(s.to_i) }) ? 1 : 0
229
322
  end
230
323
  end
231
324
  @duration = Time.now - @start_time
@@ -233,13 +326,22 @@ module CemAcpt
233
326
  end
234
327
 
235
328
  def log_test_result(result)
236
- result_log_formatter = LogFormatter.new_formatter(result, config, @instance_names_ips)
237
- logger.start_ci_group("Test results for #{result_log_formatter.test_name(result)}")
238
- return log_error_test_result(result_log_formatter, result) if result.error?
329
+ logger.start_ci_group("Test results for #{result.log_formatter.test_name}")
330
+ case result
331
+ when CemAcpt::TestRunner::TestResults::TestErrorActionResult
332
+ log_error_test_result(result)
333
+ when CemAcpt::TestRunner::TestResults::TestActionResult
334
+ log_action_test_result(result)
335
+ else
336
+ raise ArgumentError, "result must be a CemAcpt::TestRunner::TestResults::TestActionResult or CemAcpt::TestRunner::TestResults::TestErrorActionResult, got #{result.class}"
337
+ end
338
+ ensure
339
+ logger.end_ci_group
340
+ end
239
341
 
240
- logger.info(result_log_formatter.summary(result))
241
- formatted_results = result_log_formatter.results(result)
242
- formatted_results.each do |r|
342
+ def log_action_test_result(result)
343
+ logger.info { result.log_formatter.summary }
344
+ result.log_formatter.results.each do |r|
243
345
  if r.start_with?('Passed:')
244
346
  logger.verbose { r }
245
347
  elsif r.start_with?('Skipped:')
@@ -248,12 +350,10 @@ module CemAcpt
248
350
  logger.error { r }
249
351
  end
250
352
  end
251
- ensure
252
- logger.end_ci_group
253
353
  end
254
354
 
255
- def log_error_test_result(formatter, result)
256
- logger.fatal { formatter.results(result).join("\n") }
355
+ def log_error_test_result(result)
356
+ logger.fatal { result.log_formatter.results.join("\n") }
257
357
  end
258
358
 
259
359
  # Upload the cem_windows module to the bucket if we're testing the cem_windows module