cem_acpt 0.3.2-universal-java-17 → 0.3.4-universal-java-17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/spec.yml +36 -0
- data/Gemfile.lock +12 -2
- data/cem_acpt.gemspec +1 -0
- data/lib/cem_acpt/platform/gcp/cmd.rb +31 -0
- data/lib/cem_acpt/platform/gcp/compute.rb +24 -0
- data/lib/cem_acpt/platform/gcp.rb +16 -4
- data/lib/cem_acpt/platform/utils/linux.rb +39 -0
- data/lib/cem_acpt/platform.rb +4 -3
- data/lib/cem_acpt/test_runner/runner.rb +40 -104
- data/lib/cem_acpt/test_runner/runner_workflow_builder.rb +238 -0
- data/lib/cem_acpt/test_runner/workflow/manager.rb +160 -0
- data/lib/cem_acpt/test_runner/workflow/step.rb +187 -0
- data/lib/cem_acpt/test_runner/workflow.rb +215 -0
- data/lib/cem_acpt/version.rb +1 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c289fcb52a1115630ffece04c465e5a8d945bdefdcc99fbf73a800398d2f2bc6
|
4
|
+
data.tar.gz: aca0f41efe831bf5bb8dc4399cd1a2d771f7bb72fb1ee13eeccb79d59bd45183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65dd7b8c5023304f0c5f9fd371a64cfb157567004d6f93ebdadc76bbf99f50f7483fab575f73fb9c07256cbb0db688ad4d8c10a6b644a8f7670a3441a54e866e
|
7
|
+
data.tar.gz: 2504bc3dc1ef1ac1a09c16d00c3cd99b08127ccd31f2b9da134f31ffb2dc19730eda580ec893def0a9b183bd4198c5aa8263ea735f50c0b2c21156a5f8f7124d
|
@@ -0,0 +1,36 @@
|
|
1
|
+
name: Unit Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
workflow_dispatch:
|
5
|
+
pull_request:
|
6
|
+
types:
|
7
|
+
- opened
|
8
|
+
- synchronize
|
9
|
+
branches:
|
10
|
+
- main
|
11
|
+
tags:
|
12
|
+
- v.*
|
13
|
+
|
14
|
+
jobs:
|
15
|
+
tests:
|
16
|
+
name: RSpec tests
|
17
|
+
runs-on: ubuntu-20.04
|
18
|
+
steps:
|
19
|
+
- name: Checkout Source
|
20
|
+
uses: actions/checkout@v3
|
21
|
+
|
22
|
+
- name: Set up Java 17
|
23
|
+
uses: actions/setup-java@v3
|
24
|
+
with:
|
25
|
+
distribution: 'adopt-hotspot'
|
26
|
+
java-version: '17'
|
27
|
+
|
28
|
+
- name: Set up JRuby
|
29
|
+
uses: ruby/setup-ruby@v1
|
30
|
+
with:
|
31
|
+
ruby-version: jruby-9.3.3.0
|
32
|
+
bundler-cache: true
|
33
|
+
|
34
|
+
- name: Run RSpec
|
35
|
+
run: |
|
36
|
+
bundle exec rake spec
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cem_acpt (0.3.
|
4
|
+
cem_acpt (0.3.4-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)
|
@@ -13,10 +13,13 @@ GEM
|
|
13
13
|
remote: https://rubygems.org/
|
14
14
|
specs:
|
15
15
|
ast (2.4.2)
|
16
|
+
coderay (1.1.3)
|
16
17
|
concurrent-ruby (1.1.10)
|
17
18
|
deep_merge (1.2.2)
|
18
19
|
diff-lcs (1.5.0)
|
19
20
|
ed25519 (1.3.0-java)
|
21
|
+
ffi (1.15.5-java)
|
22
|
+
method_source (1.0.0)
|
20
23
|
minitar (0.9)
|
21
24
|
multi_json (1.15.0)
|
22
25
|
net-scp (4.0.0)
|
@@ -27,6 +30,10 @@ GEM
|
|
27
30
|
parser (3.1.2.0)
|
28
31
|
ast (~> 2.4.1)
|
29
32
|
pathspec (1.0.0)
|
33
|
+
pry (0.14.2-java)
|
34
|
+
coderay (~> 1.1)
|
35
|
+
method_source (~> 1.0)
|
36
|
+
spoon (~> 0.0)
|
30
37
|
puppet-modulebuilder (0.3.0)
|
31
38
|
minitar (~> 0.9)
|
32
39
|
pathspec (>= 0.2.1, < 2.0.0)
|
@@ -73,6 +80,8 @@ GEM
|
|
73
80
|
net-ssh (>= 2.7)
|
74
81
|
net-telnet (= 0.1.1)
|
75
82
|
sfl
|
83
|
+
spoon (0.0.6)
|
84
|
+
ffi
|
76
85
|
unicode-display_width (2.2.0)
|
77
86
|
|
78
87
|
PLATFORMS
|
@@ -80,9 +89,10 @@ PLATFORMS
|
|
80
89
|
|
81
90
|
DEPENDENCIES
|
82
91
|
cem_acpt!
|
92
|
+
pry
|
83
93
|
rake (>= 12.0)
|
84
94
|
rspec (>= 3.0)
|
85
95
|
rubocop
|
86
96
|
|
87
97
|
BUNDLED WITH
|
88
|
-
2.3.
|
98
|
+
2.3.15
|
data/cem_acpt.gemspec
CHANGED
@@ -4,6 +4,7 @@ module CemAcpt::Platform::Gcp
|
|
4
4
|
require 'json'
|
5
5
|
require 'open3'
|
6
6
|
require_relative File.join(__dir__, '..', 'base', 'cmd.rb')
|
7
|
+
require_relative File.join(__dir__, '..', 'utils', 'linux.rb')
|
7
8
|
|
8
9
|
# This class provides methods to run gcloud commands. It allows for default values to be
|
9
10
|
# set for the project, zone, and user and can also find these values from the local config.
|
@@ -59,6 +60,10 @@ module CemAcpt::Platform::Gcp
|
|
59
60
|
@local_port ||= rand(49_512..65_535)
|
60
61
|
end
|
61
62
|
|
63
|
+
def os_release
|
64
|
+
@os_release || :not_set
|
65
|
+
end
|
66
|
+
|
62
67
|
def ssh_key
|
63
68
|
return @ssh_key unless @ssh_key.nil?
|
64
69
|
|
@@ -173,12 +178,38 @@ module CemAcpt::Platform::Gcp
|
|
173
178
|
logger.debug('Restarting SSH service')
|
174
179
|
gcloud_ssh(instance_name, 'sudo systemctl restart sshd', ignore_command_errors: true)
|
175
180
|
logger.info("SSH connection to #{instance_name} is ready")
|
181
|
+
logger.debug('Getting OS release')
|
182
|
+
osr = gcloud_ssh(instance_name, 'sudo cat /etc/os-release')
|
183
|
+
@os_release = CemAcpt::Platform::Utils::Linux::OSRelease.new(osr)
|
184
|
+
logger.debug("OS release: #{@os_release.to_h}")
|
176
185
|
true
|
177
186
|
rescue StandardError => e
|
178
187
|
logger.debug("SSH connection to #{instance_name} failed: #{e}")
|
179
188
|
false
|
180
189
|
end
|
181
190
|
|
191
|
+
def dnf_automatic_success?(instance_name, opts: {})
|
192
|
+
ssh_options = ssh_opts(instance_name: instance_name, opts: opts)
|
193
|
+
logger.debug("Checking dnf-automatic success on #{instance_name} with options #{ssh_options}")
|
194
|
+
gcloud_ssh(instance_name, 'sudo systemctl restart dnf-automatic.timer')
|
195
|
+
true
|
196
|
+
rescue StandardError => e
|
197
|
+
logger.error("DNF automatic updates on #{instance_name} failed: #{e}")
|
198
|
+
false
|
199
|
+
end
|
200
|
+
|
201
|
+
def rpm_db_check_success?(instance_name, pkgmgr, opts: {})
|
202
|
+
ssh_options = ssh_opts(instance_name: instance_name, opts: opts)
|
203
|
+
logger.debug("Checking #{pkgmgr} rpm db on #{instance_name} with options #{ssh_options}")
|
204
|
+
gcloud_ssh(instance_name, "sudo #{pkgmgr} upgrade -y rpm glibc")
|
205
|
+
gcloud_ssh(instance_name, "sudo rm -f /var/lib/rpm/.rpm.lock")
|
206
|
+
gcloud_ssh(instance_name, "sudo #{pkgmgr} upgrade -y #{pkgmgr}")
|
207
|
+
true
|
208
|
+
rescue StandardError => e
|
209
|
+
logger.error("#{pkgmgr} rpm db check on #{instance_name} failed: #{e}")
|
210
|
+
false
|
211
|
+
end
|
212
|
+
|
182
213
|
# This function spawns a background thread to run a GCP IAP tunnel, run the given
|
183
214
|
# code block, then kill the thread. The code block will be yielded ssh_opts that
|
184
215
|
# are used to configure SSH connections over the IAP tunnel. The IAP tunnel is
|
@@ -236,6 +236,7 @@ module CemAcpt::Platform::Gcp
|
|
236
236
|
node_data: data,
|
237
237
|
transport: :ssh,
|
238
238
|
ssh_opts: opts,
|
239
|
+
os_release: os_release.to_h,
|
239
240
|
}
|
240
241
|
end
|
241
242
|
|
@@ -260,6 +261,29 @@ module CemAcpt::Platform::Gcp
|
|
260
261
|
false
|
261
262
|
end
|
262
263
|
|
264
|
+
def dnf_automatic_success?
|
265
|
+
if os_release.name.match?(%r{^Red Hat.*}) && os_release.version.match?(%r{^(8|9).*})
|
266
|
+
logger.debug("Checking dnf-automatic on #{name} with platform #{info[:os_release][:platform]}")
|
267
|
+
@cmd.dnf_automatic_success?(name)
|
268
|
+
else
|
269
|
+
true
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def rpm_db_check_success?
|
274
|
+
if os_release.name.match?(%r{^Red Hat.*})
|
275
|
+
logger.debug("Checking rpmdb on #{name} with platform #{info[:os_release][:platform]}")
|
276
|
+
pkgmgr = os_release.version.match?(%r{^(8|9).*}) ? 'dnf' : 'yum'
|
277
|
+
@cmd.rpm_db_check_success?(name, pkgmgr)
|
278
|
+
else
|
279
|
+
true
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def os_release
|
284
|
+
@cmd.os_release
|
285
|
+
end
|
286
|
+
|
263
287
|
def destroy
|
264
288
|
@cmd.delete_instance(name)
|
265
289
|
end
|
@@ -12,9 +12,9 @@ module Platform
|
|
12
12
|
|
13
13
|
# Provision a GCP instance
|
14
14
|
def provision
|
15
|
-
creation_params = config
|
16
|
-
creation_params[:disk][:image_name] = image_name
|
17
|
-
creation_params[:local_port] = local_port
|
15
|
+
creation_params = Marshal.load(Marshal.dump(config))
|
16
|
+
creation_params[:disk][:image_name] = image_name
|
17
|
+
creation_params[:local_port] = local_port
|
18
18
|
@instance = CemAcpt::Platform::Gcp::VM.new(
|
19
19
|
node_name.dup,
|
20
20
|
components: creation_params,
|
@@ -35,6 +35,18 @@ module Platform
|
|
35
35
|
@instance.ready?
|
36
36
|
end
|
37
37
|
|
38
|
+
# Returns true if dnf_automatic ran successfully on the GCP instance
|
39
|
+
def dnf_automatic_success?
|
40
|
+
logger.debug("Checking if dnf_automatic ran successfully on #{node_name}...")
|
41
|
+
@instance.dnf_automatic_success?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns true if rpm_db_check ran successfully on the GCP instance
|
45
|
+
def rpm_db_check_success?
|
46
|
+
logger.debug("Checking if rpm_db_check ran successfully on #{node_name}...")
|
47
|
+
@instance.rpm_db_check_success?
|
48
|
+
end
|
49
|
+
|
38
50
|
# Runs the test suite against the GCP instance. Must be given a block.
|
39
51
|
# If necessary, can pass information into the block to be used in the test suite.
|
40
52
|
def run_tests(&block)
|
@@ -64,7 +76,7 @@ module Platform
|
|
64
76
|
CemAcpt::Platform::Gcp::Cmd.new(out_format: 'json')
|
65
77
|
end
|
66
78
|
|
67
|
-
#
|
79
|
+
# Applies the given Puppet manifest on the given instance
|
68
80
|
# @param instance_name [String] the name of the instance to apply the manifest to
|
69
81
|
# @param manifest [String] the Puppet manifest to apply
|
70
82
|
# @param opts [Hash] options to pass to the apply command
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CemAcpt
|
4
|
+
module Platform
|
5
|
+
module Utils
|
6
|
+
module Linux
|
7
|
+
class OSRelease
|
8
|
+
attr_reader :properties
|
9
|
+
|
10
|
+
def initialize(os_release)
|
11
|
+
@os_release = parse_string(os_release)
|
12
|
+
@properties = []
|
13
|
+
define_properties(@os_release)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
@os_release
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_string(os_release)
|
23
|
+
os_release = os_release.split("\n")
|
24
|
+
os_release = os_release.map { |line| line.split('=', 2) }.reject { |l| l.length != 2 }
|
25
|
+
os_release.map! { |k, v| [k.downcase, v.delete_prefix('"').delete_suffix('"')] }
|
26
|
+
os_release.to_h
|
27
|
+
end
|
28
|
+
|
29
|
+
def define_properties(hsh)
|
30
|
+
hsh.each do |k, v|
|
31
|
+
@properties << k
|
32
|
+
self.class.send(:define_method, k) { v }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/cem_acpt/platform.rb
CHANGED
@@ -59,12 +59,13 @@ module CemAcpt::Platform
|
|
59
59
|
# @param platform [String] the name of the platform.
|
60
60
|
# @return [Class] the platform-specific Object.
|
61
61
|
def platform_class(platform)
|
62
|
+
class_name = platform.capitalize
|
62
63
|
# We require the platform base class here so that we can use it as
|
63
64
|
# a parent class for the platform-specific class.
|
64
65
|
require_relative 'platform/base'
|
65
66
|
# If the class has already been defined, we can just use it.
|
66
|
-
if Object.const_defined?(
|
67
|
-
klass = Object.const_get(
|
67
|
+
if Object.const_defined?(class_name)
|
68
|
+
klass = Object.const_get(class_name)
|
68
69
|
else
|
69
70
|
# Otherwise, we need to create the class. We do this by setting
|
70
71
|
# a new constant with the name of the platform capitalized, and
|
@@ -74,7 +75,7 @@ module CemAcpt::Platform
|
|
74
75
|
# include Logging and Concurrent::Async, and finally call the
|
75
76
|
# initialize method on the class.
|
76
77
|
klass = Object.const_set(
|
77
|
-
|
78
|
+
class_name,
|
78
79
|
Class.new(CemAcpt::Platform::Base) do
|
79
80
|
require_relative "platform/#{platform}"
|
80
81
|
include Platform
|
@@ -5,6 +5,8 @@ require 'English'
|
|
5
5
|
require_relative '../logging'
|
6
6
|
require_relative '../rspec_utils'
|
7
7
|
require_relative 'runner_result'
|
8
|
+
require_relative 'runner_workflow_builder'
|
9
|
+
#require_relative 'workflow'
|
8
10
|
|
9
11
|
module CemAcpt
|
10
12
|
module TestRunner
|
@@ -23,6 +25,8 @@ module CemAcpt
|
|
23
25
|
|
24
26
|
class RunnerProvisionError < RunnerStepError; end
|
25
27
|
|
28
|
+
|
29
|
+
|
26
30
|
# Runner is a class that runs a single acceptance test suite on a single node.
|
27
31
|
# It is responsible for managing the lifecycle of the test suite and
|
28
32
|
# reporting the results back to the main thread. Runner objects are created
|
@@ -32,6 +36,8 @@ module CemAcpt
|
|
32
36
|
|
33
37
|
attr_reader :node, :node_exists, :run_result
|
34
38
|
|
39
|
+
MAX_PROVISION_ATTEMPTS = 3
|
40
|
+
|
35
41
|
# @param node [String] the name of the node to run the acceptance test suite on
|
36
42
|
# @param ctx [CemAcpt::RunnerCtx] a cem_acpt Ctx (context) object
|
37
43
|
# @param module_pkg_path [Concurrent::IVar] the path to the module package
|
@@ -42,34 +48,33 @@ module CemAcpt
|
|
42
48
|
@debug_mode = @context.config.debug_mode?
|
43
49
|
@node_inventory = @context.node_inventory
|
44
50
|
@module_pkg_path = @context.module_package_path
|
51
|
+
@provision_attempts = 0
|
52
|
+
@provision_start_time = nil
|
45
53
|
@node_exists = false
|
46
54
|
@run_result = CemAcpt::TestRunner::RunnerResult.new(@node, debug: @debug_mode)
|
47
|
-
@completed_steps = []
|
48
55
|
validate!
|
49
56
|
end
|
50
57
|
|
51
|
-
def run_step(step_sym)
|
52
|
-
send(step_sym)
|
53
|
-
@completed_steps << step_sym
|
54
|
-
rescue StandardError => e
|
55
|
-
err = CemAcpt::TestRunner::RunnerStepError.new(step_sym, e)
|
56
|
-
step_error_logging(err)
|
57
|
-
@run_result.from_error(err)
|
58
|
-
destroy unless step_sym == :destroy
|
59
|
-
end
|
60
|
-
|
61
58
|
# Executes test suite steps
|
62
59
|
def start
|
63
60
|
async_info("Starting test suite for #{@node.node_name}", log_prefix('RUNNER'))
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
@workflow = new_workflow
|
62
|
+
@workflow.run
|
63
|
+
if @workflow.success?
|
64
|
+
@run_result = @workflow.last_result
|
65
|
+
@workflow.completed_steps.each do |s|
|
66
|
+
async_info("Step '#{s.name}' completed successfully", log_prefix('RUNNER'))
|
67
|
+
end
|
68
|
+
true
|
69
|
+
else
|
70
|
+
@run_result = @workflow.last_error
|
71
|
+
step_error_logging(@workflow.last_error)
|
72
|
+
false
|
73
|
+
end
|
69
74
|
rescue StandardError => e
|
70
75
|
step_error_logging(e)
|
76
|
+
@run_result = CemAcpt::TestRunner::RunnerResult.new(@node, debug: @debug_mode)
|
71
77
|
@run_result.from_error(e)
|
72
|
-
destroy
|
73
78
|
end
|
74
79
|
|
75
80
|
# Checks for failures in the test results.
|
@@ -81,6 +86,24 @@ module CemAcpt
|
|
81
86
|
|
82
87
|
private
|
83
88
|
|
89
|
+
# Builds a new workflow for the runner
|
90
|
+
# @return [CemAcpt::TestRunner::Workflow::Manager] the new workflow
|
91
|
+
def new_workflow
|
92
|
+
builder = RunnerWorkflowBuilder.new(@node, config: @context.config)
|
93
|
+
builder.add_provision
|
94
|
+
builder.add_sleep(time: 30)
|
95
|
+
builder.add_wait_for_node_ssh
|
96
|
+
builder.add_check_dnf_automatic
|
97
|
+
builder.add_check_rpm_db
|
98
|
+
builder.add_save_node_to_inventory(node_inventory: @node_inventory, platform: @platform)
|
99
|
+
builder.add_check_for_module_package_path(module_pkg_path: @module_pkg_path)
|
100
|
+
builder.add_install_module(module_pkg_path: @module_pkg_path)
|
101
|
+
builder.add_check_node_inventory_file(node_inventory: @node_inventory)
|
102
|
+
builder.add_run_tests(rspec_opts: rspec_opts, rspec_cmd: CemAcpt::RSpecUtils::Command, run_result: @run_result)
|
103
|
+
builder.add_clean_up
|
104
|
+
builder.workflow
|
105
|
+
end
|
106
|
+
|
84
107
|
def step_error_logging(err)
|
85
108
|
prefix = err.respond_to?(:step) ? log_prefix(err.step.capitalize) : log_prefix('RUNNER')
|
86
109
|
fatal_msg = ["runner failed: #{err.message}"]
|
@@ -94,93 +117,6 @@ module CemAcpt
|
|
94
117
|
"#{prefix}: #{@node.test_data[:test_name]}:"
|
95
118
|
end
|
96
119
|
|
97
|
-
# Provisions the node for the acceptance test suite.
|
98
|
-
def provision
|
99
|
-
async_info("Provisioning #{@node.node_name}...", log_prefix('PROVISION'))
|
100
|
-
start_time = Time.now
|
101
|
-
@node.provision
|
102
|
-
@node_exists = true
|
103
|
-
max_retries = 60 # equals 300 seconds because we check every five seconds
|
104
|
-
until @node.ready?
|
105
|
-
if max_retries <= 0
|
106
|
-
async_fatal("Node #{@node.node_name} failed to provision", log_prefix('PROVISION'))
|
107
|
-
raise CemAcpt::TestRunner::RunnerProvisionError, "Provisioning timed out for node #{@node.node_name}"
|
108
|
-
end
|
109
|
-
|
110
|
-
async_info("Waiting for #{@node.node_name} to be ready for remote connections...", log_prefix('PROVISION'))
|
111
|
-
max_retries -= 1
|
112
|
-
sleep(5)
|
113
|
-
end
|
114
|
-
async_info("Node #{@node.node_name} is ready...", log_prefix('PROVISION'))
|
115
|
-
node_desc = {
|
116
|
-
test_data: @node.test_data,
|
117
|
-
platform: @platform,
|
118
|
-
local_port: @node.local_port,
|
119
|
-
}.merge(@node.node)
|
120
|
-
@node_inventory.add(@node.node_name, node_desc)
|
121
|
-
@node_inventory.save
|
122
|
-
async_info("Node #{@node.node_name} provisioned in #{Time.now - start_time} seconds", log_prefix('PROVISION'))
|
123
|
-
end
|
124
|
-
|
125
|
-
# Bootstraps the node for the acceptance test suite. Currently, this
|
126
|
-
# just uploads and installs the module package.
|
127
|
-
def bootstrap
|
128
|
-
async_info("Bootstrapping #{@node.node_name}...", log_prefix('BOOTSTRAP'))
|
129
|
-
until File.exist?(@module_pkg_path)
|
130
|
-
async_debug("Waiting for module package #{@module_pkg_path} to exist...", log_prefix('BOOTSTRAP'))
|
131
|
-
sleep(1)
|
132
|
-
end
|
133
|
-
async_info("Installing module package #{@module_pkg_path}...", log_prefix('BOOTSTRAP'))
|
134
|
-
@node.install_puppet_module_package(@module_pkg_path)
|
135
|
-
end
|
136
|
-
|
137
|
-
# Runs the acceptance test suite via rspec.
|
138
|
-
def run_tests
|
139
|
-
attempts = 0
|
140
|
-
until File.exist?(@node_inventory.save_file_path)
|
141
|
-
raise 'Node inventory file not found' if (attempts += 1) > 3
|
142
|
-
|
143
|
-
sleep(1)
|
144
|
-
end
|
145
|
-
async_info("Running test #{@node.test_data[:test_name]} on node #{@node.node_name}...", log_prefix('RSPEC'))
|
146
|
-
@node.run_tests do |cmd_env|
|
147
|
-
cmd_opts = rspec_opts
|
148
|
-
cmd_opts.env = cmd_opts.env.merge(cmd_env) if cmd_env
|
149
|
-
# Documentation format gets logged in real time, JSON file is read after the fact
|
150
|
-
begin
|
151
|
-
@rspec_cmd = CemAcpt::RSpecUtils::Command.new(cmd_opts)
|
152
|
-
@rspec_cmd.execute(pty: false, log_prefix: log_prefix('RSPEC'))
|
153
|
-
@run_result.from_json_file(cmd_opts.format[:json])
|
154
|
-
rescue Errno::EIO => e
|
155
|
-
async_error("failed to run rspec: #{@node.test_data[:test_name]}: #{$ERROR_INFO}", log_prefix('RSPEC'))
|
156
|
-
@run_result.from_error(e)
|
157
|
-
rescue StandardError => e
|
158
|
-
async_error("failed to run rspec: #{@node.test_data[:test_name]}: #{e.message}", log_prefix('RSPEC'))
|
159
|
-
async_debug("Backtrace:\n#{e.backtrace}", log_prefix('RSPEC'))
|
160
|
-
@run_result.from_error(e)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
async_info("Tests completed with exit code: #{@run_result.exit_status}", log_prefix('RSPEC'))
|
164
|
-
end
|
165
|
-
|
166
|
-
# Destroys the node for the acceptance test suite.
|
167
|
-
def destroy
|
168
|
-
kill_spec_pty_if_exists
|
169
|
-
if @context.config.get('no_destroy_nodes')
|
170
|
-
async_info("Not destroying node #{@node.node_name} because 'no_destroy_nodes' is set to true",
|
171
|
-
log_prefix('DESTROY'))
|
172
|
-
else
|
173
|
-
async_info("Destroying #{@node.node_name}...", log_prefix('DESTROY'))
|
174
|
-
@node.destroy
|
175
|
-
@node_exists = false
|
176
|
-
async_info("Node #{@node.node_name} destroyed successfully", log_prefix('DESTROY'))
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
def kill_spec_pty_if_exists
|
181
|
-
@rspec_cmd&.kill_pty
|
182
|
-
end
|
183
|
-
|
184
120
|
# Validates the runner configuration.
|
185
121
|
def validate!
|
186
122
|
raise 'No node provided' unless @node
|