cem_acpt 0.3.4-universal-java-17 → 0.3.5-universal-java-17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c289fcb52a1115630ffece04c465e5a8d945bdefdcc99fbf73a800398d2f2bc6
4
- data.tar.gz: aca0f41efe831bf5bb8dc4399cd1a2d771f7bb72fb1ee13eeccb79d59bd45183
3
+ metadata.gz: b62e59f800597758c9a69bc1ede3d3f97a9a68c6c38f0d4705201ac2613feab9
4
+ data.tar.gz: 4d4a0ad559702df7cff661726a962b0bbc278d2cb0ecba48241a67a55345dac6
5
5
  SHA512:
6
- metadata.gz: 65dd7b8c5023304f0c5f9fd371a64cfb157567004d6f93ebdadc76bbf99f50f7483fab575f73fb9c07256cbb0db688ad4d8c10a6b644a8f7670a3441a54e866e
7
- data.tar.gz: 2504bc3dc1ef1ac1a09c16d00c3cd99b08127ccd31f2b9da134f31ffb2dc19730eda580ec893def0a9b183bd4198c5aa8263ea735f50c0b2c21156a5f8f7124d
6
+ metadata.gz: ee72270cae3121c03597e12f91c3fd6134da4ab40ef342cc3f694ea0a5ee2dcaf37363e9430b2610539120e0cf5ea733caf191d916a926e2d29dc17ac8bc7cfb
7
+ data.tar.gz: 79a40b4e74935a7842bffd7b9252aa63d277cc31e49c0a3a10200f647117a1c3e51d4183a3e2e16aa9cc0e1fd185d0ee375177fdc876ca4097e8828884b55f36
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.3.4-universal-java-17)
4
+ cem_acpt (0.3.5-universal-java-17)
5
5
  concurrent-ruby (>= 1.1, < 2.0)
6
6
  deep_merge (>= 1.2, < 2.0)
7
7
  ed25519 (>= 1.2, < 2.0)
@@ -113,6 +113,9 @@ module CemAcpt::Platform::Gcp
113
113
 
114
114
  # Deletes a GCP VM instance.
115
115
  def delete_instance(instance_name)
116
+ ssh_all_known_hosts.each do |kh_file|
117
+ CemAcpt::Platform::Utils::Linux::SSHelper.remove_known_host(vm_alias(instance_name), kh_file)
118
+ end
116
119
  local_exec("compute instances delete #{instance_name} --quiet")
117
120
  rescue StandardError
118
121
  # Ignore errors when deleting instances.
@@ -318,6 +321,14 @@ module CemAcpt::Platform::Gcp
318
321
  "compute.#{vm_describe(vm)['id']}"
319
322
  end
320
323
 
324
+ def ssh_all_known_hosts
325
+ [
326
+ File.join(ENV['HOME'], '.ssh', 'acpt_test_known_hosts'),
327
+ File.join(ENV['HOME'], '.ssh', 'known_hosts'),
328
+ File.join(ENV['HOME'], '.ssh', 'google_compute_known_hosts'),
329
+ ]
330
+ end
331
+
321
332
  # Default options for Net::SSH
322
333
  def default_ssh_opts
323
334
  {
@@ -4,6 +4,43 @@ module CemAcpt
4
4
  module Platform
5
5
  module Utils
6
6
  module Linux
7
+ # Module provides SSH helper methods for Linux platforms
8
+ class SSHelper
9
+ def self.ssh_keygen?
10
+ system('command -v ssh-keygen 2>&1 > /dev/null')
11
+ end
12
+
13
+ def self.remove_known_host(host, file = File.join([ENV['HOME'], '.ssh', 'known_hosts']))
14
+ if File.exist?(file)
15
+ if ssh_keygen?
16
+ system("ssh-keygen -R #{host} -f #{file} 2>&1 > /dev/null")
17
+ else
18
+ remove_known_host_no_keygen(host, file)
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.remove_known_host_no_keygen(host, file = File.join([ENV['HOME'], '.ssh', 'known_hosts']))
24
+ require 'fileutils'
25
+ found = false
26
+ File.open("#{file}.cem_acpt_new", 'w') do |f|
27
+ File.readlines(file).each do |line|
28
+ if line.include?(host)
29
+ found = true
30
+ else
31
+ f.puts(line)
32
+ end
33
+ end
34
+ end
35
+ if found
36
+ FileUtils.mv("#{file}.cem_acpt_new", file)
37
+ else
38
+ FileUtils.rm("#{file}.cem_acpt_new")
39
+ end
40
+ end
41
+ end
42
+
43
+ # Class to parse the /etc/os-release file
7
44
  class OSRelease
8
45
  attr_reader :properties
9
46
 
@@ -21,7 +58,7 @@ module CemAcpt
21
58
 
22
59
  def parse_string(os_release)
23
60
  os_release = os_release.split("\n")
24
- os_release = os_release.map { |line| line.split('=', 2) }.reject { |l| l.length != 2 }
61
+ os_release = os_release.map { |line| line.split('=', 2) }.select { |l| l.length == 2 }
25
62
  os_release.map! { |k, v| [k.downcase, v.delete_prefix('"').delete_suffix('"')] }
26
63
  os_release.to_h
27
64
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../logging'
4
+
5
+ module CemAcpt
6
+ module TestRunner
7
+ # Namespace for TestRunner logging wrapper
8
+ module Logging
9
+ def use_logger(logger, **prefix_parts)
10
+ if logger.nil? || !logger.is_a?(CemAcpt::TestRunner::Logging::Logger)
11
+ CemAcpt::TestRunner::Logging::Logger.new(**prefix_parts)
12
+ else
13
+ this_prefix_parts = logger.prefix_parts.dup.merge(prefix_parts)
14
+ CemAcpt::TestRunner::Logging::Logger.new(**this_prefix_parts)
15
+ end
16
+ end
17
+
18
+ # Class to handle logging for Runner objects
19
+ class Logger
20
+ include CemAcpt::Logging
21
+
22
+ attr_reader :prefix_parts
23
+
24
+ def initialize(**prefix_parts)
25
+ @prefix_parts = prefix_parts
26
+ end
27
+
28
+ def log_prefix
29
+ parts = []
30
+ parts << @prefix_parts[:test] if @prefix_parts.key?(:test)
31
+ parts << @prefix_parts[:node] if @prefix_parts.key?(:node)
32
+ parts << @prefix_parts[:stage] if @prefix_parts.key?(:stage)
33
+ parts << @prefix_parts[:step] if @prefix_parts.key?(:step)
34
+ parts.join(': ')
35
+ end
36
+
37
+ def add_prefix_parts(**parts)
38
+ @prefix_parts.merge!(parts)
39
+ end
40
+
41
+ def debug(msg, no_prefix: false)
42
+ logger.debug(format_msg(msg, no_prefix))
43
+ end
44
+
45
+ def info(msg, no_prefix: false)
46
+ logger.info(format_msg(msg, no_prefix))
47
+ end
48
+
49
+ def warn(msg, no_prefix: false)
50
+ logger.warn(format_msg(msg, no_prefix))
51
+ end
52
+
53
+ def error(msg, no_prefix: false)
54
+ logger.error(format_msg(msg, no_prefix))
55
+ end
56
+
57
+ def fatal(msg, no_prefix: false)
58
+ logger.fatal(format_msg(msg, no_prefix))
59
+ end
60
+
61
+ def <<(msg)
62
+ logger << msg
63
+ end
64
+
65
+ private
66
+
67
+ def format_msg(msg, no_prefix)
68
+ if no_prefix
69
+ msg
70
+ else
71
+ "#{log_prefix}: #{msg}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -3,8 +3,8 @@
3
3
  require 'concurrent-ruby'
4
4
  require 'open3'
5
5
  require_relative '../context'
6
- require_relative '../logging'
7
6
  require_relative '../puppet_helpers'
7
+ require_relative 'logging'
8
8
  require_relative 'runner'
9
9
 
10
10
  module CemAcpt
@@ -19,7 +19,7 @@ module CemAcpt
19
19
  # creating Runner objects, handling input and output, and exception
20
20
  # handling.
21
21
  class RunHandler
22
- include CemAcpt::Logging
22
+ include CemAcpt::TestRunner::Logging
23
23
 
24
24
  attr_accessor :run_context
25
25
 
@@ -29,6 +29,7 @@ module CemAcpt
29
29
  @module_pkg_path = Concurrent::IVar.new
30
30
  @runners = Concurrent::Array.new
31
31
  @thread_pool = Concurrent::SimpleExecutorService.new
32
+ @logger = use_logger(nil, stage: 'RunHandler')
32
33
  end
33
34
 
34
35
  # Gets the overall exit code for all runners
@@ -38,14 +39,14 @@ module CemAcpt
38
39
 
39
40
  # Runs the acceptance test suites.
40
41
  def run
41
- logger.info('RUN HANDLER: Creating and starting test runners...')
42
+ @logger.info('creating and starting test runners...')
42
43
  create_runners
43
- logger.info("RUN HANDLER: Created #{@runners.length} runners...")
44
+ @logger.info("created #{@runners.length} runners...")
44
45
  @runners.map { |r| @thread_pool.post { r.start } }
45
46
  @thread_pool.shutdown
46
47
  @thread_pool.wait_for_termination
47
48
  @thread_pool = Concurrent::SimpleExecutorService.new
48
- logger.info('Test runners have all exited...')
49
+ @logger.info('test runners have all exited...')
49
50
  rescue StandardError => e
50
51
  handle_fatal_error(e)
51
52
  ensure
@@ -70,17 +71,17 @@ module CemAcpt
70
71
  end
71
72
 
72
73
  def create_runner(node, platform)
73
- logger.info("RUN HANDLER: Creating runner for #{node.test_data[:test_name]} on node #{node.node_name}...")
74
+ @logger.info("creating runner for #{node.test_data[:test_name]} on node #{node.node_name}...")
74
75
  runner = CemAcpt::TestRunner::Runner.new(node, @run_context, platform)
75
76
  runner || runner_creation_error(node)
76
77
  end
77
78
 
78
79
  def runner_creation_error(node)
79
80
  msg = [
80
- "Failed to create runner object for node #{node.node_name}.",
81
+ "failed to create runner object for node #{node.node_name}!",
81
82
  "Cannot run test #{node.test_data[:test_name]}",
82
83
  ].join(' ')
83
- logger.error(msg)
84
+ @logger.error(msg)
84
85
  nil
85
86
  end
86
87
 
@@ -88,22 +89,22 @@ module CemAcpt
88
89
  def handle_test_results
89
90
  @runners.each do |runner|
90
91
  result = runner.run_result.to_h
91
- logger << "::group::{Results for #{runner.node.test_data[:test_name]}}\n"
92
+ @logger << "::group::{Results for #{runner.node.test_data[:test_name]}}\n"
92
93
  if result.key?('summary_line')
93
- logger.info("SUMMARY: #{result['summary_line']} for test #{runner.node.test_data[:test_name]}")
94
+ @logger.info("SUMMARY: #{result['summary_line']} for test #{runner.node.test_data[:test_name]}", no_prefix: true)
94
95
  else
95
96
  handle_runner_error_results(runner)
96
- logger << "::endgroup::\n"
97
+ @logger << "::endgroup::\n"
97
98
  next
98
99
  end
99
100
  unless runner.test_failures?
100
- logger << "::endgroup::\n"
101
+ @logger << "::endgroup::\n"
101
102
  next
102
103
  end
103
104
 
104
105
  if result.key?('examples') # Log errors outside of examples
105
106
  if result['examples'].empty? && !result['messages'].empty?
106
- logger.error(result['messages'].join("\n"))
107
+ @logger.error(result['messages'].join("\n"), no_prefix: true)
107
108
  else
108
109
  handle_example_error_pending_skipped(runner.node.node_name, result['examples'])
109
110
  end
@@ -111,7 +112,7 @@ module CemAcpt
111
112
  handle_runner_error_results(runner)
112
113
  end
113
114
  #debug_test_results(runner) if logger.debug?
114
- logger << "::endgroup::\n"
115
+ @logger << "::endgroup::\n"
115
116
  end
116
117
  end
117
118
 
@@ -121,18 +122,18 @@ module CemAcpt
121
122
  next if e['status'] == 'passed'
122
123
 
123
124
  if e['status'] == 'pending'
124
- logger.info(test_pending_msg(node_name, e))
125
+ @logger.info(test_pending_msg(node_name, e), no_prefix: true)
125
126
  else
126
- logger.error(test_error_msg(node_name, e))
127
+ @logger.error(test_error_msg(node_name, e), no_prefix: true)
127
128
  end
128
129
  end
129
130
  end
130
131
 
131
132
  # Handles logging the results of the runners that errored.
132
133
  def handle_runner_error_results(runner)
133
- logger.error("SUMMARY: Encountered an error with test #{runner.node.test_data[:test_name]} on node #{runner.node.node_name}")
134
+ @logger.error("SUMMARY: Encountered an error with test #{runner.node.test_data[:test_name]} on node #{runner.node.node_name}", no_prefix: true)
134
135
  runner.run_result.to_h.each do |k, v|
135
- logger.error("#{k.upcase}: #{v}")
136
+ @logger.error("#{k.upcase}: #{v}", no_prefix: true)
136
137
  end
137
138
  end
138
139
 
@@ -202,8 +203,8 @@ module CemAcpt
202
203
  # Gracefully handles a fatal error and exits the program.
203
204
  # @param err [StandardError, Exception] the error that caused the fatal error
204
205
  def handle_fatal_error(err)
205
- logger.fatal("RUN HANDLER: Fatal error: #{err.message}")
206
- logger.debug(err.backtrace.join("\n"))
206
+ @logger.fatal("fatal error: #{err.message}")
207
+ @logger.debug(err.backtrace.join("\n"), no_prefix: true)
207
208
  end
208
209
  end
209
210
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'concurrent-ruby'
4
4
  require 'English'
5
- require_relative '../logging'
6
5
  require_relative '../rspec_utils'
6
+ require_relative 'logging'
7
7
  require_relative 'runner_result'
8
8
  require_relative 'runner_workflow_builder'
9
9
  #require_relative 'workflow'
@@ -25,19 +25,15 @@ module CemAcpt
25
25
 
26
26
  class RunnerProvisionError < RunnerStepError; end
27
27
 
28
-
29
-
30
28
  # Runner is a class that runs a single acceptance test suite on a single node.
31
29
  # It is responsible for managing the lifecycle of the test suite and
32
30
  # reporting the results back to the main thread. Runner objects are created
33
31
  # by the RunHandler and then, when started, execute their logic in a thread.
34
32
  class Runner
35
- include CemAcpt::LoggingAsync
33
+ include CemAcpt::TestRunner::Logging
36
34
 
37
35
  attr_reader :node, :node_exists, :run_result
38
36
 
39
- MAX_PROVISION_ATTEMPTS = 3
40
-
41
37
  # @param node [String] the name of the node to run the acceptance test suite on
42
38
  # @param ctx [CemAcpt::RunnerCtx] a cem_acpt Ctx (context) object
43
39
  # @param module_pkg_path [Concurrent::IVar] the path to the module package
@@ -52,18 +48,19 @@ module CemAcpt
52
48
  @provision_start_time = nil
53
49
  @node_exists = false
54
50
  @run_result = CemAcpt::TestRunner::RunnerResult.new(@node, debug: @debug_mode)
51
+ @logger = use_logger(nil, stage: 'Runner', node: @node.node_name, test: @node.test_data[:test_name])
55
52
  validate!
56
53
  end
57
54
 
58
55
  # Executes test suite steps
59
56
  def start
60
- async_info("Starting test suite for #{@node.node_name}", log_prefix('RUNNER'))
57
+ @logger.info('Starting test suite workflow...')
61
58
  @workflow = new_workflow
62
59
  @workflow.run
63
60
  if @workflow.success?
64
61
  @run_result = @workflow.last_result
65
62
  @workflow.completed_steps.each do |s|
66
- async_info("Step '#{s.name}' completed successfully", log_prefix('RUNNER'))
63
+ @logger.info("Step '#{s.name}' completed successfully")
67
64
  end
68
65
  true
69
66
  else
@@ -72,7 +69,7 @@ module CemAcpt
72
69
  false
73
70
  end
74
71
  rescue StandardError => e
75
- step_error_logging(e)
72
+ step_error_logging(e, :fatal)
76
73
  @run_result = CemAcpt::TestRunner::RunnerResult.new(@node, debug: @debug_mode)
77
74
  @run_result.from_error(e)
78
75
  end
@@ -89,7 +86,7 @@ module CemAcpt
89
86
  # Builds a new workflow for the runner
90
87
  # @return [CemAcpt::TestRunner::Workflow::Manager] the new workflow
91
88
  def new_workflow
92
- builder = RunnerWorkflowBuilder.new(@node, config: @context.config)
89
+ builder = RunnerWorkflowBuilder.new(@node, @context.config, @logger)
93
90
  builder.add_provision
94
91
  builder.add_sleep(time: 30)
95
92
  builder.add_wait_for_node_ssh
@@ -104,13 +101,15 @@ module CemAcpt
104
101
  builder.workflow
105
102
  end
106
103
 
107
- def step_error_logging(err)
108
- prefix = err.respond_to?(:step) ? log_prefix(err.step.capitalize) : log_prefix('RUNNER')
109
- fatal_msg = ["runner failed: #{err.message}"]
110
- async_fatal(fatal_msg, prefix)
111
- async_debug("Completed steps: #{@completed_steps}", prefix)
112
- async_debug("Failed runner backtrace:\n#{err.backtrace.join("\n")}", prefix)
113
- async_debug("Failed runner test data: #{@node.test_data}", prefix)
104
+ def step_error_logging(err, kind = :error)
105
+ msg = if err.respond_to?(:step)
106
+ "runner failed on step '#{err.step}': #{err.message}"
107
+ else
108
+ "runner failed: #{err.message}"
109
+ end
110
+ @logger.send(kind, msg)
111
+ @logger.debug("failed runner backtrace:\n#{err.backtrace.join("\n")}")
112
+ @logger.debug("failed runner test data: #{@node.test_data}")
114
113
  end
115
114
 
116
115
  def log_prefix(prefix)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../logging'
3
+ require_relative 'logging'
4
4
  require_relative 'workflow'
5
5
 
6
6
  module CemAcpt
@@ -9,15 +9,17 @@ module CemAcpt
9
9
  # @!attribute [r] workflow
10
10
  # @return [CemAcpt::TestRunner::Workflow::Manager] Workflow object
11
11
  class RunnerWorkflowBuilder
12
- include CemAcpt::LoggingAsync
12
+ include CemAcpt::TestRunner::Logging
13
13
 
14
14
  attr_reader :workflow
15
15
 
16
16
  # @param node [CemAcpt::Platform::Base] Initialized node object
17
17
  # @param config [Hash] Context config hash
18
- def initialize(node, config)
18
+ # @param logger [CemAcpt::TestRunner::Logging::Logger] Logger object
19
+ def initialize(node, config, logger = nil)
19
20
  @node = node
20
- @workflow = CemAcpt::TestRunner::Workflow::Manager.new(workflow_manager_opts(config))
21
+ @logger = use_logger(logger, stage: 'Workflow')
22
+ @workflow = CemAcpt::TestRunner::Workflow::Manager.new(workflow_manager_opts(config, logger))
21
23
  @config = config
22
24
  end
23
25
 
@@ -28,7 +30,7 @@ module CemAcpt
28
30
  retryable: false,
29
31
  }
30
32
  @workflow.add_step(:sleep, **opts) do |s|
31
- log_info("sleeping for #{s.opts[:time]} seconds", s)
33
+ s.logger.info("sleeping for #{s.opts[:time]} seconds")
32
34
  sleep(s.opts[:time])
33
35
  end
34
36
  end
@@ -104,7 +106,7 @@ module CemAcpt
104
106
  }.merge(s.opts[:node].node)
105
107
  s.opts[:node_inventory].add(s.opts[:node].node_name, node_desc)
106
108
  s.opts[:node_inventory].save
107
- log_info("node #{s.opts[:node_name]} saved to inventory", s)
109
+ s.logger.info("node #{s.opts[:node_name]} saved to inventory")
108
110
  s.opts[:node_inventory]
109
111
  end
110
112
  end
@@ -169,11 +171,11 @@ module CemAcpt
169
171
  rspec_cmd.execute(pty: false, log_prefix: "RSPEC: #{@node.test_data[:test_name]}")
170
172
  run_result.from_json_file(cmd_opts.format[:json])
171
173
  rescue Errno::EIO => e
172
- log_error("failed to run rspec: #{@node.test_data[:test_name]}: #{$ERROR_INFO}", s)
174
+ s.logger.error("failed to run rspec: #{@node.test_data[:test_name]}: #{$ERROR_INFO}")
173
175
  run_result.from_error(e)
174
176
  rescue StandardError => e
175
- log_error("failed to run rspec: #{@node.test_data[:test_name]}: #{e.message}", s)
176
- log_debug(e.backtrace.join("\n"), s)
177
+ s.logger.error("failed to run rspec: #{@node.test_data[:test_name]}: #{e.message}")
178
+ s.logger.debug(e.backtrace.join("\n"))
177
179
  run_result.from_error(e)
178
180
  end
179
181
  end
@@ -184,53 +186,30 @@ module CemAcpt
184
186
  def add_clean_up(force: false, **kwargs)
185
187
  opts = {
186
188
  node: @node,
187
- config: @config[:config],
189
+ config: @config,
188
190
  force: force,
189
191
  retryable: kwargs[:retryable] || false,
190
192
  }
191
193
  @workflow.add_step(:clean_up, **opts) do |s|
192
194
  if !force && s.opts[:config].get('no_destroy_nodes')
193
- log_info("not destroying node #{s.opts[:node].node_name} because 'no_destroy_nodes' is set to true", s)
195
+ s.logger.info("not destroying node #{s.opts[:node].node_name} because 'no_destroy_nodes' is set to true")
194
196
  else
195
- log_info("destroying node #{s.opts[:node].node_name}", s)
197
+ s.logger.info("destroying node #{s.opts[:node].node_name}")
196
198
  s.opts[:node].destroy
197
- log_info("node #{s.opts[:node].node_name} destroyed", s)
199
+ s.logger.info("node #{s.opts[:node].node_name} destroyed")
198
200
  end
199
201
  end
200
202
  end
201
203
 
202
204
  private
203
205
 
204
- def log_msg(msg, step)
205
- "Step '#{step.name}' on #{@node.node_name}: #{msg}"
206
- end
207
-
208
- def log_debug(msg, step)
209
- async_debug(log_msg(msg, step))
210
- end
211
-
212
- def log_info(msg, step)
213
- async_info(log_msg(msg, step))
214
- end
215
-
216
- def log_warn(msg, step)
217
- async_warn(log_msg(msg, step))
218
- end
219
-
220
- def log_error(msg, step)
221
- async_error(log_msg(msg, step))
222
- end
223
-
224
- def log_fatal(msg, step)
225
- async_fatal(log_msg(msg, step))
226
- end
227
-
228
- def workflow_manager_opts(config)
206
+ def workflow_manager_opts(config, logger = nil)
229
207
  {
230
- retry_max: config[:workflow_retry_max] || 3,
231
- retry_delay: config[:workflow_retry_delay] || 0,
232
- ignore_failures: config[:workflow_ignore_failures] || false,
233
- raise_on_fail: config[:workflow_raise_on_fail] || true,
208
+ retry_max: config.get('workflow.retry_max') || 3,
209
+ retry_delay: config.get('workflow.retry_delay') || 0,
210
+ ignore_failures: config.get('workflow.ignore_failures') || false,
211
+ raise_on_fail: config.get('workflow.raise_on_fail') || true,
212
+ logger: logger,
234
213
  }
235
214
  end
236
215
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../logging'
3
+ require_relative '../logging'
4
4
  require_relative 'step'
5
5
 
6
6
  module CemAcpt
@@ -20,7 +20,7 @@ module CemAcpt
20
20
  # @!attribute [r] steps
21
21
  # @return [Array<Step>] The steps that are part of this workflow
22
22
  class Manager
23
- include CemAcpt::LoggingAsync
23
+ include CemAcpt::TestRunner::Logging
24
24
 
25
25
  attr_reader :completed_steps, :last_error, :last_result, :retry_max, :retry_delay, :steps
26
26
 
@@ -34,6 +34,7 @@ module CemAcpt
34
34
  @retry_delay = opts[:retry_delay] || 0
35
35
  @ignore_failures = opts[:ignore_failures] || false
36
36
  @raise_on_fail = opts[:raise_on_fail] || true
37
+ @logger = use_logger(opts[:logger], stage: 'Workflow')
37
38
  @steps = []
38
39
  @workflow_runs = 0
39
40
  @last_error = nil
@@ -57,8 +58,8 @@ module CemAcpt
57
58
  else
58
59
  name
59
60
  end
60
- step = Step.new(step_name, **kwargs, &block)
61
- @steps << StepState.new(step, @steps.length, **kwargs)
61
+ step = Step.new(step_name, **kwargs.merge(logger: @logger), &block)
62
+ @steps << StepState.new(step, @steps.length, **kwargs.merge(logger: @logger))
62
63
  end
63
64
 
64
65
  # Run the workflow
@@ -92,6 +93,43 @@ module CemAcpt
92
93
 
93
94
  private
94
95
 
96
+ def new_logger(logger)
97
+ if logger.nil?
98
+ logger
99
+ else
100
+ @logger = logger.dup
101
+ @logger.add_prefix_parts(stage: 'Workflow')
102
+ end
103
+ end
104
+
105
+ def log(level, msg)
106
+ if @logger
107
+ @logger.send(level, msg)
108
+ else
109
+ send("async_#{level}".to_sym, msg)
110
+ end
111
+ end
112
+
113
+ def log_debug(msg)
114
+ log(:debug, msg)
115
+ end
116
+
117
+ def log_info(msg)
118
+ log(:info, msg)
119
+ end
120
+
121
+ def log_warn(msg)
122
+ log(:warn, msg)
123
+ end
124
+
125
+ def log_error(msg)
126
+ log(:error, msg)
127
+ end
128
+
129
+ def log_fatal(msg)
130
+ log(:fatal, msg)
131
+ end
132
+
95
133
  # Handles the result of a step
96
134
  # @param [Step] step The step that was run
97
135
  # @param [Object] result The result of the step
@@ -100,26 +138,26 @@ module CemAcpt
100
138
  @last_result = result unless step.name == :clean_up # Don't overwrite the last result with the clean_up step
101
139
  case result
102
140
  when :retry_workflow
103
- async_warn("Step '#{step.name}' failed and requested a workflow retry")
104
- async_debug("Step '#{step.name}' failed with error: #{step.last_error.message}")
105
- async_debug("Step '#{step.name}' failed with error: #{step.last_error.backtrace.join("\n")}")
141
+ log_warn("step '#{step.name}' failed and requested a workflow retry")
142
+ log_debug("step '#{step.name}' failed with error: #{step.last_error.message}")
143
+ log_debug("step '#{step.name}' failed with error: #{step.last_error.backtrace.join("\n")}")
106
144
  @last_error = step.last_error
107
145
  retry_workflow
108
146
  when :fail
109
- async_warn("Step '#{step.name}' failed")
110
- async_debug(step.last_error.message)
111
- async_debug(step.last_error.backtrace.join("\n"))
147
+ log_warn("step '#{step.name}' failed")
148
+ log_debug(step.last_error.message)
149
+ log_debug(step.last_error.backtrace.join("\n"))
112
150
  @last_error = step.last_error
113
151
  if ignore_failures?
114
- async_warn("Ignoring failure of step '#{step.name}'")
152
+ log_warn("ignoring failure of step '#{step.name}'")
115
153
  @completed_steps << step
116
154
  else
117
- async_error("Workflow failed with error: #{@last_error.message}")
155
+ log_error("failed with error: #{@last_error.message}")
118
156
  raise @last_error
119
157
  end
120
158
  else
121
- async_info("Step '#{step.name}' succeeded")
122
- async_debug("Step '#{step.name}' returned: #{result}")
159
+ log_info("step '#{step.name}' succeeded")
160
+ log_debug("step '#{step.name}' returned: #{result}")
123
161
  @completed_steps << step
124
162
  end
125
163
  end
@@ -128,12 +166,12 @@ module CemAcpt
128
166
  # @raise [StandardError] If the workflow is not retryable or has exceeded the maximum number of retries
129
167
  def retry_workflow
130
168
  if @workflow_runs < @retry_max
131
- async_info("Retrying workflow (attempt #{@workflow_runs + 1} of #{@retry_max})")
169
+ log_info("Retrying workflow (attempt #{@workflow_runs + 1} of #{@retry_max})")
132
170
  sleep @retry_delay if @retry_delay > 0
133
171
  clean_up
134
172
  run
135
173
  else
136
- async_fatal('Workflow is not retryable or has exceeded the maximum number of retries')
174
+ log_fatal('Workflow is not retryable or has exceeded the maximum number of retries')
137
175
  raise @last_error
138
176
  end
139
177
  end
@@ -142,7 +180,7 @@ module CemAcpt
142
180
  # @return [Step] The default clean_up step
143
181
  def default_clean_up
144
182
  add_step(:clean_up) do
145
- async_info('No clean_up step defined, skipping')
183
+ log_info('No clean_up step defined, skipping')
146
184
  true
147
185
  end
148
186
  @steps.last
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../logging'
3
+ require_relative '../logging'
4
4
 
5
5
  module CemAcpt
6
6
  module TestRunner
@@ -28,9 +28,9 @@ module CemAcpt
28
28
  # @!attribute [r] result
29
29
  # @return [Object] The result of the step
30
30
  class Step
31
- include CemAcpt::LoggingAsync
31
+ include CemAcpt::TestRunner::Logging
32
32
 
33
- attr_reader :name, :opts, :result
33
+ attr_reader :logger, :name, :opts, :result
34
34
 
35
35
  # @param name [Symbol] The name of the step
36
36
  # @param opts [Hash] The options passed to the step
@@ -42,7 +42,7 @@ module CemAcpt
42
42
  @block = block
43
43
  @result = :not_run
44
44
  @failed = false
45
- @log_prefix = opts[:log_prefix] || "#{@name.upcase}:"
45
+ @logger = use_logger(opts[:logger], step: name.to_s.capitalize)
46
46
  end
47
47
 
48
48
  # @return [Boolean] True if the step has been run and failed
@@ -51,27 +51,21 @@ module CemAcpt
51
51
  end
52
52
 
53
53
  # Run the step. This calls and executes the block passed to the constructor.
54
- # @param log_prefix [String] The prefix to use when logging the step name
54
+ # @param start_log [String] The message to log when the step starts
55
55
  # @return [Object] The result of the step
56
- def run(_log_prefix = 'Running step')
57
- async_info(log_msg('Starting step'))
56
+ def run(start_log = 'starting step')
57
+ @logger.info(start_log)
58
58
  @result = @block.call(self)
59
- async_debug(log_msg('SUCCESS'))
59
+ @logger.debug('SUCCESS')
60
60
  @result
61
61
  rescue StandardError => e
62
- async_debug(log_msg("FAILED: #{e.message}"))
62
+ @logger.debug("FAILED: #{e.message}")
63
63
  @result = StepError.new(@name, e)
64
64
  @failed = true
65
65
  @result
66
66
  ensure
67
67
  Thread.pass # Be kind to the scheduler
68
68
  end
69
-
70
- private
71
-
72
- def log_msg(msg)
73
- [@log_prefix, msg].join(' ')
74
- end
75
69
  end
76
70
 
77
71
  # StepState is a class that holds the state of a Step.
@@ -144,11 +138,11 @@ module CemAcpt
144
138
  end
145
139
 
146
140
  # Run the step. This wraps the Step#run method and handles updating the state of the step.
147
- # @param log_prefix [String] The prefix to use when logging the step name
141
+ # @param start_log [String] The message to log when the step starts
148
142
  # @return [Object] The result of the step
149
- def run(log_prefix = 'Running step')
143
+ def run(start_log = 'starting step')
150
144
  @run_count += 1
151
- @last_result = @step.run(log_prefix)
145
+ @last_result = @step.run(start_log)
152
146
  @results << @last_result
153
147
  if @last_result.is_a?(StepError)
154
148
  handle_error(@last_result)
@@ -178,8 +172,8 @@ module CemAcpt
178
172
 
179
173
  # Retry running the step
180
174
  def retry_step
181
- sleep @retry_delay if @retry_delay > 0
182
- run("Retrying step (attempt #{@run_count} of #{@retry_max})")
175
+ sleep @retry_delay if @retry_delay.positive?
176
+ run("retrying step (attempt #{@run_count + 1} of #{@retry_max})")
183
177
  end
184
178
  end
185
179
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../logging'
4
3
  require_relative 'workflow/manager'
5
4
  require_relative 'workflow/step'
6
5
 
@@ -10,206 +9,3 @@ module CemAcpt
10
9
  module Workflow; end
11
10
  end
12
11
  end
13
-
14
- # module CemAcpt
15
- # module TestRunner
16
-
17
-
18
- # # Workflow is a class that manages how steps are executed.
19
- # class Workflow
20
- # include CemAcpt::LoggingAsync
21
-
22
- # attr_reader :steps, :groups, :group_retry_max, :completed_steps
23
-
24
- # def initialize(init_steps: [], **opts)
25
- # raise ArgumentError, 'init_steps must be an Array' unless init_steps.is_a?(Array)
26
- # raise ArgumentError, 'init_steps must be an Array of Step objects' unless init_steps.all? { |step| step.is_a?(Step) }
27
-
28
- # @steps = init_steps
29
- # @groups = @steps.map(&:group).compact.uniq
30
- # @group_retry_max = opts[:group_retry_max] || 3
31
- # @group_tries = {}
32
- # @last_error = nil
33
- # @completed_steps = []
34
- # end
35
-
36
- # def add_step(step, order = nil)
37
- # raise ArgumentError, 'step must be a Step object' unless step.is_a?(Step)
38
-
39
- # unless order.nil?
40
- # @steps.insert(order, step)
41
- # else
42
- # @steps << step
43
- # end
44
- # end
45
-
46
- # def add_step_with(name, order = nil, **kwargs, &block)
47
- # raise ArgumentError, 'order must be an Integer' unless order.is_a?(Integer) || order.nil?
48
- # raise ArgumentError, 'name must be a Symbol' unless name.is_a?(Symbol)
49
-
50
- # unless order.nil?
51
- # @steps.insert(order, Step.new(name, **kwargs, &block))
52
- # else
53
- # @steps << Step.new(name, **kwargs, &block)
54
- # end
55
- # end
56
-
57
- # def run
58
- # current_run_groups = []
59
- # @steps.each do |step|
60
- # next if step.name == :clean_up
61
-
62
- # group_run_increment(step, current_run_groups)
63
- # step.run
64
- # @completed_steps << step
65
- # end
66
- # @completed_steps
67
- # rescue StandardError => e
68
- # async_error("Workflow failed with error: #{e}")
69
- # @last_error = e
70
- # raise e
71
- # ensure
72
- # clean_up
73
- # end
74
-
75
- # def success?
76
- # (@completed_steps.length == @steps.length) && @completed_steps.none? { |step| step.result.is_a?(StepError) }
77
- # end
78
-
79
- # private
80
-
81
- # def group_run_increment(step, current_run_groups = [])
82
- # if step.grouped? && !current_run_groups.include?(step.group)
83
- # current_run_groups << step.group
84
- # if @group_tries[step.group].nil? || @group_tries[step.group].zero?
85
- # @group_tries[step.group] = 1
86
- # elsif @group_tries[step.group] >= @group_retry_max
87
- # raise StepError.new(step, @last_error)
88
- # else
89
- # @group_tries[step.group] += 1
90
- # end
91
- # end
92
- # end
93
-
94
- # def run_step(step)
95
- # result = step.run
96
- # #handle_result(step, result)
97
- # @completed_steps << step
98
- # result
99
- # end
100
-
101
- # def handle_result(step, result)
102
- # if result.is_a?(StepError)
103
- # handle_error(step, result)
104
- # else
105
- # async_info("Step '#{step.name}' completed successfully")
106
- # end
107
- # end
108
-
109
- # def handle_error(step, err)
110
- # if step.retryable? && step.runs < @retry_max
111
- # async_info("Retrying step '#{step.name}' (attempt #{step.runs + 1} of #{@retry_max})")
112
- # sleep step.retry_delay if step.retry_delay > 0
113
- # run_step(step)
114
- # else
115
- # async_debug("Step '#{step.name}' is not retryable or has exceeded the maximum number of retries")
116
- # raise err if step.raise_on_fail?
117
- # end
118
- # end
119
-
120
- # def default_clean_up
121
- # Step.new(:clean_up, retryable: false, raise_on_fail: true) do
122
- # async_info('No clean_up step defined, skipping')
123
- # end
124
- # end
125
-
126
- # def clean_up
127
- # cleanup_step = @steps.find { |step| step.name == :clean_up } || default_clean_up
128
- # unless cleanup_step.nil?
129
- # cleanup_step.retryable = false # clean_up steps should not be retried
130
- # cleanup_step.raise_on_fail = true # clean_up steps should always raise on failure
131
- # run_step(cleanup_step)
132
- # end
133
- # end
134
- # end
135
-
136
- # # Step is a class that defines a single step in a Workflow.
137
- # class Step
138
- # include CemAcpt::LoggingAsync
139
-
140
- # attr_reader :group, :name, :opts, :result, :retry_delay, :retry_max, :runs
141
-
142
- # def initialize(name, **opts, &logic)
143
- # @name = name
144
- # @logic = logic
145
- # @group = opts[:group] || nil
146
- # @retryable = opts[:retryable] || false
147
- # @retry_delay = opts[:retry_delay] || 0
148
- # @retry_max = opts[:retry_max] || 3
149
- # @retry_group_on_fail = opts[:retry_group_on_fail] || false
150
- # @raise_on_fail = opts[:raise_on_fail] || true
151
- # @runs = 0
152
- # @opts = opts
153
- # @result = :not_run
154
- # end
155
-
156
- # def grouped?
157
- # !@group.nil?
158
- # end
159
-
160
- # def retryable?
161
- # @retryable
162
- # end
163
-
164
- # def retry_group_on_fail?
165
- # @retry_group_on_fail
166
- # end
167
-
168
- # def raise_on_fail?
169
- # @raise_on_fail
170
- # end
171
-
172
- # def retryable=(val)
173
- # raise ArgumentError, 'retryable must be a Boolean' unless val.is_a?(TrueClass) || val.is_a?(FalseClass)
174
-
175
- # @retryable = val
176
- # end
177
-
178
- # def retry_delay=(val)
179
- # raise ArgumentError, 'retry_delay must be an Integer' unless val.is_a?(Integer)
180
-
181
- # @retry_delay = val
182
- # end
183
-
184
- # def retry_group_on_fail=(val)
185
- # raise ArgumentError, 'retry_group_on_fail must be a Boolean' unless val.is_a?(TrueClass) || val.is_a?(FalseClass)
186
-
187
- # @retry_group_on_fail = val
188
- # end
189
-
190
- # def raise_on_fail=(val)
191
- # raise ArgumentError, 'raise_on_fail must be a Boolean' unless val.is_a?(TrueClass) || val.is_a?(FalseClass)
192
-
193
- # @raise_on_fail = val
194
- # end
195
-
196
- # def run
197
- # begin
198
- # @runs += 1
199
- # async_info("Running step #{@name}...") if @runs == 1
200
- # @result = @logic.call(@opts)
201
- # rescue StandardError => e
202
- # if retryable? && @runs < @retry_max
203
- # sleep @retry_delay if @retry_delay > 0
204
- # async_info("Retrying step #{@name} (attempt #{@runs + 1} of #{@retry_max})")
205
- # run
206
- # else
207
- # @result = CemAcpt::TestRunner::StepError.new(@name, e)
208
- # raise @result if raise_on_fail?
209
- # end
210
- # end
211
- # @result
212
- # end
213
- # end
214
- # end
215
- # end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemAcpt
4
- VERSION = '0.3.4'
4
+ VERSION = '0.3.5'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cem_acpt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.5
5
5
  platform: universal-java-17
6
6
  authors:
7
7
  - puppetlabs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-30 00:00:00.000000000 Z
11
+ date: 2023-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +190,7 @@ files:
190
190
  - lib/cem_acpt/spec_helper_acceptance.rb
191
191
  - lib/cem_acpt/test_data.rb
192
192
  - lib/cem_acpt/test_runner.rb
193
+ - lib/cem_acpt/test_runner/logging.rb
193
194
  - lib/cem_acpt/test_runner/run_handler.rb
194
195
  - lib/cem_acpt/test_runner/runner.rb
195
196
  - lib/cem_acpt/test_runner/runner_result.rb