cem_acpt 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/Gemfile.lock +42 -14
- data/README.md +8 -0
- data/cem_acpt.gemspec +3 -1
- data/exe/cem_acpt_image +0 -0
- data/lib/cem_acpt/action_result.rb +85 -0
- data/lib/cem_acpt/cli.rb +42 -22
- data/lib/cem_acpt/config/base.rb +4 -2
- data/lib/cem_acpt/goss/api.rb +8 -2
- data/lib/cem_acpt/image_builder.rb +64 -72
- data/lib/cem_acpt/logging.rb +41 -30
- data/lib/cem_acpt/platform.rb +4 -5
- data/lib/cem_acpt/provision/terraform/linux.rb +2 -2
- data/lib/cem_acpt/provision/terraform/terraform_cmd.rb +181 -0
- data/lib/cem_acpt/provision/terraform/windows.rb +9 -0
- data/lib/cem_acpt/provision/terraform.rb +34 -47
- data/lib/cem_acpt/provision.rb +1 -1
- data/lib/cem_acpt/puppet_helpers.rb +1 -1
- data/lib/cem_acpt/test_data.rb +3 -3
- data/lib/cem_acpt/test_runner/log_formatter/error_formatter.rb +33 -0
- data/lib/cem_acpt/test_runner/log_formatter.rb +10 -1
- data/lib/cem_acpt/test_runner.rb +151 -52
- data/lib/cem_acpt/utils/ssh.rb +2 -2
- data/lib/cem_acpt/utils/terminal.rb +1 -5
- data/lib/cem_acpt/utils/winrm_runner.rb +160 -0
- data/lib/cem_acpt/utils.rb +41 -1
- data/lib/cem_acpt/version.rb +1 -1
- data/lib/cem_acpt.rb +51 -21
- data/lib/terraform/gcp/windows/main.tf +26 -0
- metadata +46 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 853cc9a89c0feaf798bb5efdfc0c8af47d2664121cddd3794b65a61d5dc80851
|
4
|
+
data.tar.gz: 6d0d5c67e27918d7897ea567a4134249c8a81e23ea95e6a3850a65585ebdd3e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 244c701ba966fa878c399efba4953db7be8f5977c906501f9d2da8410583ebf2c2c505c687dc03e8cd97b325f362b28472f68c089065cda21f83d01d16c15d22
|
7
|
+
data.tar.gz: ae7ca222e4264ed32ed47df2745d76c8347c1b5eab94cd2f0278af581c7c7108fb006232c5bbb4d37b2455559c0826a5630498cd620d4fd85a8948b8a0856c22
|
data/.rubocop.yml
CHANGED
@@ -3,7 +3,7 @@ require:
|
|
3
3
|
- rubocop-performance
|
4
4
|
- rubocop-rspec
|
5
5
|
AllCops:
|
6
|
-
NewCops:
|
6
|
+
NewCops: disable
|
7
7
|
SuggestExtensions: false
|
8
8
|
DisplayCopNames: true
|
9
9
|
TargetRubyVersion: '3.2'
|
@@ -414,6 +414,8 @@ Style/HashAsLastArrayItem:
|
|
414
414
|
Enabled: false
|
415
415
|
Style/HashLikeCase:
|
416
416
|
Enabled: false
|
417
|
+
Style/HashSyntax:
|
418
|
+
Enabled: false
|
417
419
|
Style/HashTransformKeys:
|
418
420
|
Enabled: false
|
419
421
|
Style/HashTransformValues:
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cem_acpt (0.
|
4
|
+
cem_acpt (0.8.0)
|
5
5
|
async-http (>= 0.60, < 0.70)
|
6
6
|
bcrypt_pbkdf (>= 1.0, < 2.0)
|
7
7
|
deep_merge (>= 1.2, < 2.0)
|
8
8
|
ed25519 (>= 1.2, < 2.0)
|
9
9
|
puppet-modulebuilder (>= 0.0.1)
|
10
|
-
|
10
|
+
winrm (>= 2.3, < 3.0)
|
11
11
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
@@ -30,25 +30,32 @@ GEM
|
|
30
30
|
async-pool (0.4.0)
|
31
31
|
async (>= 1.25)
|
32
32
|
bcrypt_pbkdf (1.1.0)
|
33
|
+
builder (3.2.4)
|
33
34
|
coderay (1.1.3)
|
34
|
-
concurrent-ruby (1.2.2)
|
35
35
|
console (1.16.2)
|
36
36
|
fiber-local
|
37
37
|
deep_merge (1.2.2)
|
38
38
|
diff-lcs (1.5.0)
|
39
39
|
ed25519 (1.3.0)
|
40
|
+
erubi (1.12.0)
|
41
|
+
ffi (1.15.5)
|
40
42
|
fiber-local (1.0.0)
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
gssapi (1.3.1)
|
44
|
+
ffi (>= 1.0.1)
|
45
|
+
gyoku (1.4.0)
|
46
|
+
builder (>= 2.1.2)
|
47
|
+
rexml (~> 3.0)
|
48
|
+
httpclient (2.8.3)
|
44
49
|
io-event (1.1.7)
|
45
50
|
json (2.6.3)
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
little-plugger (1.1.4)
|
52
|
+
logging (2.3.1)
|
53
|
+
little-plugger (~> 1.1)
|
54
|
+
multi_json (~> 1.14)
|
49
55
|
method_source (1.0.0)
|
50
56
|
minitar (0.9)
|
51
|
-
|
57
|
+
multi_json (1.15.0)
|
58
|
+
nori (2.6.0)
|
52
59
|
parallel (1.22.1)
|
53
60
|
parser (3.2.1.1)
|
54
61
|
ast (~> 2.4.1)
|
@@ -95,15 +102,34 @@ GEM
|
|
95
102
|
unicode-display_width (>= 2.4.0, < 3.0)
|
96
103
|
rubocop-ast (1.28.0)
|
97
104
|
parser (>= 3.2.1.0)
|
105
|
+
rubocop-capybara (2.18.0)
|
106
|
+
rubocop (~> 1.41)
|
107
|
+
rubocop-factory_bot (2.23.1)
|
108
|
+
rubocop (~> 1.33)
|
109
|
+
rubocop-performance (1.19.0)
|
110
|
+
rubocop (>= 1.7.0, < 2.0)
|
111
|
+
rubocop-ast (>= 0.4.0)
|
112
|
+
rubocop-rspec (2.23.2)
|
113
|
+
rubocop (~> 1.33)
|
114
|
+
rubocop-capybara (~> 2.17)
|
115
|
+
rubocop-factory_bot (~> 2.22)
|
98
116
|
ruby-progressbar (1.13.0)
|
99
|
-
|
100
|
-
immutable-struct (~> 2.4)
|
101
|
-
lino (~> 3.0)
|
117
|
+
rubyntlm (0.6.3)
|
102
118
|
timers (4.3.5)
|
103
119
|
traces (0.9.1)
|
104
120
|
unicode-display_width (2.4.2)
|
121
|
+
winrm (2.3.6)
|
122
|
+
builder (>= 2.1.2)
|
123
|
+
erubi (~> 1.8)
|
124
|
+
gssapi (~> 1.2)
|
125
|
+
gyoku (~> 1.0)
|
126
|
+
httpclient (~> 2.2, >= 2.2.0.2)
|
127
|
+
logging (>= 1.6.1, < 3.0)
|
128
|
+
nori (~> 2.0)
|
129
|
+
rubyntlm (~> 0.6.0, >= 0.6.3)
|
105
130
|
|
106
131
|
PLATFORMS
|
132
|
+
arm64-darwin-22
|
107
133
|
x86_64-darwin-20
|
108
134
|
x86_64-linux
|
109
135
|
|
@@ -113,6 +139,8 @@ DEPENDENCIES
|
|
113
139
|
rake (>= 12.0)
|
114
140
|
rspec (>= 3.0)
|
115
141
|
rubocop
|
142
|
+
rubocop-performance
|
143
|
+
rubocop-rspec
|
116
144
|
|
117
145
|
BUNDLED WITH
|
118
|
-
2.4.
|
146
|
+
2.4.18
|
data/README.md
CHANGED
@@ -89,6 +89,10 @@ Options set in the user-specific config file will be overridden by options set i
|
|
89
89
|
|
90
90
|
CemAcpt can be configured using command-line options. These options are specified using the `--<option>` syntax. For a full list of options, run `cem_acpt -h`. Options specified on the command-line will override options specified in the config file and environment variables.
|
91
91
|
|
92
|
+
#### Tracing
|
93
|
+
|
94
|
+
To aide in development, you can enable tracing on CemAcpt's Ruby code execution by using the `--trace` flag. Traces are logged only for events executed by CemAcpt code itself, and the logger code is exempt from tracing. **CAUTION** Tracing produces **a lot** of logs and it's advised to only use it when logging to a file. Additionally, the specific trace events that are logged can be specified using the `--trace-events` flag. Tracing is enabled by the [TracePoint](https://ruby-doc.org/core-3.1.0/TracePoint.html) class.
|
95
|
+
|
92
96
|
## Goss
|
93
97
|
|
94
98
|
[Goss](https://github.com/goss-org/goss/blob/master/docs/manual.md) is the core infrastructure testing tool used by CemAcpt. The `goss.yaml` file is used to specify the tests to run. Please see the [Goss documentation](https://github.com/goss-org/goss/blob/master/docs/manual.md#goss-test-creation) for more information on how to write Goss tests.
|
@@ -248,3 +252,7 @@ images:
|
|
248
252
|
```
|
249
253
|
|
250
254
|
See [sample_config.yaml](sample_config.yaml) for a more complete example.
|
255
|
+
|
256
|
+
### Testing with cem_windows
|
257
|
+
|
258
|
+
While testing with cem_windows follows pretty much the same outline as cem_linux, there are a few extra step that we have to do when bootstrapping the generated node. Two of the most prominents steps are enabling long path and using NSSM to start the goss service. When we enable long path on Windows, it allows the command `puppet module install` to install dependencies correctly (specifically the dsc modules). As for [NSSM](https://nssm.cc/), stands for Non-sucking service manager, it is necessary for us to use this tool because without it, we will not be able to create services for Goss. Windows services cannot run from an executable but rather through a Windows service project that can be build with Visual Studio. NSSM allows us to bypass having to create Windows service project for Goss and create services directly from the Goss executable.
|
data/cem_acpt.gemspec
CHANGED
@@ -32,7 +32,9 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_runtime_dependency 'deep_merge', '>= 1.2', '< 2.0'
|
33
33
|
spec.add_runtime_dependency 'ed25519', '>= 1.2', '< 2.0'
|
34
34
|
spec.add_runtime_dependency 'puppet-modulebuilder', '>= 0.0.1'
|
35
|
-
spec.add_runtime_dependency '
|
35
|
+
spec.add_runtime_dependency 'winrm', '>= 2.3', '< 3.0'
|
36
36
|
spec.add_development_dependency 'pry'
|
37
37
|
spec.add_development_dependency 'rubocop'
|
38
|
+
spec.add_development_dependency 'rubocop-performance'
|
39
|
+
spec.add_development_dependency 'rubocop-rspec'
|
38
40
|
end
|
data/exe/cem_acpt_image
CHANGED
File without changes
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CemAcpt
|
4
|
+
# Wrapper class for the result of an action. Provides a common interface for
|
5
|
+
# getting reportable data from the result.
|
6
|
+
class ActionResult
|
7
|
+
def initialize(result)
|
8
|
+
@result = if result.instance_of?(CemAcpt::Goss::Api::ActionResponse)
|
9
|
+
result
|
10
|
+
else
|
11
|
+
ErrorActionResult.new(result)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def error?
|
16
|
+
@result.is_a?(ErrorActionResult)
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_name, *args, **kwargs, &block)
|
20
|
+
if @result.respond_to?(method_name)
|
21
|
+
@result.send(method_name, *args, **kwargs, &block)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_to_missing?(method_name, include_private = false)
|
28
|
+
@result.respond_to?(method_name, include_private) || super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Wrapper class for an error raised during an action.
|
33
|
+
class ErrorActionResult
|
34
|
+
attr_reader :error
|
35
|
+
|
36
|
+
def initialize(error)
|
37
|
+
@error = error
|
38
|
+
end
|
39
|
+
|
40
|
+
def error?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def success?
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
"#<#{@error.class.name}:0x#{@error.object_id.to_s(16)}>"
|
50
|
+
end
|
51
|
+
|
52
|
+
def inspect
|
53
|
+
to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_h
|
57
|
+
{
|
58
|
+
class: @error.class.name,
|
59
|
+
message: @error.message,
|
60
|
+
backtrace: @error.backtrace,
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def status
|
65
|
+
1
|
66
|
+
end
|
67
|
+
alias http_status status
|
68
|
+
|
69
|
+
def results
|
70
|
+
@error.backtrace
|
71
|
+
end
|
72
|
+
|
73
|
+
def results?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def summary
|
78
|
+
@error.message
|
79
|
+
end
|
80
|
+
|
81
|
+
def summary?
|
82
|
+
true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/cem_acpt/cli.rb
CHANGED
@@ -9,7 +9,7 @@ module CemAcpt
|
|
9
9
|
options = {}
|
10
10
|
parser = OptionParser.new do |opts|
|
11
11
|
opts.banner = "Usage: #{command} [options]"
|
12
|
-
|
12
|
+
|
13
13
|
opts.on('-h', '--help', 'Show this help message') do
|
14
14
|
puts opts
|
15
15
|
exit 0
|
@@ -21,17 +21,17 @@ module CemAcpt
|
|
21
21
|
opts.on('-m', '--module-dir DIR', 'Set module directory. Example: -m "/tmp/module"') do |m|
|
22
22
|
options[:module_dir] = m
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
opts.on('-a', '--only-actions ACTIONS', 'Set actions. Example: -a "acpt,noop"') do |a|
|
26
26
|
options[:actions] ||= {}
|
27
27
|
options[:actions][:only] = a.split(',')
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
opts.on('-A', '--except-actions ACTIONS', 'Set excluded actions. Example: -A "noop,idempotent"') do |a|
|
31
31
|
options[:actions] ||= {}
|
32
32
|
options[:actions][:except] = a.split(',')
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
opts.on('-t', '--tests TESTS', 'Set tests. Example: -t "test1,test2"') do |t|
|
36
36
|
options[:tests] = t.split(',')
|
37
37
|
end
|
@@ -58,67 +58,87 @@ module CemAcpt
|
|
58
58
|
options[:image_name_filter] = Regexp.new(f)
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
opts.on('-D', '--debug', 'Enable debug logging') do
|
63
63
|
options[:log_level] = 'debug'
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
opts.on('-L', '--log-file FILE', 'Log to FILE') do |file|
|
67
67
|
options[:log_file] = file
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
opts.on('-O', '--options OPTS', 'Set options. Example: -P "param1=value1,param2=value2"') do |o|
|
71
71
|
params = o.split(',').map { |s| s.split('=') }.to_h
|
72
72
|
params.transform_keys(&:to_sym).each do |k, v|
|
73
73
|
options[k] = v
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
opts.on('-p', '--platform PLATFORM', 'Set platform. Example: -p "gcp"') do |p|
|
78
78
|
options[:platform] = p
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
opts.on('-c', '--config-file FILE', 'Set config file. Example: -c "/tmp/config.yaml"') do |c|
|
82
82
|
options[:config_file] = c
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
opts.on('-I', '--CI', 'Run in CI mode (modifies logging for Github Actions output)') do
|
86
86
|
options[:ci_mode] = true
|
87
87
|
options[:log_format] = 'github_action'
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
opts.on('-E', '--no-destroy-nodes', 'Do not destroy nodes') do
|
91
91
|
options[:no_destroy_nodes] = true
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
opts.on('-q', '--quiet', 'Do not log to stdout') do
|
95
95
|
options[:quiet] = true
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
opts.on('-v', '--verbose', 'Enables verbose logging mode') do
|
99
99
|
options[:verbose] = true
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
opts.on('-S', '--no-epehemeral-ssh-key', 'Do not generate an ephemeral SSH key for test suites') do
|
103
103
|
options[:no_ephemeral_ssh_key] = true
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
opts.on('-V', '--version', 'Show the cem_acpt version') do
|
107
107
|
cmd = :version
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
opts.on('-Y', '--print-yaml-config', 'Loads and prints the config as YAML. Other specified options will be added to the config.') do
|
111
111
|
cmd = :print_yaml_config
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
opts.on('-X', '--explain-config', 'Loads and prints the config explanation. Other specified options will be added to the config.') do
|
115
115
|
cmd = :print_explain_config
|
116
116
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
|
118
|
+
opts.on('--trace', 'Enables trace output') do
|
119
|
+
options[:trace] = true
|
120
|
+
end
|
121
|
+
|
122
|
+
opts.on(
|
123
|
+
'--trace-events [EVENTS]',
|
124
|
+
[
|
125
|
+
'Comma-separated list of trace events to enable. Example: --trace-events "line,call,b_call,thread_begin,thread_end"',
|
126
|
+
'See here for list of events: https://ruby-doc.org/core-2.5.0/TracePoint.html#class-TracePoint-label-Events.',
|
127
|
+
'Default: line,call,b_call,thread_begin,thread_end',
|
128
|
+
].join(' '),
|
129
|
+
) do |events|
|
130
|
+
options[:trace_events] = events.split(',')
|
131
|
+
end
|
132
|
+
|
133
|
+
opts.on('--puppet-no-debug', 'Disables Puppet debug logging') do
|
134
|
+
options[:puppet] ||= {}
|
135
|
+
options[:puppet][:no_debug] = true
|
136
|
+
end
|
137
|
+
|
138
|
+
opts.on('--puppet-no-verbose', 'Disables Puppet verbose logging') do
|
139
|
+
options[:puppet] ||= {}
|
140
|
+
options[:puppet][:no_verbose] = true
|
141
|
+
end
|
122
142
|
end
|
123
143
|
parser.parse!
|
124
144
|
[cmd, options]
|
data/lib/cem_acpt/config/base.rb
CHANGED
@@ -33,6 +33,7 @@ module CemAcpt
|
|
33
33
|
no_ephemeral_ssh_key
|
34
34
|
platform
|
35
35
|
provisioner
|
36
|
+
puppet
|
36
37
|
quiet
|
37
38
|
terraform
|
38
39
|
user_config
|
@@ -85,6 +86,7 @@ module CemAcpt
|
|
85
86
|
add_static_options!(@config)
|
86
87
|
@config.format! # Symbolize keys of all hashes
|
87
88
|
validate_config!
|
89
|
+
@dot_key_cache = {}
|
88
90
|
# Freeze the config so it can't be modified
|
89
91
|
# This helps with thread safety and deterministic behavior
|
90
92
|
@config.freeze
|
@@ -115,14 +117,14 @@ module CemAcpt
|
|
115
117
|
if key.is_a?(Symbol)
|
116
118
|
@config[key].dup
|
117
119
|
elsif key.is_a?(String)
|
118
|
-
|
120
|
+
get(key)
|
119
121
|
else
|
120
122
|
raise ArgumentError, "Invalid key type '#{key.class}'"
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
124
126
|
def get(dot_key)
|
125
|
-
@config.dget(dot_key).dup
|
127
|
+
@dot_key_cache[dot_key] ||= @config.dget(dot_key).dup
|
126
128
|
end
|
127
129
|
alias dget get
|
128
130
|
|
data/lib/cem_acpt/goss/api.rb
CHANGED
@@ -5,12 +5,15 @@ require 'async/barrier'
|
|
5
5
|
require 'async/http/internet'
|
6
6
|
require 'json'
|
7
7
|
require_relative 'api/action_response'
|
8
|
+
require_relative '../logging'
|
8
9
|
|
9
10
|
module CemAcpt
|
10
11
|
module Goss
|
11
12
|
# Holds methods for interacting with the Goss API running on a test node.
|
12
13
|
module Api
|
13
14
|
class << self
|
15
|
+
include CemAcpt::Logging
|
16
|
+
|
14
17
|
# The actions that can be run against the Goss API. The key is the action
|
15
18
|
# name and the value is the port/endpoint of the action.
|
16
19
|
ACTIONS = {
|
@@ -40,16 +43,17 @@ module CemAcpt
|
|
40
43
|
raise ArgumentError, 'results must be a Queue-like object implementing #<<' unless results.respond_to?(:<<)
|
41
44
|
raise ArgumentError, 'only must be an Array' unless except.is_a?(Array)
|
42
45
|
raise ArgumentError, 'except must be an Array' unless except.is_a?(Array)
|
46
|
+
logger.info('CemAcpt::Goss::Api') { "Running test actions against #{hosts.size} host(s)..." }
|
43
47
|
only.map!(&:to_sym)
|
44
48
|
except.map!(&:to_sym)
|
45
49
|
only_specified = !only.empty?
|
46
50
|
except_specified = !except.empty?
|
47
|
-
Async do
|
51
|
+
task = Async do
|
48
52
|
internet = Async::HTTP::Internet.new
|
49
53
|
barrier = Async::Barrier.new
|
50
54
|
barrier.async do
|
51
55
|
hosts.each do |host|
|
52
|
-
ACTIONS.
|
56
|
+
ACTIONS.each_key do |action|
|
53
57
|
next if only_specified && !only.include?(action)
|
54
58
|
next if except_specified && except.include?(action)
|
55
59
|
|
@@ -62,6 +66,8 @@ module CemAcpt
|
|
62
66
|
internet&.close
|
63
67
|
results.close if results.respond_to?(:close)
|
64
68
|
end
|
69
|
+
task.wait
|
70
|
+
logger.info('CemAcpt::Goss::Api') { 'Finished running test actions, returning results...' }
|
65
71
|
results
|
66
72
|
end
|
67
73
|
|