cem_win_spec 0.1.5 → 0.1.7
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 +12 -8
- data/lib/cem_win_spec/fixture_cache.rb +43 -9
- data/lib/cem_win_spec/module_archive_builder.rb +28 -33
- data/lib/cem_win_spec/rake_tasks.rb +15 -7
- data/lib/cem_win_spec/test_runner.rb +12 -14
- data/lib/cem_win_spec/version.rb +1 -1
- data/lib/cem_win_spec/win_exec/cmd/base_cmd.rb +11 -2
- data/lib/cem_win_spec/win_exec/cmd/winrm_cmd.rb +2 -2
- data/lib/cem_win_spec/win_exec/exec.rb +5 -3
- data/lib/cem_win_spec/win_exec/output.rb +15 -3
- data/lib/cem_win_spec.rb +76 -32
- 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: 0f80bb9bd51e4ad8a8d005504e107a6c7761a4f8c63da2fe2df69f84e1afb1b4
|
4
|
+
data.tar.gz: 6eb10d5243db33711faa2b8f21914e05f3ce16cc6514ae6add15159f03c53266
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
19
|
-
faraday-net_http (>= 2.0, < 3.
|
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
|
24
|
-
|
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
|
-
|
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
|
-
|
28
|
-
|
29
|
+
validate_platform!
|
29
30
|
@cache_dir = CACHE_DIR
|
30
31
|
@cache_entries = setup_and_load_cache
|
31
|
-
@entries_digest =
|
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.
|
59
|
-
|
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
|
-
|
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 ==
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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, :
|
20
|
+
attr_reader :module_dir, :excludelist, :tempdir, :archive
|
32
21
|
|
33
|
-
def initialize(module_dir = Dir.pwd,
|
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
|
-
@
|
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
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
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
|
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
|
-
|
98
|
-
end
|
100
|
+
raise 'Hiera config copy failed!' unless File.exist?(hiera_fix)
|
101
|
+
|
99
102
|
puts 'Spec data prepared successfully'
|
100
|
-
puts '
|
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 << '--
|
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
|
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)
|
@@ -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
|
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)
|
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
|
|
@@ -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
|
-
|
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
|
-
"
|
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
|
33
|
-
logger << stderr
|
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 <=
|
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
@@ -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
|
-
|
44
|
-
|
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
|
-
|
47
|
-
check_output!(srr_out, runner)
|
48
|
+
setup_remote_ruby(runner, module_dir, **options)
|
48
49
|
case operation
|
49
50
|
when :spec
|
50
|
-
|
51
|
-
check_output!(spec_out, runner)
|
51
|
+
run_spec(runner, module_dir, **options)
|
52
52
|
when :clean_fixture_cache
|
53
|
-
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
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.
|
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:
|
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.
|
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.
|