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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c99510b91f69ac85f4e529d51134f797546bca8ee7ede74629a08620280b4c6
4
- data.tar.gz: 57aa64d9931b08ce6a1e49178303643ded631334b43612707ee7383fb8c07426
3
+ metadata.gz: 000454f69f3ea2722dcd11ec105a5ebe617301d076a2c1772cb530d8275e0f11
4
+ data.tar.gz: 1d2635cc5f330baa755482c5738901e2e79aeabd585200db5ee0ef218cd9decf
5
5
  SHA512:
6
- metadata.gz: bdc2ba16b32de3f4e5eff3f327d5407cb7d377cb836ae971b9c7dd57b771d8b1e7d7347c312006e52e77302c8ff2c61c899d5f82e39336aefa8bfb41dca0e865
7
- data.tar.gz: 07f97ff0b736be471fea8cd9db08ce10c070353e03c5e523fc301b75a39a6689e77149ea95933d55c7cda5110f93983e562305bf4020472025fadde500293a31
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.6)
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
- builder (3.2.4)
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.12.0)
18
- faraday (2.7.10)
19
- faraday-net_http (>= 2.0, < 3.1)
20
- ruby2_keywords (>= 0.0.4)
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.2)
24
- ffi (1.15.5)
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
- logging (2.3.1)
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.9)
42
+ minitar (0.12.1)
37
43
  multi_json (1.15.0)
38
- nori (2.6.0)
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
- ruby2_keywords (0.0.5)
82
- rubyntlm (0.6.3)
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
- winrm (2.3.6)
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
@@ -77,3 +77,4 @@ parser.parse!
77
77
 
78
78
  operation = options[:operation] || :spec
79
79
  CemWinSpec.run(operation, options)
80
+ exit CemWinSpec.exit_code
@@ -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 run_all
27
- check_connectivity.run
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 |working_dir|
109
- if remote_available?
110
- remote_run(cleanup_cmd, quiet: true)
111
- else
112
- logger.warn 'Cleanup not available'
113
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemWinSpec
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.8"
5
5
  end
@@ -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
- def command(cmd)
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 = command(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
- "uru #{ruby_version}"
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
- "set #{key}=\"#{value}\""
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, **_kwargs)
38
+ def bg_run(cmd, *_args, **kwargs)
39
+ cmd = command(cmd, **kwargs)
39
40
  log_command(cmd)
40
- Process.detach(spawn(command(cmd)))
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, **_kwargs)
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(command(cmd))
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, **_kwargs)
64
+ def run(cmd, *_args, **kwargs)
65
+ cmd = command(cmd, **kwargs)
63
66
  log_command(cmd)
64
- Open3.capture3(command(cmd))
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
- def run(cmd, *_args, **_kwargs)
25
- cmd = cmd.join('; ') if cmd.is_a?(Array)
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(command(cmd)) do |stdout, stderr|
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, **opts)
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, **@init_opts.merge(opts))
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 <= 115
76
+ return "#{@line_prefix}#{str}" if str.length <= 180
67
77
 
68
- str.scan(/.{1,115}/).map { |s| "#{@line_prefix}#{s}" }.join("\n")
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 interrupt, killing tunnel and exiting'
14
- runner.iap_tunnel.stop(wait: false, log: false)
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 interrupt, killing tunnel and exiting'
19
- runner.iap_tunnel.stop(wait: false, log: false)
20
- exit 1
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
- check_output!(sre_out, runner)
44
- module_dir = sre_out.stdout.chomp
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
- srr_out = setup_remote_ruby(runner, module_dir, **options)
47
- check_output!(srr_out, runner)
57
+ setup_remote_ruby(runner, module_dir, **options)
48
58
  case operation
49
59
  when :spec
50
- spec_out = run_spec(runner, module_dir, **options)
51
- check_output!(spec_out, runner)
60
+ run_spec(runner, module_dir, **options)
52
61
  when :clean_fixture_cache
53
- clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, **options)
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
- exit 1
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
- clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, **options)
82
- check_output!(clean_fixture_cache_out, runner)
83
- spec_out = run_spec(runner, module_dir, **options)
84
- check_output!(spec_out, runner)
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
- runner.enable_long_paths.run
89
- runner.enable_symlinks.run
90
- working_dir_out = runner.create_working_dir.run
91
- working_dir = working_dir_out.stdout.chomp
92
- logger.debug "Working dir: #{working_dir}"
93
- runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
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
- runner.setup_ruby(operation_timeout: 300,
98
- receive_timeout: 310,
99
- working_dir: module_dir,
100
- reuse_tunnel: false,
101
- **opts).run
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
- runner.rspec_tests_parallel(operation_timeout: 300,
107
- receive_timeout: 310,
108
- working_dir: module_dir,
109
- ignore_exitcode: true,
110
- reuse_tunnel: false,
111
- **opts).run
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
- runner.clean_fixture_cache(working_dir: module_dir, **opts).run
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.6
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: 2023-09-26 00:00:00.000000000 Z
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.4.18
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.