cem_win_spec 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 155b49bb4366a1b2fca4237d9da909e05093d907a5e7ff326f4d7a9c4e75f375
4
- data.tar.gz: f374c915ab3afcf1636315c02b869fdd4690291070f8429418108d292a922cce
3
+ metadata.gz: 0f80bb9bd51e4ad8a8d005504e107a6c7761a4f8c63da2fe2df69f84e1afb1b4
4
+ data.tar.gz: 6eb10d5243db33711faa2b8f21914e05f3ce16cc6514ae6add15159f03c53266
5
5
  SHA512:
6
- metadata.gz: 5709e80190d88d38826deae83c379a948d5e7de72202891db48b00521801ef56e9718a64c681b17ccc7eb82a275af72c955737fef9ee2ab62a8c1fbdccb0aa51
7
- data.tar.gz: 3ec1282194e8a3afe8df90e3e13e7bd80428bf9d2a70f7d7b8fe6aea0437460bc3b35e8f7e19e8d3a55ded60076b489b078ba80b551b25aa917ccb9cdc0526d0
6
+ metadata.gz: 3203c1ce68eb0c392c3968b82cf80066023545b1a4522d415b1f199538bdfd7cef34c4b2e4c8bd154ddec5e95fe5fe1f5b88652aeac81f2650f8a1b27bf3a8f4
7
+ data.tar.gz: 8ef99fac173500c73992db6f059a704674f862bf17563a3f3aff05507eb01e715a829ea822bf6c1f3845bdae9640f90f8d178247c57ad28eb402250fc8046b48
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_win_spec (0.1.5)
4
+ cem_win_spec (0.1.7)
5
5
  parallel_tests (~> 3.4)
6
6
  puppet_forge (~> 4.1)
7
7
  winrm (~> 2.3)
@@ -11,17 +11,18 @@ GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
13
  ast (2.4.2)
14
+ bigdecimal (3.1.6)
14
15
  builder (3.2.4)
15
16
  coderay (1.1.3)
16
17
  diff-lcs (1.5.0)
17
18
  erubi (1.12.0)
18
- faraday (2.7.10)
19
- faraday-net_http (>= 2.0, < 3.1)
20
- ruby2_keywords (>= 0.0.4)
19
+ faraday (2.9.0)
20
+ faraday-net_http (>= 2.0, < 3.2)
21
21
  faraday-follow_redirects (0.3.0)
22
22
  faraday (>= 1, < 3)
23
- faraday-net_http (3.0.2)
24
- ffi (1.15.5)
23
+ faraday-net_http (3.1.0)
24
+ net-http
25
+ ffi (1.16.3)
25
26
  gssapi (1.3.1)
26
27
  ffi (>= 1.0.1)
27
28
  gyoku (1.4.0)
@@ -35,7 +36,10 @@ GEM
35
36
  method_source (1.0.0)
36
37
  minitar (0.9)
37
38
  multi_json (1.15.0)
38
- nori (2.6.0)
39
+ net-http (0.4.1)
40
+ uri
41
+ nori (2.7.0)
42
+ bigdecimal
39
43
  parallel (1.22.1)
40
44
  parallel_tests (3.13.0)
41
45
  parallel
@@ -78,11 +82,11 @@ GEM
78
82
  rubocop-ast (1.24.1)
79
83
  parser (>= 3.1.1.0)
80
84
  ruby-progressbar (1.11.0)
81
- ruby2_keywords (0.0.5)
82
85
  rubyntlm (0.6.3)
83
86
  rubyzip (2.3.2)
84
87
  semantic_puppet (1.1.0)
85
88
  unicode-display_width (2.1.0)
89
+ uri (0.13.0)
86
90
  winrm (2.3.6)
87
91
  builder (>= 2.1.2)
88
92
  erubi (~> 1.8)
@@ -8,6 +8,8 @@ require 'puppet_forge'
8
8
  require 'yaml'
9
9
 
10
10
  module CemWinSpec
11
+ class FixtureCacheError < StandardError; end
12
+
11
13
  # Class for managing cached fixtures
12
14
  # Fixture caching is used to speed up test runs by reusing the same
13
15
  # Puppet modules between test runs instead of downloading them each time.
@@ -24,11 +26,10 @@ module CemWinSpec
24
26
  attr_reader :cache_dir, :cache_entries
25
27
 
26
28
  def initialize
27
- raise 'FixtureCache must be ran on Windows' unless Gem.win_platform?
28
-
29
+ validate_platform!
29
30
  @cache_dir = CACHE_DIR
30
31
  @cache_entries = setup_and_load_cache
31
- @entries_digest = Digest::SHA256.hexdigest(@cache_entries.to_s)
32
+ @entries_digest = hexdigest(@cache_entries.to_s)
32
33
  @dependencies = dependencies_from_metadata
33
34
  setup!
34
35
  end
@@ -43,6 +44,8 @@ module CemWinSpec
43
44
  puts "Downloading #{name} #{data[:version]}..."
44
45
  download_and_cache(name, data[:release_slug], data[:checksum])
45
46
  end
47
+ rescue StandardError => e
48
+ handle_error(e, 'Failed to setup fixture cache')
46
49
  ensure
47
50
  save_cache_entries
48
51
  end
@@ -52,16 +55,37 @@ module CemWinSpec
52
55
  raise "Directory #{fixtures_dir} does not exist" unless File.directory?(fixtures_dir)
53
56
 
54
57
  @cache_entries.each do |_, path|
55
- ::FileUtils.cp_r(path, fixtures_dir)
56
- interim_mod_path = File.join(fixtures_dir, File.basename(path))
57
58
  final_mod_path = File.join(fixtures_dir, File.basename(path).split('-').last)
58
- ::FileUtils.mv(interim_mod_path, final_mod_path)
59
- puts "Copied #{File.basename(path)} to #{final_mod_path}"
59
+ ::FileUtils.remove_entry_secure(final_mod_path) if File.exist?(final_mod_path)
60
+ ::FileUtils.cp_r(path, final_mod_path)
61
+ puts "Copied #{path} to #{final_mod_path}"
60
62
  end
63
+ rescue StandardError => e
64
+ handle_error(e, "Failed to copy fixtures to #{fixtures_dir}")
61
65
  end
62
66
 
63
67
  private
64
68
 
69
+ def validate_platform!
70
+ return if Gem.win_platform?
71
+
72
+ $stderr.puts 'ERROR: FixtureCache must run on Windows'
73
+ raise FixtureCacheError, 'FixtureCache must run on Windows'
74
+ end
75
+
76
+ def hexdigest(str)
77
+ Digest(:SHA256).hexdigest(str)
78
+ end
79
+
80
+ def handle_error(e, msg = 'Fixture cache error')
81
+ $stderr.puts "ERROR: #{msg}: #{e}"
82
+ raise e if e.is_a?(FixtureCacheError)
83
+
84
+ new_err = FixtureCacheError.new("#{msg}: #{e}")
85
+ new_err.set_backtrace(e.backtrace)
86
+ raise new_err
87
+ end
88
+
65
89
  def dependencies_from_metadata
66
90
  raise "File metadata.json not found in current directory #{Dir.pwd}" unless File.exist?('metadata.json')
67
91
 
@@ -81,6 +105,8 @@ module CemWinSpec
81
105
  release_slug: latest_valid_release.slug,
82
106
  }
83
107
  end
108
+ rescue StandardError => e
109
+ handle_error(e, 'Failed to get dependencies from metadata.json')
84
110
  end
85
111
 
86
112
  def dep_version_req_satisfied?(version_req, version)
@@ -88,6 +114,8 @@ module CemWinSpec
88
114
  raise "Invalid version requirement #{version_req}" unless reqs.to_a.length > 1
89
115
 
90
116
  reqs.to_a[1..-1].all? { |req| version_req_satisfied?(req, version) }
117
+ rescue StandardError => e
118
+ handle_error(e, 'Failed checking version requirement satisfaction')
91
119
  end
92
120
 
93
121
  def version_req_satisfied?(version_req, version)
@@ -95,7 +123,7 @@ module CemWinSpec
95
123
  end
96
124
 
97
125
  def module_checksum(name, version_req, version)
98
- Digest::SHA256.hexdigest("#{name}#{version_req}#{version}")
126
+ hexdigest("#{name}#{version_req}#{version}")
99
127
  end
100
128
 
101
129
  def manifest
@@ -114,6 +142,8 @@ module CemWinSpec
114
142
  end
115
143
  puts "Loading cache manifest #{manifest}..."
116
144
  YAML.load_file(manifest)
145
+ rescue StandardError => e
146
+ handle_error(e, 'Failed to setup and load cache')
117
147
  end
118
148
 
119
149
  def cached?(checksum)
@@ -132,13 +162,17 @@ module CemWinSpec
132
162
  File.join(module_cache_dir, 'temp'))
133
163
  cache_entries[checksum] = File.join(module_cache_dir, name)
134
164
  puts "Downloaded #{release_slug} to #{File.join(module_cache_dir, name)}"
165
+ rescue StandardError => e
166
+ handle_error(e, "Failed to download and cache #{name} with slug #{release_slug} and checksum #{checksum}")
135
167
  end
136
168
 
137
169
  def save_cache_entries
138
- return if @entries_digest == Digest::SHA256.hexdigest(cache_entries.to_s)
170
+ return if @entries_digest == hexdigest(cache_entries.to_s)
139
171
 
140
172
  File.write(manifest, cache_entries.to_yaml)
141
173
  puts "Saved cache manifest #{manifest}"
174
+ rescue StandardError => e
175
+ handle_error(e, "Failed to save cache manifest #{manifest}")
142
176
  end
143
177
  end
144
178
  end
@@ -8,50 +8,37 @@ module CemWinSpec
8
8
  class ModuleArchiveBuilder
9
9
  include CemWinSpec::Logging
10
10
 
11
- FILE_ALLOWLIST = %w[
12
- data
13
- files
14
- lib
15
- manifests
16
- plans
17
- spec
18
- tasks
19
- types
20
- .fixtures.yml
21
- .gitignore
22
- .rspec
23
- .rubocop.yml
24
- .yardopts
25
- hiera.yaml
26
- Gemfile
27
- metadata.json
28
- Rakefile
11
+ FILE_EXCLUDELIST = %w[
12
+ .git/**/*
13
+ data/benchmarks/**/*
14
+ dev/**/*
15
+ spec/fixtures/modules/*
16
+ pkg/**/*
17
+ Gemfile.lock
29
18
  ].freeze
30
19
 
31
- attr_reader :module_dir, :allowlist, :tempdir, :archive
20
+ attr_reader :module_dir, :excludelist, :tempdir, :archive
32
21
 
33
- def initialize(module_dir = Dir.pwd, allowlist: FILE_ALLOWLIST)
22
+ def initialize(module_dir = Dir.pwd, excludelist: FILE_EXCLUDELIST)
34
23
  @module_dir = module_dir
35
24
  @module_name = File.basename(module_dir)
36
- @allowlist = allowlist
25
+ @excludelist = excludelist
37
26
  end
38
27
 
39
28
  alias path archive
40
29
 
41
- def build
30
+ def build(remove_when_complete: true)
42
31
  create_tempdir
43
32
  copy_module_to_tempdir
44
33
  remove_unwanted_files
45
34
  create_archive
46
35
  if block_given?
47
36
  begin
48
- yield archive
49
- ensure
50
- FileUtils.rm_rf(archive) if archive && File.exist?(archive)
37
+ yield File.join(tempdir, archive)
51
38
  end
52
39
  end
53
40
  ensure
54
- FileUtils.rm_rf(tempdir) if tempdir && File.exist?(tempdir)
41
+ FileUtils.rm_rf(tempdir) if remove_when_complete && tempdir && File.exist?(tempdir)
55
42
  end
56
43
 
57
44
  private
@@ -62,22 +49,30 @@ module CemWinSpec
62
49
  end
63
50
 
64
51
  def copy_module_to_tempdir
65
- FileUtils.cp_r(module_dir, tempdir)
52
+ FileUtils.cp_r(module_dir, tempdir, preserve: false)
66
53
  logger.debug "Copied #{module_dir} to #{tempdir}"
67
54
  @temp_module_dir = File.join(tempdir, @module_name)
68
55
  end
69
56
 
70
- def remove_unwanted_files
71
- to_remove = Dir.glob("*", File::FNM_DOTMATCH, base: @temp_module_dir).reject { |f| allowlist.include?(f) || %w[. ..].include?(f) }
72
- to_remove.each do |file|
73
- FileUtils.rm_rf(File.join(@temp_module_dir, file))
74
- logger.debug "Removed #{file} from #{@temp_module_dir}"
57
+ def unwanted_files
58
+ unwanted = []
59
+ Dir.glob('**/*', File::FNM_DOTMATCH, base: @temp_module_dir) do |f|
60
+ next if %w[. ..].include?(f)
61
+
62
+ unwanted << File.join(@temp_module_dir, f) if excludelist.any? { |e| File.fnmatch?(e, f, File::FNM_DOTMATCH) }
75
63
  end
64
+ unwanted
65
+ end
66
+
67
+ def remove_unwanted_files
68
+ FileUtils.rm_rf(unwanted_files, verbose: (logger.level.first <= Logger::DEBUG))
76
69
  end
77
70
 
78
71
  def create_archive
79
72
  @archive = "#{@module_name}.tar.gz"
80
- `tar -czf #{archive} -C #{tempdir} #{@module_name}`
73
+ Dir.chdir(tempdir) do
74
+ `COPYFILE_DISABLE=1 tar -czf #{archive} --no-acls --no-xattrs #{@module_name}`
75
+ end
81
76
  logger.info "Created module archive #{archive}"
82
77
  end
83
78
  end
@@ -81,7 +81,7 @@ namespace 'cem_win_spec' do
81
81
  task :prep do
82
82
  puts 'Preparing spec data...'
83
83
  data_fix = cem_win_spec_base_path_in_fixtures(cem_win_spec_data_dir)
84
- if File.directory?(data_fix)
84
+ if Dir.exist?(data_fix)
85
85
  puts "Removing old #{data_fix} directory..."
86
86
  ::FileUtils.remove_entry_secure(data_fix)
87
87
  end
@@ -91,16 +91,23 @@ namespace 'cem_win_spec' do
91
91
  raise 'Spec data copy failed!'
92
92
  end
93
93
  hiera_fix = cem_win_spec_base_path_in_fixtures(cem_win_spec_hiera_conf)
94
+ if File.file?(hiera_fix)
95
+ puts "Removing old #{hiera_fix} file..."
96
+ ::FileUtils.remove_entry_secure(hiera_fix)
97
+ end
94
98
  puts "Copying Hiera config to #{hiera_fix}..."
95
99
  ::FileUtils.cp(cem_win_spec_hiera_conf, hiera_fix)
96
- unless File.exist?(hiera_fix)
97
- raise 'Hiera config copy failed!'
98
- end
100
+ raise 'Hiera config copy failed!' unless File.exist?(hiera_fix)
101
+
99
102
  puts 'Spec data prepared successfully'
100
- puts 'Preparing module fixtures...'
101
- mod_fix = cem_win_spec_base_path_in_fixtures('modules')
103
+ puts 'Setting up module fixture cache...'
102
104
  cache = CemWinSpec::FixtureCache.new
105
+ puts 'Copying module fixtures to spec fixtures directory...'
106
+ mod_fix = cem_win_spec_base_path_in_fixtures('modules')
103
107
  cache.copy_fixtures_to(mod_fix)
108
+ puts 'Removing old module symlink...'
109
+ link_path = File.join(mod_fix, 'cem_windows')
110
+ ::FileUtils.remove_entry_secure(link_path) if File.exist?(link_path)
104
111
  puts 'Module fixtures prepared successfully'
105
112
  end
106
113
 
@@ -108,9 +115,10 @@ namespace 'cem_win_spec' do
108
115
  task :parallel_spec_standalone do
109
116
  spec_files = Rake::FileList[cem_win_spec_pattern]
110
117
  pargs = ['--type', 'rspec']
111
- pargs << '--trace' if cem_win_spec_trace
118
+ pargs << '--verbose' if cem_win_spec_trace
112
119
  rspec_args = ['--']
113
120
  rspec_args << '--fail-fast' if cem_win_spec_fail_fast
121
+ rspec_args << '--backtrace' if cem_win_spec_trace
114
122
  rspec_args.concat(['--format', cem_win_spec_format])
115
123
  pargs.concat(rspec_args)
116
124
  pargs << '--'
@@ -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)
@@ -68,7 +60,7 @@ module CemWinSpec
68
60
  module_archive_build { |a| remote_upload(a, remote_working_dir) }
69
61
  module_dir = "#{remote_working_dir}\\#{File.basename(module_archive_path, '.tar.gz')}"
70
62
  logger.debug "Module uploaded to #{module_dir}.tar.gz, extracting..."
71
- remote_run("tar -xzf #{module_dir}.tar.gz -C #{remote_working_dir}")
63
+ remote_run("tar -C #{remote_working_dir} -xzf #{module_dir}.tar.gz")
72
64
  logger.debug "Module extracted to #{module_dir}"
73
65
  module_dir
74
66
  end
@@ -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,10 +98,10 @@ module CemWinSpec
104
98
  end
105
99
  end
106
100
 
107
- def clean_up
101
+ def clean_up(working_dir)
108
102
  @clean_up ||= new_command('Cleanup') do |working_dir|
109
103
  if remote_available?
110
- remote_run(cleanup_cmd, quiet: true)
104
+ remote_run(cleanup_cmd, working_dir, quiet: true)
111
105
  else
112
106
  logger.warn 'Cleanup not available'
113
107
  end
@@ -120,6 +114,10 @@ module CemWinSpec
120
114
  end
121
115
  end
122
116
 
117
+ def inspect
118
+ "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
119
+ end
120
+
123
121
  private
124
122
 
125
123
  def title_sym(title)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemWinSpec
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
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
 
@@ -80,12 +84,17 @@ module CemWinSpec
80
84
  logger.debug "Executing command:\n#{cmd.split(%r{\n|\r\n|;\s*}).map { |c| " #> #{c}" }.join("\n")}"
81
85
  end
82
86
 
87
+ # Commands that, when ran, will change the ruby version. This will also set the local bundle config path
83
88
  def change_ruby_version_cmd
84
- "uru #{ruby_version}"
89
+ [
90
+ "uru #{ruby_version}",
91
+ '$env:GEM_HOME = "$(ruby -e "puts Gem.dir")"',
92
+ 'bundle config set --local path "$env:GEM_HOME"',
93
+ ].join(COMMAND_SEPARATOR)
85
94
  end
86
95
 
87
96
  def set_env_var_cmd(key, value)
88
- "set #{key}=\"#{value}\""
97
+ "$env:#{key} = \"#{value}\""
89
98
  end
90
99
 
91
100
  def change_working_dir_cmd(dir)
@@ -29,8 +29,8 @@ module CemWinSpec
29
29
  begin
30
30
  shell = conn.shell(:powershell)
31
31
  output = shell.run(command(cmd)) do |stdout, stderr|
32
- logger << stdout unless stdout.nil? || stdout.empty?
33
- logger << stderr unless stderr.nil? || stderr.empty?
32
+ logger << stdout if stdout
33
+ logger << stderr if stderr
34
34
  end
35
35
  rescue WinRM::WinRMAuthorizationError => e
36
36
  @available = false
@@ -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
 
@@ -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
@@ -40,23 +40,22 @@ module CemWinSpec
40
40
  logger.debug 'Set up signal handler'
41
41
  begin
42
42
  sre_out = setup_remote_environment(runner)
43
- check_output!(sre_out, runner)
44
- module_dir = sre_out.stdout.chomp
43
+ working_dir = sre_out.stdout.chomp
44
+ logger.debug "Working dir: #{working_dir}"
45
+ upload_out = upload_module(runner, working_dir)
46
+ module_dir = upload_out.stdout.chomp
45
47
  logger.debug "Module dir: #{module_dir}"
46
- srr_out = setup_remote_ruby(runner, module_dir, **options)
47
- check_output!(srr_out, runner)
48
+ setup_remote_ruby(runner, module_dir, **options)
48
49
  case operation
49
50
  when :spec
50
- spec_out = run_spec(runner, module_dir, **options)
51
- check_output!(spec_out, runner)
51
+ run_spec(runner, module_dir, **options)
52
52
  when :clean_fixture_cache
53
- clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, **options)
54
- check_output!(clean_fixture_cache_out, runner)
53
+ clean_fixture_cache(runner, module_dir, **options)
55
54
  else
56
55
  raise ArgumentError, "Unknown operation: #{operation}"
57
56
  end
58
57
  rescue StandardError => e
59
- if operation == :spec
58
+ if operation == :spec && runner.retry?
60
59
  begin
61
60
  logger.warn "Error running spec: #{e.message}"
62
61
  logger.debug e.backtrace.join("\n")
@@ -67,6 +66,9 @@ module CemWinSpec
67
66
  else
68
67
  handle_run_error(e)
69
68
  end
69
+ ensure
70
+ runner&.clean_up(working_dir) if working_dir
71
+ runner&.iap_tunnel&.stop(wait: false, log: false)
70
72
  end
71
73
  end
72
74
 
@@ -78,44 +80,60 @@ module CemWinSpec
78
80
 
79
81
  def self.retry_spec_on_error(runner, module_dir, **options)
80
82
  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)
83
+ validate_output do
84
+ clean_fixture_cache(runner, module_dir, **options)
85
+ end
86
+ validate_output do
87
+ run_spec(runner, module_dir, **options)
88
+ end
85
89
  end
86
90
 
87
91
  def self.setup_remote_environment(runner)
88
- runner.enable_long_paths.run
89
- runner.enable_symlinks.run
90
- runner.enable_symlinks.run
91
- working_dir_out = runner.create_working_dir.run
92
- working_dir = working_dir_out.stdout.chomp
93
- logger.debug "Working dir: #{working_dir}"
94
- runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
92
+ validate_output do
93
+ runner.enable_long_paths.run
94
+ end
95
+ validate_output do
96
+ runner.enable_symlinks.run
97
+ end
98
+ validate_output do
99
+ runner.create_working_dir.run
100
+ end
101
+ end
102
+
103
+ def self.upload_module(runner, working_dir)
104
+ validate_output do
105
+ runner.upload_module(operation_timeout: 300, receive_timeout: 310, working_dir: working_dir).run
106
+ end
95
107
  end
96
108
 
97
109
  def self.setup_remote_ruby(runner, module_dir, **opts)
98
- runner.setup_ruby(operation_timeout: 300,
99
- receive_timeout: 310,
100
- working_dir: module_dir,
101
- reuse_tunnel: false,
102
- **opts).run
110
+ validate_output do
111
+ runner.setup_ruby(operation_timeout: 300,
112
+ receive_timeout: 310,
113
+ working_dir: module_dir,
114
+ reuse_tunnel: false,
115
+ **opts).run
116
+ end
103
117
  end
104
118
 
105
119
  # Runs RSpec tests
106
120
  def self.run_spec(runner, module_dir, **opts)
107
- runner.rspec_tests_parallel(operation_timeout: 300,
108
- receive_timeout: 310,
109
- working_dir: module_dir,
110
- ignore_exitcode: true,
111
- reuse_tunnel: false,
112
- **opts).run
121
+ output = validate_output(validation_method: :inspect) do
122
+ runner.rspec_tests_parallel(operation_timeout: 300,
123
+ receive_timeout: 310,
124
+ working_dir: module_dir,
125
+ ignore_exitcode: true,
126
+ reuse_tunnel: false,
127
+ **opts).run
128
+ end
113
129
  end
114
130
 
115
131
  # Clean the remote fixture cache
116
132
  # @param options [Hash] Options for the test runner
117
133
  def self.clean_fixture_cache(runner, module_dir, **opts)
118
- runner.clean_fixture_cache(working_dir: module_dir, **opts).run
134
+ validate_output do
135
+ runner.clean_fixture_cache(working_dir: module_dir, **opts).run
136
+ end
119
137
  end
120
138
 
121
139
  def self.check_output!(output, runner = nil)
@@ -124,4 +142,30 @@ module CemWinSpec
124
142
  raise "Command failed with exit code #{output.exitcode}"
125
143
  end
126
144
  end
145
+
146
+ class CemWinSpecValidationError < StandardError; end
147
+
148
+ def self.validate_output(*args, validation_method: :success?, no_output_strat: :debug, **kwargs)
149
+ raise ArgumentError, 'Block required' unless block_given?
150
+
151
+ output = yield *args, **kwargs
152
+ unless output
153
+ case no_output_strat
154
+ when :raise
155
+ raise 'No output'
156
+ when :warn
157
+ logger.warn 'No output'
158
+ when :debug
159
+ logger.debug 'No output'
160
+ else
161
+ # Do nothing
162
+ end
163
+ return false
164
+ end
165
+
166
+ unless output.send(validation_method)
167
+ raise CemWinSpecValidationError, "Output validation \"#{validation_method}\" failed: #{output}"
168
+ end
169
+ output
170
+ end
127
171
  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.5
4
+ version: 0.1.7
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-08-21 00:00:00.000000000 Z
11
+ date: 2024-03-29 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.4.22
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Write a short summary, because RubyGems requires one.