cem_win_spec 0.1.6 → 0.1.8
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/Gemfile.lock +26 -15
- data/exe/cem-win-spec +1 -0
- data/lib/cem_win_spec/rake_tasks.rb +1 -1
- data/lib/cem_win_spec/test_runner.rb +20 -25
- data/lib/cem_win_spec/version.rb +1 -1
- data/lib/cem_win_spec/win_exec/cmd/base_cmd.rb +25 -7
- data/lib/cem_win_spec/win_exec/cmd/local_cmd.rb +9 -6
- data/lib/cem_win_spec/win_exec/cmd/winrm_cmd.rb +11 -3
- data/lib/cem_win_spec/win_exec/exec.rb +5 -3
- data/lib/cem_win_spec/win_exec/factory.rb +3 -3
- data/lib/cem_win_spec/win_exec/output.rb +15 -3
- data/lib/cem_win_spec.rb +115 -37
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 000454f69f3ea2722dcd11ec105a5ebe617301d076a2c1772cb530d8275e0f11
|
|
4
|
+
data.tar.gz: 1d2635cc5f330baa755482c5738901e2e79aeabd585200db5ee0ef218cd9decf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8d28e53eeb77001c89b81a9140be2783278c528fa1dc92aef59b7154cd0174fba47b534d346977135e9465115b74981d9bfdd04eb35952a612e80dea71657a4
|
|
7
|
+
data.tar.gz: 0d4b7117383ab02ee03c0d8f19f75be611a3e678dd973140844f9316d651db7bc0263ed0f4354fda64893b498a344128adb6e44dcb999030bef66445dc4cd0f9
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
cem_win_spec (0.1.
|
|
4
|
+
cem_win_spec (0.1.8)
|
|
5
5
|
parallel_tests (~> 3.4)
|
|
6
6
|
puppet_forge (~> 4.1)
|
|
7
7
|
winrm (~> 2.3)
|
|
@@ -11,31 +11,40 @@ GEM
|
|
|
11
11
|
remote: https://rubygems.org/
|
|
12
12
|
specs:
|
|
13
13
|
ast (2.4.2)
|
|
14
|
-
|
|
14
|
+
base64 (0.2.0)
|
|
15
|
+
bigdecimal (3.1.8)
|
|
16
|
+
builder (3.3.0)
|
|
15
17
|
coderay (1.1.3)
|
|
16
18
|
diff-lcs (1.5.0)
|
|
17
|
-
erubi (1.
|
|
18
|
-
faraday (2.
|
|
19
|
-
faraday-net_http (>= 2.0, < 3.
|
|
20
|
-
|
|
19
|
+
erubi (1.13.0)
|
|
20
|
+
faraday (2.12.1)
|
|
21
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
22
|
+
json
|
|
23
|
+
logger
|
|
21
24
|
faraday-follow_redirects (0.3.0)
|
|
22
25
|
faraday (>= 1, < 3)
|
|
23
|
-
faraday-net_http (3.0
|
|
24
|
-
|
|
26
|
+
faraday-net_http (3.4.0)
|
|
27
|
+
net-http (>= 0.5.0)
|
|
28
|
+
ffi (1.16.3)
|
|
25
29
|
gssapi (1.3.1)
|
|
26
30
|
ffi (>= 1.0.1)
|
|
27
31
|
gyoku (1.4.0)
|
|
28
32
|
builder (>= 2.1.2)
|
|
29
33
|
rexml (~> 3.0)
|
|
30
34
|
httpclient (2.8.3)
|
|
35
|
+
json (2.8.2)
|
|
31
36
|
little-plugger (1.1.4)
|
|
32
|
-
|
|
37
|
+
logger (1.6.5)
|
|
38
|
+
logging (2.4.0)
|
|
33
39
|
little-plugger (~> 1.1)
|
|
34
40
|
multi_json (~> 1.14)
|
|
35
41
|
method_source (1.0.0)
|
|
36
|
-
minitar (0.
|
|
42
|
+
minitar (0.12.1)
|
|
37
43
|
multi_json (1.15.0)
|
|
38
|
-
|
|
44
|
+
net-http (0.5.0)
|
|
45
|
+
uri
|
|
46
|
+
nori (2.7.1)
|
|
47
|
+
bigdecimal
|
|
39
48
|
parallel (1.22.1)
|
|
40
49
|
parallel_tests (3.13.0)
|
|
41
50
|
parallel
|
|
@@ -78,19 +87,21 @@ GEM
|
|
|
78
87
|
rubocop-ast (1.24.1)
|
|
79
88
|
parser (>= 3.1.1.0)
|
|
80
89
|
ruby-progressbar (1.11.0)
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
rubyntlm (0.6.5)
|
|
91
|
+
base64
|
|
83
92
|
rubyzip (2.3.2)
|
|
84
93
|
semantic_puppet (1.1.0)
|
|
85
94
|
unicode-display_width (2.1.0)
|
|
86
|
-
|
|
95
|
+
uri (1.0.2)
|
|
96
|
+
winrm (2.3.9)
|
|
87
97
|
builder (>= 2.1.2)
|
|
88
98
|
erubi (~> 1.8)
|
|
89
99
|
gssapi (~> 1.2)
|
|
90
100
|
gyoku (~> 1.0)
|
|
91
101
|
httpclient (~> 2.2, >= 2.2.0.2)
|
|
92
102
|
logging (>= 1.6.1, < 3.0)
|
|
93
|
-
nori (~> 2.0)
|
|
103
|
+
nori (~> 2.0, >= 2.7.1)
|
|
104
|
+
rexml (~> 3.0)
|
|
94
105
|
rubyntlm (~> 0.6.0, >= 0.6.3)
|
|
95
106
|
winrm-fs (1.3.5)
|
|
96
107
|
erubi (~> 1.8)
|
data/exe/cem-win-spec
CHANGED
|
@@ -98,7 +98,7 @@ namespace 'cem_win_spec' do
|
|
|
98
98
|
puts "Copying Hiera config to #{hiera_fix}..."
|
|
99
99
|
::FileUtils.cp(cem_win_spec_hiera_conf, hiera_fix)
|
|
100
100
|
raise 'Hiera config copy failed!' unless File.exist?(hiera_fix)
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
puts 'Spec data prepared successfully'
|
|
103
103
|
puts 'Setting up module fixture cache...'
|
|
104
104
|
cache = CemWinSpec::FixtureCache.new
|
|
@@ -21,19 +21,11 @@ module CemWinSpec
|
|
|
21
21
|
@rspec_cmds = RspecTestCmds.new
|
|
22
22
|
@iap_tunnel = IapTunnel.new
|
|
23
23
|
@win_exec_factory = CemWinSpec::WinExec::Factory.new(@iap_tunnel, @module_archive_builder, @rspec_cmds)
|
|
24
|
+
@retry = false
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
def
|
|
27
|
-
|
|
28
|
-
enable_long_paths.run
|
|
29
|
-
enable_symlinks.run
|
|
30
|
-
@working_dir = create_working_dir.run
|
|
31
|
-
upload_module.run(@working_dir)
|
|
32
|
-
setup_ruby.run(@working_dir)
|
|
33
|
-
rspec_tests_parallel.run(@working_dir)
|
|
34
|
-
ensure
|
|
35
|
-
clean_up(@working_dir)
|
|
36
|
-
@iap_tunnel.stop if @iap_tunnel.running?
|
|
27
|
+
def retry?
|
|
28
|
+
@retry
|
|
37
29
|
end
|
|
38
30
|
|
|
39
31
|
def enable_long_paths(**opts)
|
|
@@ -78,6 +70,8 @@ module CemWinSpec
|
|
|
78
70
|
@setup_ruby ||= new_command('Set up ruby', **opts) do
|
|
79
71
|
remote_run(
|
|
80
72
|
[
|
|
73
|
+
'if (Test-Path .bundle) { Remove-Item -Recurse -Force .bundle }',
|
|
74
|
+
'if (Test-Path Gemfile.lock) { Remove-Item -Force Gemfile.lock }',
|
|
81
75
|
'bundle config disable_platform_warnings true',
|
|
82
76
|
'bundle config set --local without \'local_development\'',
|
|
83
77
|
'bundle install',
|
|
@@ -104,13 +98,17 @@ module CemWinSpec
|
|
|
104
98
|
end
|
|
105
99
|
end
|
|
106
100
|
|
|
107
|
-
def clean_up
|
|
108
|
-
@clean_up ||= new_command('Cleanup') do
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
101
|
+
def clean_up(**opts)
|
|
102
|
+
@clean_up ||= new_command('Cleanup', **opts) do
|
|
103
|
+
remote_run(
|
|
104
|
+
[
|
|
105
|
+
"Get-ChildItem -Path #{remote_working_dir} -Force -Recurse | Remove-Item -Force -Recurse",
|
|
106
|
+
"Remove-Item #{remote_working_dir} -Force",
|
|
107
|
+
],
|
|
108
|
+
ruby_cmd: false,
|
|
109
|
+
add_envs: false,
|
|
110
|
+
chdir: false,
|
|
111
|
+
)
|
|
114
112
|
end
|
|
115
113
|
end
|
|
116
114
|
|
|
@@ -120,6 +118,10 @@ module CemWinSpec
|
|
|
120
118
|
end
|
|
121
119
|
end
|
|
122
120
|
|
|
121
|
+
def inspect
|
|
122
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)}>"
|
|
123
|
+
end
|
|
124
|
+
|
|
123
125
|
private
|
|
124
126
|
|
|
125
127
|
def title_sym(title)
|
|
@@ -144,12 +146,5 @@ module CemWinSpec
|
|
|
144
146
|
end
|
|
145
147
|
end
|
|
146
148
|
end
|
|
147
|
-
|
|
148
|
-
def cleanup_cmd(working_dir)
|
|
149
|
-
<<~EOS
|
|
150
|
-
Get-ChildItem #{working_dir} -Recurse | Remove-Item -Force
|
|
151
|
-
Remove-Item -Force #{working_dir}
|
|
152
|
-
EOS
|
|
153
|
-
end
|
|
154
149
|
end
|
|
155
150
|
end
|
data/lib/cem_win_spec/version.rb
CHANGED
|
@@ -12,6 +12,10 @@ module CemWinSpec
|
|
|
12
12
|
'7' => '278',
|
|
13
13
|
'8' => '322',
|
|
14
14
|
}.freeze
|
|
15
|
+
TOOL_DIR_BY_RUBY_VER = {
|
|
16
|
+
'278' => 'C:/tools/ruby/2.7.8',
|
|
17
|
+
'322' => 'C:/tools/ruby/3.2.2',
|
|
18
|
+
}.freeze
|
|
15
19
|
|
|
16
20
|
attr_accessor :working_dir, :env_vars, :puppet_version
|
|
17
21
|
|
|
@@ -45,6 +49,7 @@ module CemWinSpec
|
|
|
45
49
|
|
|
46
50
|
value['PUPPET_GEM_VERSION'] = "~> #{puppet_version}" if puppet_version
|
|
47
51
|
value['FACTER_GEM_VERSION'] = 'https://github.com/puppetlabs/facter#main' if puppet_version
|
|
52
|
+
value.delete('password') if value.key?('password')
|
|
48
53
|
@env_vars = value
|
|
49
54
|
end
|
|
50
55
|
|
|
@@ -65,27 +70,40 @@ module CemWinSpec
|
|
|
65
70
|
PUPPET_VER_TO_RUBY_VER[puppet_version.split('.')[0]]
|
|
66
71
|
end
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
# Formats the command to be run
|
|
74
|
+
# @param cmd [String, Array[String]] the command to be run
|
|
75
|
+
# @param ruby_cmd [Boolean] Whether the command is a ruby command and should be ran
|
|
76
|
+
# in a ruby context. If false, the command will not set up the Uru ruby environment.
|
|
77
|
+
# @param add_envs [Boolean] Whether to add the environment variables to the command
|
|
78
|
+
# @param chdir [Boolean] Whether to change the working directory to the working dir
|
|
79
|
+
# @return [String] the formatted command
|
|
80
|
+
def command(cmd, ruby_cmd: true, add_envs: true, chdir: true, **_kwargs)
|
|
81
|
+
cmd = cmd.join(COMMAND_SEPARATOR) if cmd.is_a?(Array)
|
|
69
82
|
cmd = [cmd]
|
|
70
|
-
cmd.unshift(change_ruby_version_cmd) if ruby_version # executes third
|
|
71
|
-
env_vars.each { |k, v| cmd.unshift(set_env_var_cmd(k, v)) } if env_vars.any? # executes second
|
|
72
|
-
cmd.unshift(change_working_dir_cmd(working_dir)) if working_dir # executes first
|
|
83
|
+
cmd.unshift(change_ruby_version_cmd) if ruby_cmd && ruby_version # executes third
|
|
84
|
+
env_vars.each { |k, v| cmd.unshift(set_env_var_cmd(k, v)) } if add_envs && env_vars.any? # executes second
|
|
85
|
+
cmd.unshift(change_working_dir_cmd(working_dir)) if chdir && working_dir # executes first
|
|
73
86
|
cmd.join(COMMAND_SEPARATOR)
|
|
74
87
|
end
|
|
75
88
|
|
|
76
89
|
private
|
|
77
90
|
|
|
78
91
|
def log_command(cmd)
|
|
79
|
-
cmd =
|
|
92
|
+
cmd.gsub!(/\$env:password = "\w+"/, '$env:password = [REDACTED]')
|
|
80
93
|
logger.debug "Executing command:\n#{cmd.split(%r{\n|\r\n|;\s*}).map { |c| " #> #{c}" }.join("\n")}"
|
|
81
94
|
end
|
|
82
95
|
|
|
96
|
+
# Commands that, when ran, will change the ruby version. This will also set the local bundle config path
|
|
83
97
|
def change_ruby_version_cmd
|
|
84
|
-
|
|
98
|
+
[
|
|
99
|
+
"uru #{ruby_version}",
|
|
100
|
+
'$env:GEM_HOME = "$(ruby -e "puts Gem.dir")"',
|
|
101
|
+
'bundle config set --local path "$env:GEM_HOME"',
|
|
102
|
+
].join(COMMAND_SEPARATOR)
|
|
85
103
|
end
|
|
86
104
|
|
|
87
105
|
def set_env_var_cmd(key, value)
|
|
88
|
-
"
|
|
106
|
+
"$env:#{key} = \"#{value}\""
|
|
89
107
|
end
|
|
90
108
|
|
|
91
109
|
def change_working_dir_cmd(dir)
|
|
@@ -35,9 +35,10 @@ module CemWinSpec
|
|
|
35
35
|
# This is useful for running commands that should not block the current process
|
|
36
36
|
# and that you don't need stdout/stderr from.
|
|
37
37
|
# @param cmd [String] The command to execute
|
|
38
|
-
def bg_run(cmd, *_args, **
|
|
38
|
+
def bg_run(cmd, *_args, **kwargs)
|
|
39
|
+
cmd = command(cmd, **kwargs)
|
|
39
40
|
log_command(cmd)
|
|
40
|
-
Process.detach(spawn(
|
|
41
|
+
Process.detach(spawn())
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
# Execute a command in a new thread. This works by creating a new thread in a thread group
|
|
@@ -48,20 +49,22 @@ module CemWinSpec
|
|
|
48
49
|
# Process::Status object.
|
|
49
50
|
# @param cmd [String] The command to execute
|
|
50
51
|
# @return [Array] An array of [:threaded, cmd]
|
|
51
|
-
def thread_run(cmd, *_args, **
|
|
52
|
+
def thread_run(cmd, *_args, **kwargs)
|
|
52
53
|
@ran_in_thread = true
|
|
53
54
|
th = Thread.new do
|
|
55
|
+
cmd = command(cmd, **kwargs)
|
|
54
56
|
log_command(cmd)
|
|
55
|
-
so, se, st = Open3.capture3(
|
|
57
|
+
so, se, st = Open3.capture3(cmd)
|
|
56
58
|
@thread_results[cmd] = [so, se, st]
|
|
57
59
|
end
|
|
58
60
|
thread_group.add th
|
|
59
61
|
:threaded
|
|
60
62
|
end
|
|
61
63
|
|
|
62
|
-
def run(cmd, *_args, **
|
|
64
|
+
def run(cmd, *_args, **kwargs)
|
|
65
|
+
cmd = command(cmd, **kwargs)
|
|
63
66
|
log_command(cmd)
|
|
64
|
-
Open3.capture3(
|
|
67
|
+
Open3.capture3(cmd)
|
|
65
68
|
end
|
|
66
69
|
|
|
67
70
|
private
|
|
@@ -21,14 +21,22 @@ module CemWinSpec
|
|
|
21
21
|
@available
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
# Run a command over WinRM
|
|
25
|
+
# @param cmd [String] The command to run
|
|
26
|
+
# @param kwargs [Hash] Additional options for the command
|
|
27
|
+
# These following options are available:
|
|
28
|
+
# - :ruby_cmd [Boolean] Whether the command is a ruby command and should be ran
|
|
29
|
+
# in a ruby context. If false, the command will not set up the Uru ruby environment.
|
|
30
|
+
# - :add_envs [Boolean] Whether to add the environment variables to the command
|
|
31
|
+
# - :chdir [Boolean] Whether to change the working directory to the working dir
|
|
32
|
+
def run(cmd, *_args, **kwargs)
|
|
33
|
+
cmd = command(cmd, **kwargs)
|
|
26
34
|
log_command(cmd)
|
|
27
35
|
shell = nil
|
|
28
36
|
output = nil
|
|
29
37
|
begin
|
|
30
38
|
shell = conn.shell(:powershell)
|
|
31
|
-
output = shell.run(
|
|
39
|
+
output = shell.run(cmd) do |stdout, stderr|
|
|
32
40
|
logger << stdout if stdout
|
|
33
41
|
logger << stderr if stderr
|
|
34
42
|
end
|
|
@@ -36,7 +36,7 @@ module CemWinSpec
|
|
|
36
36
|
|
|
37
37
|
def add_local_cmd(value)
|
|
38
38
|
raise ArgumentError, 'local_exec must implement the #run method' unless value.respond_to?(:run)
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
@local_cmd = value
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -88,7 +88,7 @@ module CemWinSpec
|
|
|
88
88
|
@ignore_exitcode = value
|
|
89
89
|
end
|
|
90
90
|
alias ignore_exitcode? ignore_exitcode
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
def success?
|
|
93
93
|
@result.success? if @result.is_a?(Output)
|
|
94
94
|
|
|
@@ -146,11 +146,13 @@ module CemWinSpec
|
|
|
146
146
|
super
|
|
147
147
|
end
|
|
148
148
|
end
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
def run(*args, **kwargs)
|
|
151
151
|
validate_instance_variables
|
|
152
152
|
logger.info "Running #{@title}"
|
|
153
153
|
result = run_with_tunnel { run_in_current_scope(*args, **kwargs) }
|
|
154
|
+
logger.debug "Command stdout: #{result.stdout}" if result.respond_to?(:stdout)
|
|
155
|
+
logger.debug "Command stderr: #{result.stderr}" if result.respond_to?(:stderr)
|
|
154
156
|
@result = Output.new(result)
|
|
155
157
|
return if @result.pending_threaded?
|
|
156
158
|
|
|
@@ -35,12 +35,12 @@ module CemWinSpec
|
|
|
35
35
|
# @return [Exec] An Exec object
|
|
36
36
|
def build(title, merge: true, user: nil, pass: nil, working_dir: nil, **opts, &block)
|
|
37
37
|
logger.debug "Building Wexec object for #{title}"
|
|
38
|
-
build_conn_opts(merge: merge, user: user, pass: pass,
|
|
38
|
+
build_conn_opts(merge: merge, user: user, pass: pass, **@init_opts.merge(opts))
|
|
39
39
|
logger.debug 'Created ConnectionOpts'
|
|
40
40
|
wexec = Exec.new
|
|
41
41
|
wexec.add_title title
|
|
42
42
|
wexec.add_local_cmd @current_local_cmd
|
|
43
|
-
wexec.add_remote_cmd get_remote_cmd(working_dir, **@
|
|
43
|
+
wexec.add_remote_cmd get_remote_cmd(working_dir, **@current_conn_opts.to_h)
|
|
44
44
|
wexec.add_iap_tunnel @iap_tunnel
|
|
45
45
|
wexec.add_ma_builder @ma_builder
|
|
46
46
|
wexec.add_rspec_test_cmds @rspec_test_cmds
|
|
@@ -68,7 +68,7 @@ module CemWinSpec
|
|
|
68
68
|
@current_conn_opts = ConnectionOpts.new(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
|
|
69
69
|
return @current_conn_opts
|
|
70
70
|
end
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
if need_new_conn_opts?(new_host: 'localhost', new_port: @iap_tunnel.port, user: user, pass: pass, **opts)
|
|
73
73
|
if merge
|
|
74
74
|
logger.debug 'Merging ConnectionOpts with new options'
|
|
@@ -53,19 +53,31 @@ module CemWinSpec
|
|
|
53
53
|
end
|
|
54
54
|
out_array.compact!
|
|
55
55
|
return if out_array.empty?
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
logger.info "#{stream_name.to_s.upcase}:\n#{out_array.join("\n")}"
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
def to_s
|
|
61
|
+
return '' if @raw_output.nil?
|
|
62
|
+
|
|
63
|
+
format_output_string(@raw_output.to_s)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def inspect
|
|
67
|
+
"#<#{self.class}:#{object_id} exitcode=#{exitcode.inspect} stdout=#{stdout.inspect} stderr=#{stderr.inspect}>"
|
|
68
|
+
end
|
|
69
|
+
|
|
60
70
|
private
|
|
61
71
|
|
|
62
72
|
def format_output_string(str)
|
|
63
73
|
# Cut the number of spaces in half, replace tabs with double spaces
|
|
64
74
|
str.gsub!(/\s\s/, ' ')
|
|
65
75
|
str.gsub!(/\t/, ' ')
|
|
66
|
-
return "#{@line_prefix}#{str}" if str.length <=
|
|
76
|
+
return "#{@line_prefix}#{str}" if str.length <= 180
|
|
67
77
|
|
|
68
|
-
str.scan(/.{1,
|
|
78
|
+
str.scan(/.{1,180}/).map { |s| "#{@line_prefix}#{s}" }.instance_eval { |a|
|
|
79
|
+
[a.first] + a.drop(1).map { |s| " #{s}" }
|
|
80
|
+
}.join("\n")
|
|
69
81
|
end
|
|
70
82
|
|
|
71
83
|
def set_vars_from_output(out)
|
data/lib/cem_win_spec.rb
CHANGED
|
@@ -8,16 +8,24 @@ module CemWinSpec
|
|
|
8
8
|
include CemWinSpec::Logging
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def self.exit_code
|
|
12
|
+
@exit_code ||= 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.exit_code=(value)
|
|
16
|
+
@exit_code = value
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
def self.signal_handler(runner)
|
|
12
20
|
Signal.trap('INT') do
|
|
13
|
-
puts 'Caught
|
|
14
|
-
runner
|
|
21
|
+
puts 'Caught SIGINT, killing tunnel and exiting'
|
|
22
|
+
runner&.iap_tunnel&.stop(wait: false, log: false)
|
|
15
23
|
exit 1
|
|
16
24
|
end
|
|
17
25
|
Signal.trap('TERM') do
|
|
18
|
-
puts 'Caught
|
|
19
|
-
runner
|
|
20
|
-
exit
|
|
26
|
+
puts 'Caught SIGTERM, killing tunnel and exiting'
|
|
27
|
+
runner&.iap_tunnel&.stop(wait: false, log: false)
|
|
28
|
+
exit!
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
|
|
@@ -38,25 +46,25 @@ module CemWinSpec
|
|
|
38
46
|
logger.debug "Created TestRunner: #{runner}"
|
|
39
47
|
signal_handler(runner)
|
|
40
48
|
logger.debug 'Set up signal handler'
|
|
49
|
+
working_dir = nil
|
|
41
50
|
begin
|
|
42
51
|
sre_out = setup_remote_environment(runner)
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
working_dir = sre_out.stdout.chomp
|
|
53
|
+
logger.debug "Working dir: #{working_dir}"
|
|
54
|
+
upload_out = upload_module(runner, working_dir)
|
|
55
|
+
module_dir = upload_out.stdout.chomp
|
|
45
56
|
logger.debug "Module dir: #{module_dir}"
|
|
46
|
-
|
|
47
|
-
check_output!(srr_out, runner)
|
|
57
|
+
setup_remote_ruby(runner, module_dir, **options)
|
|
48
58
|
case operation
|
|
49
59
|
when :spec
|
|
50
|
-
|
|
51
|
-
check_output!(spec_out, runner)
|
|
60
|
+
run_spec(runner, module_dir, **options)
|
|
52
61
|
when :clean_fixture_cache
|
|
53
|
-
|
|
54
|
-
check_output!(clean_fixture_cache_out, runner)
|
|
62
|
+
clean_fixture_cache(runner, module_dir, **options)
|
|
55
63
|
else
|
|
56
64
|
raise ArgumentError, "Unknown operation: #{operation}"
|
|
57
65
|
end
|
|
58
66
|
rescue StandardError => e
|
|
59
|
-
if operation == :spec
|
|
67
|
+
if operation == :spec && runner.retry?
|
|
60
68
|
begin
|
|
61
69
|
logger.warn "Error running spec: #{e.message}"
|
|
62
70
|
logger.debug e.backtrace.join("\n")
|
|
@@ -67,54 +75,98 @@ module CemWinSpec
|
|
|
67
75
|
else
|
|
68
76
|
handle_run_error(e)
|
|
69
77
|
end
|
|
78
|
+
ensure
|
|
79
|
+
if working_dir
|
|
80
|
+
begin
|
|
81
|
+
logger.info "Cleaning up working directory #{working_dir}"
|
|
82
|
+
clean_up(runner, working_dir, **options)
|
|
83
|
+
logger.debug 'Finished cleaning up working directory'
|
|
84
|
+
rescue StandardError => e
|
|
85
|
+
handle_run_error(e)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
runner&.iap_tunnel&.stop(log: false)
|
|
89
|
+
logger.info 'Finished running cem-win-spec'
|
|
70
90
|
end
|
|
71
91
|
end
|
|
72
92
|
|
|
73
93
|
def self.handle_run_error(err)
|
|
74
94
|
logger.fatal "Error: #{err.message}"
|
|
75
95
|
logger.debug err.backtrace.join("\n")
|
|
76
|
-
|
|
96
|
+
self.exit_code = 1
|
|
77
97
|
end
|
|
78
98
|
|
|
79
99
|
def self.retry_spec_on_error(runner, module_dir, **options)
|
|
80
100
|
logger.info 'Cleaning cache and trying again...'
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
101
|
+
validate_output do
|
|
102
|
+
clean_fixture_cache(runner, module_dir, **options)
|
|
103
|
+
end
|
|
104
|
+
validate_output do
|
|
105
|
+
run_spec(runner, module_dir, **options)
|
|
106
|
+
end
|
|
85
107
|
end
|
|
86
108
|
|
|
87
109
|
def self.setup_remote_environment(runner)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
validate_output do
|
|
111
|
+
runner.enable_long_paths.run
|
|
112
|
+
end
|
|
113
|
+
validate_output do
|
|
114
|
+
runner.enable_symlinks.run
|
|
115
|
+
end
|
|
116
|
+
validate_output do
|
|
117
|
+
runner.create_working_dir.run
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.upload_module(runner, working_dir)
|
|
122
|
+
validate_output do
|
|
123
|
+
runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
|
|
124
|
+
end
|
|
94
125
|
end
|
|
95
126
|
|
|
96
127
|
def self.setup_remote_ruby(runner, module_dir, **opts)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
128
|
+
validate_output do
|
|
129
|
+
runner.setup_ruby(operation_timeout: 300,
|
|
130
|
+
receive_timeout: 310,
|
|
131
|
+
working_dir: module_dir,
|
|
132
|
+
reuse_tunnel: false,
|
|
133
|
+
**opts).run
|
|
134
|
+
end
|
|
102
135
|
end
|
|
103
136
|
|
|
104
137
|
# Runs RSpec tests
|
|
105
138
|
def self.run_spec(runner, module_dir, **opts)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
139
|
+
output = validate_output(validation_method: :inspect) do
|
|
140
|
+
runner.rspec_tests_parallel(operation_timeout: 300,
|
|
141
|
+
receive_timeout: 310,
|
|
142
|
+
working_dir: module_dir,
|
|
143
|
+
ignore_exitcode: true,
|
|
144
|
+
reuse_tunnel: false,
|
|
145
|
+
**opts).run
|
|
146
|
+
end
|
|
147
|
+
if output.stderr&.include?('Tests Failed')
|
|
148
|
+
logger.error 'Tests failed'
|
|
149
|
+
self.exit_code = 1
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Clean up the remote working directory
|
|
154
|
+
# @param options [Hash] Options for the test runner
|
|
155
|
+
def self.clean_up(runner, working_dir, **opts)
|
|
156
|
+
validate_output do
|
|
157
|
+
runner.clean_up(operation_timeout: 300,
|
|
158
|
+
receive_timeout: 310,
|
|
159
|
+
working_dir: working_dir,
|
|
160
|
+
**opts).run
|
|
161
|
+
end
|
|
112
162
|
end
|
|
113
163
|
|
|
114
164
|
# Clean the remote fixture cache
|
|
115
165
|
# @param options [Hash] Options for the test runner
|
|
116
166
|
def self.clean_fixture_cache(runner, module_dir, **opts)
|
|
117
|
-
|
|
167
|
+
validate_output do
|
|
168
|
+
runner.clean_fixture_cache(working_dir: module_dir, **opts).run
|
|
169
|
+
end
|
|
118
170
|
end
|
|
119
171
|
|
|
120
172
|
def self.check_output!(output, runner = nil)
|
|
@@ -123,4 +175,30 @@ module CemWinSpec
|
|
|
123
175
|
raise "Command failed with exit code #{output.exitcode}"
|
|
124
176
|
end
|
|
125
177
|
end
|
|
178
|
+
|
|
179
|
+
class CemWinSpecValidationError < StandardError; end
|
|
180
|
+
|
|
181
|
+
def self.validate_output(*args, validation_method: :success?, no_output_strat: :debug, **kwargs)
|
|
182
|
+
raise ArgumentError, 'Block required' unless block_given?
|
|
183
|
+
|
|
184
|
+
output = yield *args, **kwargs
|
|
185
|
+
unless output
|
|
186
|
+
case no_output_strat
|
|
187
|
+
when :raise
|
|
188
|
+
raise 'No output'
|
|
189
|
+
when :warn
|
|
190
|
+
logger.warn 'No output'
|
|
191
|
+
when :debug
|
|
192
|
+
logger.debug 'No output'
|
|
193
|
+
else
|
|
194
|
+
# Do nothing
|
|
195
|
+
end
|
|
196
|
+
return false
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
unless output.send(validation_method)
|
|
200
|
+
raise CemWinSpecValidationError, "Output validation \"#{validation_method}\" failed:\n#{output}"
|
|
201
|
+
end
|
|
202
|
+
output
|
|
203
|
+
end
|
|
126
204
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cem_win_spec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Heston Snodgrass
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: winrm
|
|
@@ -139,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
139
139
|
- !ruby/object:Gem::Version
|
|
140
140
|
version: '0'
|
|
141
141
|
requirements: []
|
|
142
|
-
rubygems_version: 3.
|
|
142
|
+
rubygems_version: 3.5.18
|
|
143
143
|
signing_key:
|
|
144
144
|
specification_version: 4
|
|
145
145
|
summary: Write a short summary, because RubyGems requires one.
|