cem_acpt 0.2.7-universal-java-17 → 0.2.10-universal-java-17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -3
- data/Gemfile.lock +8 -8
- data/cem_acpt.gemspec +4 -4
- data/lib/cem_acpt/context.rb +7 -7
- data/lib/cem_acpt/logging/formatter.rb +96 -0
- data/lib/cem_acpt/logging.rb +2 -35
- data/lib/cem_acpt/rspec_utils.rb +92 -84
- data/lib/cem_acpt/test_runner/runner.rb +20 -18
- data/lib/cem_acpt/utils.rb +70 -10
- data/lib/cem_acpt/version.rb +1 -1
- metadata +35 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d59f3f4432694cd766fc5ca304ade0cad8cb681849181256d8c1ced3ba68438
|
4
|
+
data.tar.gz: eff162b600769222a8d0670e2a528cc389eae0407e35a1d6671c1518248c0480
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8124eec84379d5737fc4e04327ded0de1da8cb43c724a51cfd892c150823b58b14f9f6f99ec24adff5a7bc69302595e79de34501326c1c6e85fe1b0fa3c99cc
|
7
|
+
data.tar.gz: c6ea839545a9c00779aec17f331a9769a743baf7e05654f25d9efaa0e7edd8490dc528342ba75cdef171dc79328ad0431b204310c53d736f0b8bd2faf71ac6b4
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cem_acpt (0.2.
|
5
|
-
concurrent-ruby (
|
6
|
-
deep_merge (
|
4
|
+
cem_acpt (0.2.10-universal-java-17)
|
5
|
+
concurrent-ruby (>= 1.1, < 2.0)
|
6
|
+
deep_merge (>= 1.2, < 2.0)
|
7
7
|
ed25519 (>= 1.2, < 2.0)
|
8
|
-
net-ssh (
|
9
|
-
puppet-modulebuilder (
|
8
|
+
net-ssh (>= 7.0, < 8.0)
|
9
|
+
puppet-modulebuilder (>= 0.0.1)
|
10
10
|
serverspec-cem-acpt
|
11
11
|
|
12
12
|
GEM
|
@@ -31,7 +31,7 @@ GEM
|
|
31
31
|
minitar (~> 0.9)
|
32
32
|
pathspec (>= 0.2.1, < 2.0.0)
|
33
33
|
rainbow (3.1.1)
|
34
|
-
rake (
|
34
|
+
rake (13.0.6)
|
35
35
|
regexp_parser (2.5.0)
|
36
36
|
rexml (3.2.5)
|
37
37
|
rspec (3.11.0)
|
@@ -80,8 +80,8 @@ PLATFORMS
|
|
80
80
|
|
81
81
|
DEPENDENCIES
|
82
82
|
cem_acpt!
|
83
|
-
rake (
|
84
|
-
rspec (
|
83
|
+
rake (>= 12.0)
|
84
|
+
rspec (>= 3.0)
|
85
85
|
rubocop
|
86
86
|
|
87
87
|
BUNDLED WITH
|
data/cem_acpt.gemspec
CHANGED
@@ -27,11 +27,11 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
spec.platform = Gem::Platform.local
|
30
|
-
spec.add_runtime_dependency 'concurrent-ruby', '
|
31
|
-
spec.add_runtime_dependency 'deep_merge', '
|
30
|
+
spec.add_runtime_dependency 'concurrent-ruby', '>= 1.1', '< 2.0'
|
31
|
+
spec.add_runtime_dependency 'deep_merge', '>= 1.2', '< 2.0'
|
32
32
|
spec.add_runtime_dependency 'ed25519', '>= 1.2', '< 2.0'
|
33
|
-
spec.add_runtime_dependency 'net-ssh', '
|
34
|
-
spec.add_runtime_dependency 'puppet-modulebuilder', '
|
33
|
+
spec.add_runtime_dependency 'net-ssh', '>= 7.0', '< 8.0'
|
34
|
+
spec.add_runtime_dependency 'puppet-modulebuilder', '>= 0.0.1'
|
35
35
|
spec.add_runtime_dependency 'serverspec-cem-acpt'
|
36
36
|
spec.add_development_dependency 'rubocop'
|
37
37
|
end
|
data/lib/cem_acpt/context.rb
CHANGED
@@ -36,10 +36,8 @@ module CemAcpt
|
|
36
36
|
# Creates a SSH key and a SSH known hosts file for the acceptance test suite
|
37
37
|
def new_test_ssh_key
|
38
38
|
log('Creating ephemeral SSH key and known hosts file for acceptance test suites...')
|
39
|
-
@ssh_priv_key, @ssh_pub_key = CemAcpt::Utils::SSH.
|
40
|
-
|
41
|
-
CemAcpt::Utils::SSH.set_ssh_file_permissions(@ssh_priv_key, @ssh_pub_key, @ssh_known_hosts)
|
42
|
-
log('Successfully created SSH files...')
|
39
|
+
@ssh_priv_key, @ssh_pub_key, @ssh_known_hosts = CemAcpt::Utils::SSH::Ephemeral.create
|
40
|
+
log('Successfully created SSH files.')
|
43
41
|
log("SSH private key: #{@ssh_priv_key}", :debug)
|
44
42
|
log("SSH public key: #{@ssh_pub_key}", :debug)
|
45
43
|
log("SSH known hosts: #{@ssh_known_hosts}", :debug)
|
@@ -48,7 +46,9 @@ module CemAcpt
|
|
48
46
|
# Deletes acceptance test suite SSH files
|
49
47
|
def clean_test_ssh_key
|
50
48
|
log('Deleting ephemeral ssh keys and acpt_known_hosts if they exist...')
|
51
|
-
|
49
|
+
cleaned = CemAcpt::Utils::SSH::Ephemeral.clean
|
50
|
+
log('Successfully cleaned ephemeral ssh files.')
|
51
|
+
log("Deleted: #{cleaned}", :debug)
|
52
52
|
end
|
53
53
|
|
54
54
|
# Prints a period to the terminal every 5 seconds in a single line to keep the terminal
|
@@ -62,8 +62,8 @@ module CemAcpt
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def clean_up_test_suite(opts)
|
65
|
-
@ctx
|
66
|
-
@ctx
|
65
|
+
@ctx&.node_inventory&.clear!
|
66
|
+
@ctx&.node_inventory&.clean_local_files
|
67
67
|
clean_test_ssh_key unless opts[:no_ephemeral_ssh_key]
|
68
68
|
@run_handler&.destroy_test_nodes
|
69
69
|
@keep_terminal_alive&.kill
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CemAcpt
|
4
|
+
module Logging
|
5
|
+
module Formatter
|
6
|
+
class << self
|
7
|
+
def for(log_format)
|
8
|
+
all.find { |f| f.log_format == log_format.downcase.to_sym }.get
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def all
|
14
|
+
@all ||= [FileFormatter.new, JSONFormatter.new, TextFormatter.new, GithubActionFormatter.new]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class FileFormatter
|
19
|
+
attr_reader :log_format
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@log_format = :file
|
23
|
+
end
|
24
|
+
|
25
|
+
def get
|
26
|
+
proc do |severity, datetime, progname, msg|
|
27
|
+
format(severity, datetime, progname, msg)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def format(severity, datetime, _progname, msg)
|
34
|
+
"[#{datetime}] #{severity}: #{msg}\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class JSONFormatter < FileFormatter
|
39
|
+
def initialize
|
40
|
+
super
|
41
|
+
@log_format = :json
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def format(severity, datetime, progname, msg)
|
47
|
+
require 'json'
|
48
|
+
{
|
49
|
+
timestamp: datetime,
|
50
|
+
progname: progname,
|
51
|
+
severity: severity,
|
52
|
+
message: msg,
|
53
|
+
}.to_json + "\n"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class TextFormatter < FileFormatter
|
58
|
+
def initialize
|
59
|
+
super
|
60
|
+
@log_format = :text
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def format(severity, _datetime, _progname, msg)
|
66
|
+
"#{severity} - #{msg}\n"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class GithubActionFormatter < FileFormatter
|
71
|
+
SEV_MAP = {
|
72
|
+
'DEBUG' => '::debug',
|
73
|
+
'INFO' => '::notice',
|
74
|
+
'WARN' => '::warning',
|
75
|
+
'ERROR' => '::error',
|
76
|
+
'FATAL' => '::error',
|
77
|
+
}.freeze
|
78
|
+
|
79
|
+
def initialize
|
80
|
+
super
|
81
|
+
@log_format = :github_action
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def format(severity, _datetime, _progname, msg)
|
87
|
+
if severity == 'DEBUG'
|
88
|
+
"#{SEV_MAP[severity]}::{#{msg}}\n"
|
89
|
+
else
|
90
|
+
"#{SEV_MAP[severity]} #{msg}\n"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/cem_acpt/logging.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'logger'
|
4
|
+
require 'cem_acpt/logging/formatter'
|
4
5
|
|
5
6
|
module CemAcpt
|
6
7
|
# Logging for CemAcpt
|
@@ -92,41 +93,7 @@ module CemAcpt
|
|
92
93
|
# @param f [Symbol] the log format style to set
|
93
94
|
# @return [Proc] the proc to be passed to Logger#formatter=
|
94
95
|
def new_log_formatter(f)
|
95
|
-
|
96
|
-
when :json
|
97
|
-
require 'json'
|
98
|
-
@current_log_format = :json
|
99
|
-
proc do |severity, datetime, progname, msg|
|
100
|
-
{
|
101
|
-
timestamp: datetime,
|
102
|
-
progname: progname,
|
103
|
-
severity: severity,
|
104
|
-
message: msg,
|
105
|
-
}.to_json + "\n"
|
106
|
-
end
|
107
|
-
when :text
|
108
|
-
@current_log_format = :text
|
109
|
-
proc do |severity, _datetime, _progname, msg|
|
110
|
-
"#{severity} - #{msg}\n"
|
111
|
-
end
|
112
|
-
when :github_action
|
113
|
-
@current_log_format = :github_action
|
114
|
-
sev_map = {
|
115
|
-
'DEBUG' => '::debug::',
|
116
|
-
'INFO' => '::notice::',
|
117
|
-
'WARN' => '::warning::',
|
118
|
-
'ERROR' => '::error::',
|
119
|
-
'FATAL' => '::error::',
|
120
|
-
}
|
121
|
-
proc do |severity, _datetime, _progname, msg|
|
122
|
-
"#{sev_map[severity]}{#{msg}}\n"
|
123
|
-
end
|
124
|
-
else
|
125
|
-
@current_log_format = :file
|
126
|
-
proc do |severity, datetime, _progname, msg|
|
127
|
-
"[#{datetime}] #{severity}: #{msg}\n"
|
128
|
-
end
|
129
|
-
end
|
96
|
+
CemAcpt::Logging::Formatter.for(f)
|
130
97
|
end
|
131
98
|
|
132
99
|
# Returns the current log config if set, or the default if not.
|
data/lib/cem_acpt/rspec_utils.rb
CHANGED
@@ -12,13 +12,17 @@ module CemAcpt
|
|
12
12
|
class BundlerNotFoundError < StandardError; end
|
13
13
|
class RSpecNotFoundError < StandardError; end
|
14
14
|
|
15
|
-
# Holds
|
16
|
-
class
|
17
|
-
|
18
|
-
attr_reader :debug, :format, :test_path, :use_bundler, :pty_pid
|
15
|
+
# Holds RSpec options used by Command
|
16
|
+
class Options
|
17
|
+
OPTIONS = %i[test_path bundle rspec use_bundler bundle_install format debug quiet env].freeze
|
19
18
|
|
19
|
+
attr_accessor(*OPTIONS)
|
20
|
+
|
21
|
+
# @param config [CemAcpt::Config] A config object
|
20
22
|
# @param opts [Hash] options hash for the RSpec command
|
21
23
|
# @option opts [String] :test_path The path (or glob path) to the test file(s) to run. If blank, runs all.
|
24
|
+
# @option opts [String] :bundle The path to the `bundle` binary.
|
25
|
+
# @option opts [String] :rspec The path to the `rspec` binary.
|
22
26
|
# @option opts [Hash] :format Format options for rspec where the key is the format (documentation, json, etc)
|
23
27
|
# and the value is the out-file path. If you do not want to save the results of a format to a file, the
|
24
28
|
# value should be `nil`.
|
@@ -30,56 +34,97 @@ module CemAcpt
|
|
30
34
|
# Default is `true`.
|
31
35
|
# @option opts [Boolean] :bundle_install Whether or not to run `bundle install` before the RSpec command
|
32
36
|
# if `use_bundler` is `true`.
|
33
|
-
# @option opts [Boolean] :use_shell Whether or not to add `$SHELL` as a prefix to the command
|
34
37
|
# @option opts [Hash] :env Environment variables to prepend to the command
|
35
|
-
def initialize(opts
|
36
|
-
@
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
def initialize(config, **opts)
|
39
|
+
@config = config
|
40
|
+
@opts = opts
|
41
|
+
define_option_instance_vars
|
42
|
+
end
|
43
|
+
|
44
|
+
# Finds and sets the paths to the `bundle` and `rspec` binaries. The paths can
|
45
|
+
# be either passed in as options in the `opts` Hash or interrogated from the
|
46
|
+
# system.
|
47
|
+
# @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
|
48
|
+
# `bundle` binary is not found.
|
49
|
+
# @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
|
50
|
+
def resolve_bin_paths
|
51
|
+
%i[bundle rspec].each do |bin|
|
52
|
+
bin_path = instance_variable_get("@#{bin}") || `#{ENV['SHELL']} -c 'command -v #{bin}'`.strip
|
53
|
+
bin_not_found(bin, bin_path) unless bin_path && File.exist?(bin_path)
|
54
|
+
instance_variable_set("@#{bin}", bin_path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Detects if the current Ruby context is JRuby
|
59
|
+
def jruby?
|
60
|
+
Object.const_defined?('JRUBY_VERSION')
|
45
61
|
end
|
46
62
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
63
|
+
private
|
64
|
+
|
65
|
+
def defaults
|
66
|
+
@defaults ||= { use_bundler: false,
|
67
|
+
bundle_install: false,
|
68
|
+
format: { documentation: nil },
|
69
|
+
debug: false,
|
70
|
+
quiet: false,
|
71
|
+
env: {} }
|
72
|
+
end
|
73
|
+
|
74
|
+
def define_option_instance_vars
|
75
|
+
OPTIONS.each do |o|
|
76
|
+
val = @config.get("rspec.#{o}") || @opts[o] || defaults[o] || nil
|
77
|
+
instance_variable_set("@#{o}", val)
|
53
78
|
end
|
54
79
|
end
|
55
80
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
81
|
+
# Handles binary paths which are not found
|
82
|
+
# @param bin [Symbol] The binary that was not found, either :bundle or :rspec.
|
83
|
+
# @param bin_path [String] The path to the binary that was checked.
|
84
|
+
# @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
|
85
|
+
# `bundle` binary is not found.
|
86
|
+
# @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
|
87
|
+
# @raise [RuntimeError] if `bin` is not :bundle or :rspec.
|
88
|
+
def bin_not_found(bin, bin_path)
|
89
|
+
msg_base = "#{bin} not found."
|
90
|
+
msg = bin_path.nil? ? "#{msg_base} Path is nil." : "#{msg_base} Path: #{bin_path}"
|
91
|
+
case bin
|
92
|
+
when :bundle
|
93
|
+
raise BundlerNotFoundError, msg if opts.use_bundler
|
94
|
+
when :rspec
|
95
|
+
raise RSpecNotFoundError, msg
|
96
|
+
else
|
97
|
+
raise "bin #{bin} not recognized!"
|
98
|
+
end
|
59
99
|
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Holds and formats a RSpec command
|
103
|
+
class Command
|
104
|
+
include CemAcpt::LoggingAsync
|
105
|
+
attr_reader :opts, :pty_pid
|
106
|
+
|
107
|
+
def initialize(opts = Options.new)
|
108
|
+
raise 'opts must be instance of CemAcpt::RSpecUtils::Options' unless opts.is_a?(CemAcpt::RSpecUtils::Options)
|
60
109
|
|
61
|
-
|
62
|
-
@
|
110
|
+
@opts = opts
|
111
|
+
@opts.resolve_bin_paths
|
112
|
+
@opts.env = @opts.env.merge({ 'RSPEC_DEBUG' => 'true' }) if @opts.debug
|
113
|
+
@pty_pid = nil
|
63
114
|
end
|
64
115
|
|
65
116
|
# Adds a new format to the RSpec command
|
66
117
|
# @param fmt [String] The name of the format (i.e. "documentation", "json", etc.)
|
67
118
|
# @param out [String] If specified, saves the specified format to a file at this path
|
68
119
|
def with_format(fmt, out: nil)
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
# Environment variables that will be used for the RSpec command
|
73
|
-
# @return [Hash] A Hash of environment variables with each key pair being: <var name> => <var value>
|
74
|
-
def env
|
75
|
-
@debug ? @env.merge({ 'RSPEC_DEBUG' => 'true' }) : @env
|
120
|
+
opts.format[fmt.to_sym] = out
|
76
121
|
end
|
77
122
|
|
78
123
|
# Returns an array representation of the RSpec command
|
79
124
|
def to_a
|
80
125
|
cmd = cmd_base.dup
|
81
|
-
cmd << test_path if test_path
|
82
|
-
format.each do |fmt, out|
|
126
|
+
cmd << opts.test_path if opts.test_path
|
127
|
+
opts.format.each do |fmt, out|
|
83
128
|
cmd += ['--format', fmt.to_s.shellescape]
|
84
129
|
cmd += ['--out', out.to_s.shellescape] if out
|
85
130
|
end
|
@@ -112,12 +157,12 @@ module CemAcpt
|
|
112
157
|
# @return [Integer] The exit code of the RSpec command
|
113
158
|
def execute_pty(log_prefix: 'RSPEC')
|
114
159
|
async_debug("Executing RSpec command '#{self}' in PTY...", log_prefix)
|
115
|
-
PTY.spawn(env, ENV['SHELL']) do |r, w, pid|
|
160
|
+
PTY.spawn(opts.env, ENV['SHELL']) do |r, w, pid|
|
116
161
|
@pty_pid = pid
|
117
162
|
async_debug("Spawned RSpec PTY with PID #{@pty_pid}", log_prefix)
|
118
163
|
export_envs(w)
|
119
164
|
w.puts "#{self}; exit $?"
|
120
|
-
|
165
|
+
handle_io(r, log_prefix: log_prefix)
|
121
166
|
end
|
122
167
|
$CHILD_STATUS
|
123
168
|
end
|
@@ -130,9 +175,9 @@ module CemAcpt
|
|
130
175
|
def execute_no_pty(log_prefix: 'RSPEC')
|
131
176
|
async_info("Executing RSpec command '#{self}' with Open3.popen2e()...", log_prefix)
|
132
177
|
exit_status = nil
|
133
|
-
Open3.popen2e(env, to_s) do |stdin, std_out_err, wait_thr|
|
178
|
+
Open3.popen2e(opts.env, to_s) do |stdin, std_out_err, wait_thr|
|
134
179
|
stdin.close
|
135
|
-
|
180
|
+
handle_io(std_out_err, log_prefix: log_prefix)
|
136
181
|
exit_status = wait_thr.value
|
137
182
|
end
|
138
183
|
exit_status
|
@@ -147,26 +192,21 @@ module CemAcpt
|
|
147
192
|
|
148
193
|
private
|
149
194
|
|
150
|
-
# Detects if the current Ruby context is JRuby
|
151
|
-
def jruby?
|
152
|
-
File.basename(RbConfig.ruby) == 'jruby'
|
153
|
-
end
|
154
|
-
|
155
195
|
# The base RSpec command
|
156
196
|
def cmd_base
|
157
|
-
use_bundler ? cmd_base_bundler : cmd_base_rspec
|
197
|
+
opts.use_bundler ? cmd_base_bundler : cmd_base_rspec
|
158
198
|
end
|
159
199
|
|
160
200
|
# The base RSpec command if `:use_bundler` is `true`.
|
161
201
|
def cmd_base_bundler
|
162
|
-
base = [
|
163
|
-
base.unshift("#{
|
202
|
+
base = [opts.bundle, 'exec', 'rspec']
|
203
|
+
base.unshift("#{opts.bundle} install;") if opts.bundle_install
|
164
204
|
base
|
165
205
|
end
|
166
206
|
|
167
207
|
# The base RSpec command if `:use_bundler` is `false`
|
168
208
|
def cmd_base_rspec
|
169
|
-
[
|
209
|
+
[opts.rspec]
|
170
210
|
end
|
171
211
|
|
172
212
|
# Puts export statements for each key-value pair in `env` to the given writer.
|
@@ -174,46 +214,14 @@ module CemAcpt
|
|
174
214
|
# pass the statements to a shell.
|
175
215
|
# @param writer [IO] An IO object that supprts `puts` and can send statements to a shell
|
176
216
|
def export_envs(writer)
|
177
|
-
env.each do |key, val|
|
217
|
+
@opts.env.each do |key, val|
|
178
218
|
writer.puts "export #{key}=#{val}"
|
179
219
|
end
|
180
220
|
end
|
181
221
|
|
182
|
-
#
|
183
|
-
|
184
|
-
|
185
|
-
# @param opts [Hash] The options hash
|
186
|
-
# @option opts [String] :bundle An absolute path on the system to the `bundle` binary.
|
187
|
-
# @option opts [String] :rspec An absolute path on the system to the `rspec` binary.
|
188
|
-
# @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
|
189
|
-
# `bundle` binary is not found.
|
190
|
-
# @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
|
191
|
-
def validate_and_set_bin_paths(opts = {})
|
192
|
-
%i[bundle rspec].each do |bin|
|
193
|
-
bin_path = opts[bin] || `command -v #{bin}`.strip
|
194
|
-
bin_not_found(bin, bin_path) unless bin_path && File.exist?(bin_path)
|
195
|
-
instance_variable_set("@#{bin}", bin_path)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
# Handles binary paths which are not found
|
200
|
-
# @param bin [Symbol] The binary that was not found, either :bundle or :rspec.
|
201
|
-
# @param bin_path [String] The path to the binary that was checked.
|
202
|
-
# @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
|
203
|
-
# `bundle` binary is not found.
|
204
|
-
# @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
|
205
|
-
# @raise [RuntimeError] if `bin` is not :bundle or :rspec.
|
206
|
-
def bin_not_found(bin, bin_path)
|
207
|
-
msg_base = "#{bin} not found."
|
208
|
-
msg = bin_path.nil? ? "#{msg_base} Path is nil." : "#{msg_base} Path: #{bin_path}"
|
209
|
-
case bin
|
210
|
-
when :bundle
|
211
|
-
raise BundlerNotFoundError, msg if @use_bundler
|
212
|
-
when :rspec
|
213
|
-
raise RSpecNotFoundError, msg
|
214
|
-
else
|
215
|
-
raise "bin #{bin} not recognized!"
|
216
|
-
end
|
222
|
+
# Handles IO output
|
223
|
+
def handle_io(io_stream, **kwargs)
|
224
|
+
opts.quiet ? wait_io(io_stream) : read_io(io_stream, log_prefix: kwargs[:log_prefix])
|
217
225
|
end
|
218
226
|
|
219
227
|
# Blocking wait on an IO stream. Wait stops once the IO stream has reached
|
@@ -9,6 +9,7 @@ require_relative 'runner_result'
|
|
9
9
|
module CemAcpt
|
10
10
|
module TestRunner
|
11
11
|
class RunnerError < StandardError; end
|
12
|
+
|
12
13
|
# Error used to wrap fatal errors raised in Runner steps
|
13
14
|
class RunnerStepError < StandardError
|
14
15
|
attr_reader :step
|
@@ -19,6 +20,7 @@ module CemAcpt
|
|
19
20
|
set_backtrace err.backtrace if err.respond_to?(:backtrace)
|
20
21
|
end
|
21
22
|
end
|
23
|
+
|
22
24
|
class RunnerProvisionError < RunnerStepError; end
|
23
25
|
|
24
26
|
# Runner is a class that runs a single acceptance test suite on a single node.
|
@@ -143,12 +145,12 @@ module CemAcpt
|
|
143
145
|
async_info("Running test #{@node.test_data[:test_name]} on node #{@node.node_name}...", log_prefix('RSPEC'))
|
144
146
|
@node.run_tests do |cmd_env|
|
145
147
|
cmd_opts = rspec_opts
|
146
|
-
cmd_opts
|
148
|
+
cmd_opts.env = cmd_opts.env.merge(cmd_env) if cmd_env
|
147
149
|
# Documentation format gets logged in real time, JSON file is read after the fact
|
148
150
|
begin
|
149
151
|
@rspec_cmd = CemAcpt::RSpecUtils::Command.new(cmd_opts)
|
150
|
-
@rspec_cmd.execute(log_prefix: log_prefix('RSPEC'))
|
151
|
-
@run_result.from_json_file(cmd_opts
|
152
|
+
@rspec_cmd.execute(pty: false, log_prefix: log_prefix('RSPEC'))
|
153
|
+
@run_result.from_json_file(cmd_opts.format[:json])
|
152
154
|
rescue Errno::EIO => e
|
153
155
|
async_error("failed to run rspec: #{@node.test_data[:test_name]}: #{$ERROR_INFO}", log_prefix('RSPEC'))
|
154
156
|
@run_result.from_error(e)
|
@@ -189,21 +191,21 @@ module CemAcpt
|
|
189
191
|
|
190
192
|
# Options used with RSpec
|
191
193
|
def rspec_opts
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
194
|
+
opts_test_path = @node.test_data[:test_file]
|
195
|
+
opts_env = { 'TARGET_HOST' => @node.node_name }
|
196
|
+
opts_debug = (@debug_mode && @context.config.get('verbose'))
|
197
|
+
opts_quiet = @context.config.get('quiet')
|
198
|
+
opts_format = if @context.config.get('verbose')
|
199
|
+
{ json: "results_#{@node.test_data[:test_name]}.json", documentation: nil }
|
200
|
+
else
|
201
|
+
{ json: "results_#{@node.test_data[:test_name]}.json" }
|
202
|
+
end
|
203
|
+
CemAcpt::RSpecUtils::Options.new(@context.config,
|
204
|
+
test_path: opts_test_path,
|
205
|
+
env: opts_env,
|
206
|
+
debug: opts_debug,
|
207
|
+
quiet: opts_quiet,
|
208
|
+
format: opts_format)
|
207
209
|
end
|
208
210
|
end
|
209
211
|
end
|
data/lib/cem_acpt/utils.rb
CHANGED
@@ -81,6 +81,40 @@ module CemAcpt
|
|
81
81
|
|
82
82
|
# SSH-related utilities
|
83
83
|
module SSH
|
84
|
+
module Ephemeral
|
85
|
+
PRIV_KEY = 'acpt_test_key'
|
86
|
+
CREATE_OPTS = {
|
87
|
+
type: 'rsa',
|
88
|
+
bits: '4096',
|
89
|
+
comment: 'Ephemeral for cem_acpt',
|
90
|
+
password: '',
|
91
|
+
known_hosts: 'acpt_known_hosts',
|
92
|
+
overwrite_known_hosts: true,
|
93
|
+
}.freeze
|
94
|
+
|
95
|
+
class << self
|
96
|
+
attr_accessor :ephemeral_keydir
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.create(keydir: CemAcpt::Utils::SSH.default_keydir)
|
100
|
+
self.ephemeral_keydir = keydir
|
101
|
+
@priv_key, @pub_key, @known_hosts = CemAcpt::Utils::SSH.create(PRIV_KEY, keydir: ephemeral_keydir, **CREATE_OPTS)
|
102
|
+
[@priv_key, @pub_key, @known_hosts]
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.clean
|
106
|
+
[@priv_key, @pub_key, @known_hosts].each_with_object([]) do |f, arr|
|
107
|
+
next unless f
|
108
|
+
|
109
|
+
path = CemAcpt::Utils::SSH.file_path(f, keydir: ephemeral_keydir)
|
110
|
+
if ::File.exist?(path)
|
111
|
+
::File.delete(path)
|
112
|
+
arr << path
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
84
118
|
def self.ssh_keygen
|
85
119
|
bin_path = `#{ENV['SHELL']} -c 'command -v ssh-keygen'`.chomp
|
86
120
|
raise 'Cannot find ssh-keygen! Install it and verify PATH' unless bin_path
|
@@ -97,26 +131,52 @@ module CemAcpt
|
|
97
131
|
ssh_dir
|
98
132
|
end
|
99
133
|
|
100
|
-
def self.
|
101
|
-
|
134
|
+
def self.file_path(file_name, keydir: default_keydir)
|
135
|
+
::File.join(keydir, file_name)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Takes a file name (not path) and optional SSH key directory and returns the paths
|
139
|
+
# to the private key and public key based on the file name given.
|
140
|
+
# @param file_name [String] The base name for the keys
|
141
|
+
# @param keydir [String] An optional SSH key directory
|
142
|
+
def self.key_paths(file_name, keydir: default_keydir)
|
143
|
+
[file_path(file_name, keydir: keydir), file_path("#{file_name}.pub", keydir: keydir)]
|
144
|
+
end
|
102
145
|
|
103
|
-
|
104
|
-
|
146
|
+
def self.create(key_name, type: 'rsa', bits: '4096', comment: nil, password: '', known_hosts: nil, overwrite_known_hosts: true, keydir: default_keydir)
|
147
|
+
raise ArgumentError, "Key directory #{keydir} does not exist" unless ::File.directory?(keydir)
|
148
|
+
|
149
|
+
keys = key_paths(key_name, keydir: keydir)
|
150
|
+
# If we don't delete an existing key file, generation will fail
|
151
|
+
keys.each { |f| ::File.delete(f) if ::File.exist?(f) }
|
152
|
+
keygen_cmd = [ssh_keygen, "-t #{type}", "-b #{bits}", "-f #{keys[0]}", "-N '#{password}'"]
|
105
153
|
keygen_cmd << "-C \"#{comment}\"" if comment
|
106
154
|
_, stderr, status = Open3.capture3(keygen_cmd.join(' '))
|
107
|
-
raise "Failed to generate ephemeral SSH key: #{stderr}" unless status.success?
|
155
|
+
raise "Failed to generate ephemeral SSH key: STDOUT: #{stdout}; STDERR: #{stderr}" unless status.success?
|
108
156
|
|
109
|
-
|
157
|
+
keys << create_known_hosts(known_hosts, overwrite: overwrite_known_hosts, keydir: keydir)
|
158
|
+
set_ssh_file_permissions(*keys)
|
159
|
+
keys
|
110
160
|
end
|
111
161
|
|
112
|
-
def self.
|
113
|
-
|
162
|
+
def self.create_known_hosts(known_hosts, overwrite: true, keydir: default_keydir)
|
163
|
+
return nil unless known_hosts
|
164
|
+
|
165
|
+
kh_file = file_path(known_hosts, keydir: keydir)
|
114
166
|
::File.open(kh_file, 'w') { |f| f.write("\n") } unless ::File.exist?(kh_file) && !overwrite
|
115
167
|
kh_file
|
116
168
|
end
|
117
169
|
|
118
|
-
def self.set_ssh_file_permissions(
|
119
|
-
CemAcpt::Utils::File.set_permissions(0o600,
|
170
|
+
def self.set_ssh_file_permissions(*files)
|
171
|
+
CemAcpt::Utils::File.set_permissions(0o600, *files.uniq.compact)
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.ephemeral_ssh_key(keydir: default_keydir)
|
175
|
+
CemAcpt::Utils::SSH::Ephemeral.create(keydir: keydir)
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.clean_ephemeral_keys
|
179
|
+
CemAcpt::Utils::SSH::Ephemeral.clean
|
120
180
|
end
|
121
181
|
end
|
122
182
|
|
data/lib/cem_acpt/version.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cem_acpt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.10
|
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: 2022-
|
11
|
+
date: 2022-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - "
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.1'
|
19
|
+
- - "<"
|
17
20
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
21
|
+
version: '2.0'
|
19
22
|
name: concurrent-ruby
|
20
23
|
prerelease: false
|
21
24
|
type: :runtime
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.1'
|
30
|
+
- - "<"
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
32
|
+
version: '2.0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
29
35
|
requirements:
|
30
|
-
- - "
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.2'
|
39
|
+
- - "<"
|
31
40
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
41
|
+
version: '2.0'
|
33
42
|
name: deep_merge
|
34
43
|
prerelease: false
|
35
44
|
type: :runtime
|
36
45
|
version_requirements: !ruby/object:Gem::Requirement
|
37
46
|
requirements:
|
38
|
-
- - "
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.2'
|
50
|
+
- - "<"
|
39
51
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
52
|
+
version: '2.0'
|
41
53
|
- !ruby/object:Gem::Dependency
|
42
54
|
requirement: !ruby/object:Gem::Requirement
|
43
55
|
requirements:
|
@@ -61,21 +73,27 @@ dependencies:
|
|
61
73
|
- !ruby/object:Gem::Dependency
|
62
74
|
requirement: !ruby/object:Gem::Requirement
|
63
75
|
requirements:
|
64
|
-
- - "
|
76
|
+
- - ">="
|
65
77
|
- !ruby/object:Gem::Version
|
66
|
-
version: 7.0
|
78
|
+
version: '7.0'
|
79
|
+
- - "<"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '8.0'
|
67
82
|
name: net-ssh
|
68
83
|
prerelease: false
|
69
84
|
type: :runtime
|
70
85
|
version_requirements: !ruby/object:Gem::Requirement
|
71
86
|
requirements:
|
72
|
-
- - "
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '7.0'
|
90
|
+
- - "<"
|
73
91
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
92
|
+
version: '8.0'
|
75
93
|
- !ruby/object:Gem::Dependency
|
76
94
|
requirement: !ruby/object:Gem::Requirement
|
77
95
|
requirements:
|
78
|
-
- - "
|
96
|
+
- - ">="
|
79
97
|
- !ruby/object:Gem::Version
|
80
98
|
version: 0.0.1
|
81
99
|
name: puppet-modulebuilder
|
@@ -83,7 +101,7 @@ dependencies:
|
|
83
101
|
type: :runtime
|
84
102
|
version_requirements: !ruby/object:Gem::Requirement
|
85
103
|
requirements:
|
86
|
-
- - "
|
104
|
+
- - ">="
|
87
105
|
- !ruby/object:Gem::Version
|
88
106
|
version: 0.0.1
|
89
107
|
- !ruby/object:Gem::Dependency
|
@@ -142,6 +160,7 @@ files:
|
|
142
160
|
- lib/cem_acpt/core_extensions.rb
|
143
161
|
- lib/cem_acpt/image_name_builder.rb
|
144
162
|
- lib/cem_acpt/logging.rb
|
163
|
+
- lib/cem_acpt/logging/formatter.rb
|
145
164
|
- lib/cem_acpt/platform.rb
|
146
165
|
- lib/cem_acpt/platform/base.rb
|
147
166
|
- lib/cem_acpt/platform/base/cmd.rb
|