beaker 6.9.0 → 7.0.0
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/.github/workflows/release.yml +4 -4
- data/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +2 -8
- data/CHANGELOG.md +6 -12
- data/Rakefile +5 -3
- data/beaker.gemspec +3 -3
- data/lib/beaker/dsl/helpers/host_helpers.rb +11 -11
- data/lib/beaker/dsl/patterns.rb +2 -2
- data/lib/beaker/dsl/structure.rb +5 -5
- data/lib/beaker/host/aix/group.rb +4 -4
- data/lib/beaker/host/aix/user.rb +4 -4
- data/lib/beaker/host/mac/group.rb +2 -2
- data/lib/beaker/host/mac/user.rb +2 -2
- data/lib/beaker/host/pswindows/group.rb +4 -4
- data/lib/beaker/host/pswindows/user.rb +4 -4
- data/lib/beaker/host/unix/group.rb +4 -4
- data/lib/beaker/host/unix/user.rb +4 -4
- data/lib/beaker/host/windows/group.rb +4 -4
- data/lib/beaker/host/windows/user.rb +4 -4
- data/lib/beaker/logger.rb +1 -1
- data/lib/beaker/logger_junit.rb +10 -23
- data/lib/beaker/platform.rb +1 -2
- data/lib/beaker/result.rb +4 -18
- data/lib/beaker/shared/repetition.rb +2 -2
- data/lib/beaker/tasks/rake_task.rb +2 -2
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/host_prebuilt_steps_spec.rb +6 -6
- data/spec/beaker/logger_junit_spec.rb +0 -36
- data/spec/beaker/logger_spec.rb +0 -18
- data/spec/beaker/platform_spec.rb +1 -11
- metadata +7 -8
- data/spec/beaker/result_spec.rb +0 -189
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a52a04e5317c78954859cef26c1988cf66a832ad0f62de9d78c69ffbe23c108c
|
|
4
|
+
data.tar.gz: 4de10d9e282aaa62986410393d440278c5821d042505436131ba5d6ac92a2fdd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 155935fc22c9dd129c5c54c6179709b330048f85f6048aa4f67430b61402bbdc1934856138f23e159aaa40c306024208b7ad18ca9d9628df9c17326b20725e31
|
|
7
|
+
data.tar.gz: 92508f324729fde5238743beabd46b89c98921d5bd28321240ae73aebb06690cceae28db7a403ed4f385812353f650e01a82d6a67d35592d82673f6b6d7322bc
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
contents: write # clone repo and create release
|
|
40
40
|
steps:
|
|
41
41
|
- name: Download gem from GitHub cache
|
|
42
|
-
uses: actions/download-artifact@
|
|
42
|
+
uses: actions/download-artifact@v5
|
|
43
43
|
with:
|
|
44
44
|
name: gem-artifact
|
|
45
45
|
- name: Create Release
|
|
@@ -56,7 +56,7 @@ jobs:
|
|
|
56
56
|
packages: write # publish to rubygems.pkg.github.com
|
|
57
57
|
steps:
|
|
58
58
|
- name: Download gem from GitHub cache
|
|
59
|
-
uses: actions/download-artifact@
|
|
59
|
+
uses: actions/download-artifact@v5
|
|
60
60
|
with:
|
|
61
61
|
name: gem-artifact
|
|
62
62
|
- name: Publish gem to GitHub packages
|
|
@@ -73,7 +73,7 @@ jobs:
|
|
|
73
73
|
id-token: write # rubygems.org authentication
|
|
74
74
|
steps:
|
|
75
75
|
- name: Download gem from GitHub cache
|
|
76
|
-
uses: actions/download-artifact@
|
|
76
|
+
uses: actions/download-artifact@v5
|
|
77
77
|
with:
|
|
78
78
|
name: gem-artifact
|
|
79
79
|
- uses: rubygems/configure-rubygems-credentials@v1.0.0
|
|
@@ -92,7 +92,7 @@ jobs:
|
|
|
92
92
|
- release-to-rubygems
|
|
93
93
|
steps:
|
|
94
94
|
- name: Download gem from GitHub cache
|
|
95
|
-
uses: actions/download-artifact@
|
|
95
|
+
uses: actions/download-artifact@v5
|
|
96
96
|
with:
|
|
97
97
|
name: gem-artifact
|
|
98
98
|
- name: Install Ruby
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config --no-auto-gen-timestamp`
|
|
3
|
-
# using RuboCop version 1.75.
|
|
3
|
+
# using RuboCop version 1.75.8.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -294,12 +294,6 @@ RSpec/UnspecifiedException:
|
|
|
294
294
|
RSpec/VerifiedDoubles:
|
|
295
295
|
Enabled: false
|
|
296
296
|
|
|
297
|
-
# Offense count: 2
|
|
298
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
299
|
-
Rake/Desc:
|
|
300
|
-
Exclude:
|
|
301
|
-
- 'Rakefile'
|
|
302
|
-
|
|
303
297
|
# Offense count: 7
|
|
304
298
|
Security/Eval:
|
|
305
299
|
Exclude:
|
|
@@ -316,7 +310,7 @@ Security/Open:
|
|
|
316
310
|
Exclude:
|
|
317
311
|
- 'lib/beaker/dsl/helpers/web_helpers.rb'
|
|
318
312
|
|
|
319
|
-
# Offense count:
|
|
313
|
+
# Offense count: 105
|
|
320
314
|
# This cop supports safe autocorrection (--autocorrect).
|
|
321
315
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
|
322
316
|
# URISchemes: http, https
|
data/CHANGELOG.md
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [7.0.0](https://github.com/voxpupuli/beaker/tree/7.0.0) (2025-08-07)
|
|
4
4
|
|
|
5
|
-
[Full Changelog](https://github.com/voxpupuli/beaker/compare/6.8.1...
|
|
5
|
+
[Full Changelog](https://github.com/voxpupuli/beaker/compare/6.8.1...7.0.0)
|
|
6
6
|
|
|
7
|
-
**
|
|
8
|
-
|
|
9
|
-
- \(maint\) Add Ubuntu 26.04 \(resolute\) codename mapping [\#2024](https://github.com/voxpupuli/beaker/pull/2024) ([bastelfreak](https://github.com/bastelfreak))
|
|
10
|
-
|
|
11
|
-
**Fixed bugs:**
|
|
7
|
+
**Breaking changes:**
|
|
12
8
|
|
|
13
|
-
-
|
|
14
|
-
- Don't lose a whole junit report to one bad byte [\#2026](https://github.com/voxpupuli/beaker/pull/2026) ([bastelfreak](https://github.com/bastelfreak))
|
|
15
|
-
- Stop escape\_invalid\_xml\_chars allocating per character [\#2025](https://github.com/voxpupuli/beaker/pull/2025) ([bastelfreak](https://github.com/bastelfreak))
|
|
9
|
+
- Require Ruby 3.2 [\#1906](https://github.com/voxpupuli/beaker/pull/1906) ([bastelfreak](https://github.com/bastelfreak))
|
|
16
10
|
|
|
17
|
-
**
|
|
11
|
+
**Implemented enhancements:**
|
|
18
12
|
|
|
19
|
-
-
|
|
13
|
+
- beaker-hostgenerator: Switch to 3.x [\#1937](https://github.com/voxpupuli/beaker/pull/1937) ([bastelfreak](https://github.com/bastelfreak))
|
|
20
14
|
|
|
21
15
|
## [6.8.1](https://github.com/voxpupuli/beaker/tree/6.8.1) (2025-06-16)
|
|
22
16
|
|
data/Rakefile
CHANGED
|
@@ -6,10 +6,12 @@ HOSTS_PRESERVED = 'log/latest/hosts_preserved.yml'
|
|
|
6
6
|
|
|
7
7
|
task :default => ['test:spec']
|
|
8
8
|
|
|
9
|
+
desc 'Run unit tests'
|
|
9
10
|
task :test do
|
|
10
11
|
Rake::Task['test:spec'].invoke
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
desc 'run unit tests'
|
|
13
15
|
task :spec do
|
|
14
16
|
Rake::Task['test:spec'].invoke
|
|
15
17
|
end
|
|
@@ -186,13 +188,13 @@ begin
|
|
|
186
188
|
require 'github_changelog_generator/task'
|
|
187
189
|
|
|
188
190
|
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
|
189
|
-
config.exclude_labels = %w{duplicate question invalid wontfix wont-fix skip-changelog}
|
|
191
|
+
config.exclude_labels = %w{duplicate question invalid wontfix wont-fix skip-changelog github_actions}
|
|
190
192
|
config.user = 'voxpupuli'
|
|
191
193
|
config.project = 'beaker'
|
|
192
194
|
gem_version = Gem::Specification.load("#{config.project}.gemspec").version
|
|
193
195
|
config.future_release = gem_version
|
|
194
|
-
config.release_branch = '
|
|
195
|
-
config.exclude_tags_regex =
|
|
196
|
+
config.release_branch = 'master'
|
|
197
|
+
config.exclude_tags_regex = /\A4\./
|
|
196
198
|
config.since_tag = '5.7.0'
|
|
197
199
|
end
|
|
198
200
|
rescue LoadError
|
data/beaker.gemspec
CHANGED
|
@@ -16,13 +16,13 @@ Gem::Specification.new do |s|
|
|
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
17
17
|
s.require_paths = ["lib"]
|
|
18
18
|
|
|
19
|
-
s.required_ruby_version = Gem::Requirement.new('>= 2
|
|
19
|
+
s.required_ruby_version = Gem::Requirement.new('>= 3.2')
|
|
20
20
|
|
|
21
21
|
# Testing dependencies
|
|
22
22
|
s.add_development_dependency 'fakefs', '>= 2.4', '< 4'
|
|
23
23
|
s.add_development_dependency 'rake', '~> 13.0'
|
|
24
24
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
25
|
-
s.add_development_dependency 'voxpupuli-rubocop', '~>
|
|
25
|
+
s.add_development_dependency 'voxpupuli-rubocop', '~> 4.1.0'
|
|
26
26
|
|
|
27
27
|
# Run time dependencies
|
|
28
28
|
# Required for Ruby 3.3+ support
|
|
@@ -47,6 +47,6 @@ Gem::Specification.new do |s|
|
|
|
47
47
|
s.add_dependency 'thor', ['>= 1.0.1', '< 2.0']
|
|
48
48
|
|
|
49
49
|
# Run time dependencies that are Beaker libraries
|
|
50
|
-
s.add_dependency 'beaker-hostgenerator', '~>
|
|
50
|
+
s.add_dependency 'beaker-hostgenerator', '~> 3.0'
|
|
51
51
|
s.add_dependency 'stringify-hash', '~> 0.0'
|
|
52
52
|
end
|
|
@@ -118,8 +118,8 @@ module Beaker
|
|
|
118
118
|
#
|
|
119
119
|
# @return [Result] An object representing the outcome of *command*.
|
|
120
120
|
# @raise [FailTest] Raises an exception if *command* obviously fails.
|
|
121
|
-
def shell(command, opts = {}, &
|
|
122
|
-
on(default, command, opts, &
|
|
121
|
+
def shell(command, opts = {}, &)
|
|
122
|
+
on(default, command, opts, &)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
# Move a file from a remote to a local path
|
|
@@ -307,7 +307,7 @@ module Beaker
|
|
|
307
307
|
# @param [Proc] block Additional tests to run after script has executed
|
|
308
308
|
#
|
|
309
309
|
# @return [Result] Returns the result of the underlying SCP operation.
|
|
310
|
-
def run_script_on(host, script, opts = {}, &
|
|
310
|
+
def run_script_on(host, script, opts = {}, &)
|
|
311
311
|
# this is unsafe as it uses the File::SEPARATOR will be set to that
|
|
312
312
|
# of the coordinator node. This works for us because we use cygwin
|
|
313
313
|
# which will properly convert the paths. Otherwise this would not
|
|
@@ -317,13 +317,13 @@ module Beaker
|
|
|
317
317
|
remote_path = File.join("", "tmp", File.basename(script))
|
|
318
318
|
|
|
319
319
|
scp_to host, script, remote_path
|
|
320
|
-
on
|
|
320
|
+
on(host, remote_path, opts, &)
|
|
321
321
|
end
|
|
322
322
|
|
|
323
323
|
# Move a local script to default host and execute it
|
|
324
324
|
# @see #run_script_on
|
|
325
|
-
def run_script(script, opts = {}, &
|
|
326
|
-
run_script_on(default, script, opts, &
|
|
325
|
+
def run_script(script, opts = {}, &)
|
|
326
|
+
run_script_on(default, script, opts, &)
|
|
327
327
|
end
|
|
328
328
|
|
|
329
329
|
# Install a package on a host
|
|
@@ -515,8 +515,8 @@ module Beaker
|
|
|
515
515
|
# @param [Proc] block Additional actions or assertions.
|
|
516
516
|
# @!macro common_opts
|
|
517
517
|
#
|
|
518
|
-
def curl_on(host, cmd, opts = {}, &
|
|
519
|
-
on
|
|
518
|
+
def curl_on(host, cmd, opts = {}, &)
|
|
519
|
+
on(host, "curl --tlsv1 %s" % cmd, opts, &)
|
|
520
520
|
end
|
|
521
521
|
|
|
522
522
|
def curl_with_retries(_desc, host, url, desired_exit_codes, max_retries = 60, retry_interval = 1)
|
|
@@ -547,7 +547,7 @@ module Beaker
|
|
|
547
547
|
# @option opts [Boolean] :verbose (false)
|
|
548
548
|
#
|
|
549
549
|
# @return [Result] Result object of the last command execution
|
|
550
|
-
def retry_on(host, command, opts = {}, &
|
|
550
|
+
def retry_on(host, command, opts = {}, &)
|
|
551
551
|
option_exit_codes = opts[:desired_exit_codes]
|
|
552
552
|
option_max_retries = opts[:max_retries].to_i
|
|
553
553
|
option_retry_interval = opts[:retry_interval].to_f
|
|
@@ -562,11 +562,11 @@ module Beaker
|
|
|
562
562
|
logger.debug " Trying command #{max_retries} times."
|
|
563
563
|
logger.debug ".", add_newline: false
|
|
564
564
|
|
|
565
|
-
result = on
|
|
565
|
+
result = on(host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &)
|
|
566
566
|
num_retries = 0
|
|
567
567
|
until desired_exit_codes.include?(result.exit_code)
|
|
568
568
|
sleep retry_interval
|
|
569
|
-
result = on
|
|
569
|
+
result = on(host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &)
|
|
570
570
|
num_retries += 1
|
|
571
571
|
logger.debug ".", add_newline: false
|
|
572
572
|
if (num_retries > max_retries)
|
data/lib/beaker/dsl/patterns.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Beaker
|
|
|
22
22
|
#
|
|
23
23
|
# @return [Array<Result>, Result, nil] An array of results, a result object, or nil.
|
|
24
24
|
# Check {Beaker::Shared::HostManager#run_block_on} for more details on this.
|
|
25
|
-
def block_on
|
|
25
|
+
def block_on(hosts_or_filter, opts = {}, &)
|
|
26
26
|
block_hosts = nil
|
|
27
27
|
if defined? hosts
|
|
28
28
|
block_hosts = hosts
|
|
@@ -33,7 +33,7 @@ module Beaker
|
|
|
33
33
|
else
|
|
34
34
|
block_hosts = hosts_or_filter
|
|
35
35
|
end
|
|
36
|
-
run_block_on
|
|
36
|
+
run_block_on(block_hosts, filter, opts, &)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
data/lib/beaker/dsl/structure.rb
CHANGED
|
@@ -107,10 +107,10 @@ module Beaker
|
|
|
107
107
|
# @param [String] manual_test_name The name of the test to be logged.
|
|
108
108
|
# @param [Proc] block The actions to be performed during this test.
|
|
109
109
|
#
|
|
110
|
-
def manual_test
|
|
110
|
+
def manual_test(manual_test_name, &)
|
|
111
111
|
if @options.has_key?(:exec_manual_tests) && @options[:exec_manual_tests] == true
|
|
112
112
|
# here the option is set so we run the test as normal
|
|
113
|
-
test_name
|
|
113
|
+
test_name(manual_test_name, &)
|
|
114
114
|
else
|
|
115
115
|
# here no option was set so we log the test name and skip it
|
|
116
116
|
test_name manual_test_name
|
|
@@ -261,13 +261,13 @@ module Beaker
|
|
|
261
261
|
# targets for this tests case.
|
|
262
262
|
# @raise [SkipTest] Raises skip test if there are no valid hosts for
|
|
263
263
|
# this test case after confinement.
|
|
264
|
-
def confine(type, criteria, host_array = nil, &
|
|
264
|
+
def confine(type, criteria, host_array = nil, &)
|
|
265
265
|
hosts_to_modify = Array(host_array || hosts)
|
|
266
266
|
hosts_not_modified = hosts - hosts_to_modify # we aren't examining these hosts
|
|
267
267
|
case type
|
|
268
268
|
when :except
|
|
269
269
|
hosts_to_modify = if criteria and (not criteria.empty?)
|
|
270
|
-
hosts_to_modify - select_hosts(criteria, hosts_to_modify, &
|
|
270
|
+
hosts_to_modify - select_hosts(criteria, hosts_to_modify, &) + hosts_not_modified
|
|
271
271
|
else
|
|
272
272
|
# confining to all hosts *except* provided array of hosts
|
|
273
273
|
hosts_not_modified
|
|
@@ -278,7 +278,7 @@ module Beaker
|
|
|
278
278
|
end
|
|
279
279
|
when :to
|
|
280
280
|
if criteria and (not criteria.empty?)
|
|
281
|
-
hosts_to_modify = select_hosts(criteria, hosts_to_modify, &
|
|
281
|
+
hosts_to_modify = select_hosts(criteria, hosts_to_modify, &) + hosts_not_modified
|
|
282
282
|
else
|
|
283
283
|
# confining to only hosts in provided array of hosts
|
|
284
284
|
end
|
|
@@ -26,11 +26,11 @@ module Aix::Group
|
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def group_present(name, &
|
|
30
|
-
execute("if ! lsgroup #{name}; then mkgroup #{name}; fi", {}, &
|
|
29
|
+
def group_present(name, &)
|
|
30
|
+
execute("if ! lsgroup #{name}; then mkgroup #{name}; fi", {}, &)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def group_absent(name, &
|
|
34
|
-
execute("if lsgroup #{name}; then rmgroup #{name}; fi", {}, &
|
|
33
|
+
def group_absent(name, &)
|
|
34
|
+
execute("if lsgroup #{name}; then rmgroup #{name}; fi", {}, &)
|
|
35
35
|
end
|
|
36
36
|
end
|
data/lib/beaker/host/aix/user.rb
CHANGED
|
@@ -23,11 +23,11 @@ module Aix::User
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def user_present(name, &
|
|
27
|
-
execute("if ! lsuser #{name}; then mkuser #{name}; fi", {}, &
|
|
26
|
+
def user_present(name, &)
|
|
27
|
+
execute("if ! lsuser #{name}; then mkuser #{name}; fi", {}, &)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def user_absent(name, &
|
|
31
|
-
execute("if lsuser #{name}; then rmuser #{name}; fi", {}, &
|
|
30
|
+
def user_absent(name, &)
|
|
31
|
+
execute("if lsuser #{name}; then rmuser #{name}; fi", {}, &)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -83,8 +83,8 @@ module Mac::Group
|
|
|
83
83
|
#
|
|
84
84
|
# @param [String] name Name of the group
|
|
85
85
|
# @param [Proc] block Additional actions or insertions
|
|
86
|
-
def group_absent(name, &
|
|
87
|
-
execute("if dscl . -list /Groups/#{name}; then dscl . -delete /Groups/#{name}; fi", {}, &
|
|
86
|
+
def group_absent(name, &)
|
|
87
|
+
execute("if dscl . -list /Groups/#{name}; then dscl . -delete /Groups/#{name}; fi", {}, &)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
# Gives the next gid not used on the system
|
data/lib/beaker/host/mac/user.rb
CHANGED
|
@@ -66,8 +66,8 @@ module Mac::User
|
|
|
66
66
|
#
|
|
67
67
|
# @param [String] name Name of the user
|
|
68
68
|
# @param [Proc] block Additional actions or insertions
|
|
69
|
-
def user_absent(name, &
|
|
70
|
-
execute("if dscl . -list /Users/#{name}; then dscl . -delete /Users/#{name}; fi", {}, &
|
|
69
|
+
def user_absent(name, &)
|
|
70
|
+
execute("if dscl . -list /Users/#{name}; then dscl . -delete /Users/#{name}; fi", {}, &)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Gives the next uid not used on the system
|
|
@@ -27,11 +27,11 @@ module PSWindows::Group
|
|
|
27
27
|
raise NotImplementedError, "Can't retrieve group gid on a Windows host"
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def group_present(name, &
|
|
31
|
-
execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
30
|
+
def group_present(name, &)
|
|
31
|
+
execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def group_absent(name, &
|
|
35
|
-
execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
34
|
+
def group_absent(name, &)
|
|
35
|
+
execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -23,11 +23,11 @@ module PSWindows::User
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def user_present(name, &
|
|
27
|
-
execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
26
|
+
def user_present(name, &)
|
|
27
|
+
execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def user_absent(name, &
|
|
31
|
-
execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
30
|
+
def user_absent(name, &)
|
|
31
|
+
execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -31,11 +31,11 @@ module Unix::Group
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def group_present(name, &
|
|
35
|
-
execute("if ! getent group #{name}; then groupadd #{name}; fi", {}, &
|
|
34
|
+
def group_present(name, &)
|
|
35
|
+
execute("if ! getent group #{name}; then groupadd #{name}; fi", {}, &)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def group_absent(name, &
|
|
39
|
-
execute("if getent group #{name}; then groupdel #{name}; fi", {}, &
|
|
38
|
+
def group_absent(name, &)
|
|
39
|
+
execute("if getent group #{name}; then groupdel #{name}; fi", {}, &)
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -23,11 +23,11 @@ module Unix::User
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def user_present(name, &
|
|
27
|
-
execute("if ! getent passwd #{name}; then useradd #{name}; fi", {}, &
|
|
26
|
+
def user_present(name, &)
|
|
27
|
+
execute("if ! getent passwd #{name}; then useradd #{name}; fi", {}, &)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def user_absent(name, &
|
|
31
|
-
execute("if getent passwd #{name}; then userdel #{name}; fi", {}, &
|
|
30
|
+
def user_absent(name, &)
|
|
31
|
+
execute("if getent passwd #{name}; then userdel #{name}; fi", {}, &)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -41,11 +41,11 @@ module Windows::Group
|
|
|
41
41
|
raise NotImplementedError, "Can't retrieve group gid on a Windows host"
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def group_present(name, &
|
|
45
|
-
execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
44
|
+
def group_present(name, &)
|
|
45
|
+
execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def group_absent(name, &
|
|
49
|
-
execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
48
|
+
def group_absent(name, &)
|
|
49
|
+
execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -37,11 +37,11 @@ module Windows::User
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def user_present(name, &
|
|
41
|
-
execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
40
|
+
def user_present(name, &)
|
|
41
|
+
execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def user_absent(name, &
|
|
45
|
-
execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &
|
|
44
|
+
def user_absent(name, &)
|
|
45
|
+
execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &)
|
|
46
46
|
end
|
|
47
47
|
end
|
data/lib/beaker/logger.rb
CHANGED
data/lib/beaker/logger_junit.rb
CHANGED
|
@@ -120,34 +120,21 @@ module Beaker
|
|
|
120
120
|
self.escape_invalid_xml_chars(Logger.strip_color_codes(string))
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
-
# Every character {is_valid_xml} rejects, as one pattern. Note that this
|
|
124
|
-
# tracks that method rather than the specification it cites: #xD is absent
|
|
125
|
-
# from both, and both take the last range as 0x100000 rather than the
|
|
126
|
-
# 0x10000 the specification gives. Changing either would change the
|
|
127
|
-
# contents of every junit report, so they are left alone here and the specs
|
|
128
|
-
# walk the whole range to keep the two in step.
|
|
129
|
-
INVALID_XML_CHARS = /[^\u{9}\u{A}\u{20}-\u{D7FF}\u{E000}-\u{FFFD}\u{100000}-\u{10FFFF}]/
|
|
130
|
-
|
|
131
123
|
# Escape invalid XML UTF-8 codes from provided string, see http://www.w3.org/TR/xml/#charsets for valid
|
|
132
124
|
# character specification
|
|
133
125
|
# @param [String] string The string to remove invalid codes from
|
|
134
126
|
# @return [String] Properly escaped string
|
|
135
127
|
def self.escape_invalid_xml_chars string
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# an array and joining it back into a string just to read its codepoint.
|
|
147
|
-
# That is around four objects per character, and it runs over the whole
|
|
148
|
-
# sublog of every test case at the end of a run: 28 million objects, and
|
|
149
|
-
# 98MB of permanently grown ruby heap, for a 6MB suite.
|
|
150
|
-
string.gsub(INVALID_XML_CHARS) { |char| "\\#{char.ord}" }
|
|
128
|
+
escaped_string = ""
|
|
129
|
+
string.chars.each do |i|
|
|
130
|
+
char_as_codestring = i.unpack("U*").join
|
|
131
|
+
escaped_string << if self.is_valid_xml(char_as_codestring.to_i)
|
|
132
|
+
i
|
|
133
|
+
else
|
|
134
|
+
"\\#{char_as_codestring}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
escaped_string
|
|
151
138
|
end
|
|
152
139
|
|
|
153
140
|
# Determine if the provided number falls in the range of accepted xml unicode values
|
data/lib/beaker/platform.rb
CHANGED
data/lib/beaker/result.rb
CHANGED
|
@@ -31,24 +31,10 @@ module Beaker
|
|
|
31
31
|
return string.gsub(/\r\n?/, "\n")
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
raise TypeError, "Beaker::Result#convert cannot convert nil to a String" if string.nil?
|
|
39
|
-
|
|
40
|
-
unless string.instance_of?(String)
|
|
41
|
-
# For a string subclass, `string.to_s` returns a copy, so calling
|
|
42
|
-
# `force_encoding` on it was meaningless.
|
|
43
|
-
return string.to_s.scrub('')
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Data collected from the connection is binary (ASCII-8BIT). In that
|
|
47
|
-
# encoding, every byte is a valid character, so we tag the string as UTF-8
|
|
48
|
-
string.force_encoding('UTF-8')
|
|
49
|
-
|
|
50
|
-
# And remove invalid and undefined UTF-8 character encodings.
|
|
51
|
-
string.scrub('')
|
|
34
|
+
def convert string
|
|
35
|
+
# Remove invalid and undefined UTF-8 character encodings
|
|
36
|
+
string.to_s.force_encoding('UTF-8')
|
|
37
|
+
string.to_s.chars.select { |i| i.valid_encoding? }.join
|
|
52
38
|
end
|
|
53
39
|
|
|
54
40
|
def log(logger)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Beaker
|
|
2
2
|
module Shared
|
|
3
3
|
module Repetition
|
|
4
|
-
def repeat_for
|
|
4
|
+
def repeat_for(seconds, &)
|
|
5
5
|
# do not peg CPU if &block takes less than 1 second
|
|
6
|
-
repeat_for_and_wait
|
|
6
|
+
repeat_for_and_wait(seconds, 1, &)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def repeat_for_and_wait seconds, wait
|
|
@@ -29,14 +29,14 @@ module Beaker
|
|
|
29
29
|
# Sets up the predefine task checking
|
|
30
30
|
# @param args [Array] First argument is always the name of the task
|
|
31
31
|
# if no additonal arguments are defined such as parameters it will default to [:hosts,:type]
|
|
32
|
-
def initialize(*args, &
|
|
32
|
+
def initialize(*args, &)
|
|
33
33
|
super
|
|
34
34
|
|
|
35
35
|
@name = args.shift || 'beaker:test'
|
|
36
36
|
args = %i[hosts type] if args.empty?
|
|
37
37
|
@acceptance_root = DEFAULT_ACCEPTANCE_ROOT
|
|
38
38
|
@options_file = nil
|
|
39
|
-
define(args, &
|
|
39
|
+
define(args, &)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
private
|
data/lib/beaker/version.rb
CHANGED
|
@@ -380,14 +380,14 @@ describe Beaker do
|
|
|
380
380
|
let(:cygwin) { true }
|
|
381
381
|
let(:cat) { "cat /cygdrive/c/Windows/System32/drivers/etc/hosts" }
|
|
382
382
|
|
|
383
|
-
|
|
383
|
+
it_behaves_like 'find domain name'
|
|
384
384
|
end
|
|
385
385
|
|
|
386
386
|
context "without cygwin" do
|
|
387
387
|
let(:cygwin) { false }
|
|
388
388
|
let(:cat) { 'type C:\Windows\System32\drivers\etc\hosts' }
|
|
389
389
|
|
|
390
|
-
|
|
390
|
+
it_behaves_like 'find domain name'
|
|
391
391
|
end
|
|
392
392
|
end
|
|
393
393
|
|
|
@@ -399,25 +399,25 @@ describe Beaker do
|
|
|
399
399
|
context "with a domain entry" do
|
|
400
400
|
let(:stdout) { "domain labs.lan d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" }
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
it_behaves_like 'find domain name'
|
|
403
403
|
end
|
|
404
404
|
|
|
405
405
|
context "with a search entry" do
|
|
406
406
|
let(:stdout) { "search labs.lan d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" }
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
it_behaves_like 'find domain name'
|
|
409
409
|
end
|
|
410
410
|
|
|
411
411
|
context "with a both a domain and a search entry" do
|
|
412
412
|
let(:stdout) { "domain labs.lan\nsearch d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" }
|
|
413
413
|
|
|
414
|
-
|
|
414
|
+
it_behaves_like 'find domain name'
|
|
415
415
|
end
|
|
416
416
|
|
|
417
417
|
context "with a both a domain and a search entry, the search entry first" do
|
|
418
418
|
let(:stdout) { "search foo.example.net\ndomain labs.lan d.labs.net dc1.labs.net labs.com\nnameserver 10.16.22.10\nnameserver 10.16.22.11" }
|
|
419
419
|
|
|
420
|
-
|
|
420
|
+
it_behaves_like 'find domain name'
|
|
421
421
|
end
|
|
422
422
|
end
|
|
423
423
|
end
|
|
@@ -32,42 +32,6 @@ module Beaker
|
|
|
32
32
|
testing_string = 'pants man, pants!'
|
|
33
33
|
expect(described_class.escape_invalid_xml_chars(testing_string)).to be === testing_string
|
|
34
34
|
end
|
|
35
|
-
|
|
36
|
-
it 'escapes carriage returns, which is_valid_xml does not accept' do
|
|
37
|
-
expect(described_class.escape_invalid_xml_chars("a\rb")).to be === 'a\13b'
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'agrees with is_valid_xml on every codepoint' do
|
|
41
|
-
# INVALID_XML_CHARS has to track is_valid_xml rather than the spec that
|
|
42
|
-
# method cites, so walk the whole range instead of trusting either.
|
|
43
|
-
codepoints = (0..0xD7FF).to_a + (0xE000..0x10FFFF).to_a # surrogates cannot be in a String
|
|
44
|
-
codepoints.each_slice(50_000) do |slice|
|
|
45
|
-
string = slice.map { |c| c.chr(Encoding::UTF_8) }.join
|
|
46
|
-
expected = slice.map { |c| described_class.is_valid_xml(c) ? c.chr(Encoding::UTF_8) : "\\#{c}" }.join
|
|
47
|
-
expect(described_class.escape_invalid_xml_chars(string)).to eq(expected)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it 'drops invalid encodings rather than raising' do
|
|
52
|
-
# TestSuiteResult calls format_cdata from inside a blanket rescue that
|
|
53
|
-
# abandons the whole junit document, so an exception raised here would
|
|
54
|
-
# cost the run its entire test report.
|
|
55
|
-
expect(described_class.escape_invalid_xml_chars("ok\xFFbad".b)).to eq('okbad')
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'accepts a frozen string' do
|
|
59
|
-
expect(described_class.escape_invalid_xml_chars('pants'.freeze)).to eq('pants')
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
describe '#format_cdata' do
|
|
64
|
-
it 'strips colour codes and escapes what is left' do
|
|
65
|
-
expect(described_class.format_cdata("\e[00;33mpants\e[00;00m")).to eq('pants')
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'survives invalid encodings' do
|
|
69
|
-
expect(described_class.format_cdata("\e[00;33mok\xFFbad".b)).to eq('okbad')
|
|
70
|
-
end
|
|
71
35
|
end
|
|
72
36
|
|
|
73
37
|
describe '#copy_stylesheet_into_xml_dir' do
|
data/spec/beaker/logger_spec.rb
CHANGED
|
@@ -24,24 +24,6 @@ module Beaker
|
|
|
24
24
|
valid_utf8.freeze
|
|
25
25
|
expect(logger.convert(valid_utf8)).to be === valid_utf8
|
|
26
26
|
end
|
|
27
|
-
|
|
28
|
-
it 'leaves the string it was given alone' do
|
|
29
|
-
expect(logger.convert(invalid_utf8)).not_to equal(invalid_utf8)
|
|
30
|
-
expect(invalid_utf8.bytes).to include(0xAD)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it 'converts each item of an array' do
|
|
34
|
-
expect(logger.convert([valid_utf8, invalid_utf8])).to eq([valid_utf8, valid_utf8])
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'converts arrays of arrays' do
|
|
38
|
-
expect(logger.convert([[invalid_utf8], valid_utf8])).to eq([[valid_utf8], valid_utf8])
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it 'converts anything that can describe itself' do
|
|
42
|
-
expect(logger.convert(42)).to eq('42')
|
|
43
|
-
expect(logger.convert(nil)).to eq('')
|
|
44
|
-
end
|
|
45
27
|
end
|
|
46
28
|
|
|
47
29
|
describe '#generate_dated_log_folder' do
|
|
@@ -78,11 +78,6 @@ module Beaker
|
|
|
78
78
|
expect(platform.with_version_codename).to be === 'debian-bullseye-xxx'
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
it "can convert ubuntu-2604-xxx to ubuntu-resolute-xxx" do
|
|
82
|
-
@name = 'ubuntu-2604-xxx'
|
|
83
|
-
expect(platform.with_version_codename).to be === 'ubuntu-resolute-xxx'
|
|
84
|
-
end
|
|
85
|
-
|
|
86
81
|
it "can convert ubuntu-2404-xxx to ubuntu-noble-xxx" do
|
|
87
82
|
@name = 'ubuntu-2404-xxx'
|
|
88
83
|
expect(platform.with_version_codename).to be === 'ubuntu-noble-xxx'
|
|
@@ -127,11 +122,6 @@ module Beaker
|
|
|
127
122
|
expect(platform.with_version_number).to be === 'ubuntu-2204-xxx'
|
|
128
123
|
end
|
|
129
124
|
|
|
130
|
-
it "can convert ubuntu-resolute-xxx to ubuntu-2604-xxx" do
|
|
131
|
-
@name = 'ubuntu-resolute-xxx'
|
|
132
|
-
expect(platform.with_version_number).to be === 'ubuntu-2604-xxx'
|
|
133
|
-
end
|
|
134
|
-
|
|
135
125
|
%w[centos redhat].each do |p|
|
|
136
126
|
it "leaves #{p}-7-xxx alone" do
|
|
137
127
|
@name = "#{p}-7-xxx"
|
|
@@ -150,7 +140,7 @@ module Beaker
|
|
|
150
140
|
if YAML.respond_to?(:unsafe_load)
|
|
151
141
|
YAML.unsafe_load(YAML.dump(platform))
|
|
152
142
|
else
|
|
153
|
-
YAML.load(YAML.dump(platform))
|
|
143
|
+
YAML.load(YAML.dump(platform))
|
|
154
144
|
end
|
|
155
145
|
end
|
|
156
146
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: beaker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 7.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Puppet
|
|
@@ -63,14 +63,14 @@ dependencies:
|
|
|
63
63
|
requirements:
|
|
64
64
|
- - "~>"
|
|
65
65
|
- !ruby/object:Gem::Version
|
|
66
|
-
version:
|
|
66
|
+
version: 4.1.0
|
|
67
67
|
type: :development
|
|
68
68
|
prerelease: false
|
|
69
69
|
version_requirements: !ruby/object:Gem::Requirement
|
|
70
70
|
requirements:
|
|
71
71
|
- - "~>"
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
|
-
version:
|
|
73
|
+
version: 4.1.0
|
|
74
74
|
- !ruby/object:Gem::Dependency
|
|
75
75
|
name: base64
|
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -327,14 +327,14 @@ dependencies:
|
|
|
327
327
|
requirements:
|
|
328
328
|
- - "~>"
|
|
329
329
|
- !ruby/object:Gem::Version
|
|
330
|
-
version: '
|
|
330
|
+
version: '3.0'
|
|
331
331
|
type: :runtime
|
|
332
332
|
prerelease: false
|
|
333
333
|
version_requirements: !ruby/object:Gem::Requirement
|
|
334
334
|
requirements:
|
|
335
335
|
- - "~>"
|
|
336
336
|
- !ruby/object:Gem::Version
|
|
337
|
-
version: '
|
|
337
|
+
version: '3.0'
|
|
338
338
|
- !ruby/object:Gem::Dependency
|
|
339
339
|
name: stringify-hash
|
|
340
340
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -659,7 +659,6 @@ files:
|
|
|
659
659
|
- spec/beaker/options/validator_spec.rb
|
|
660
660
|
- spec/beaker/perf_spec.rb
|
|
661
661
|
- spec/beaker/platform_spec.rb
|
|
662
|
-
- spec/beaker/result_spec.rb
|
|
663
662
|
- spec/beaker/shared/error_handler_spec.rb
|
|
664
663
|
- spec/beaker/shared/fog_credentials_spec.rb
|
|
665
664
|
- spec/beaker/shared/host_manager_spec.rb
|
|
@@ -686,14 +685,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
686
685
|
requirements:
|
|
687
686
|
- - ">="
|
|
688
687
|
- !ruby/object:Gem::Version
|
|
689
|
-
version: '2
|
|
688
|
+
version: '3.2'
|
|
690
689
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
691
690
|
requirements:
|
|
692
691
|
- - ">="
|
|
693
692
|
- !ruby/object:Gem::Version
|
|
694
693
|
version: '0'
|
|
695
694
|
requirements: []
|
|
696
|
-
rubygems_version:
|
|
695
|
+
rubygems_version: 3.6.9
|
|
697
696
|
specification_version: 4
|
|
698
697
|
summary: Let's test Puppet!
|
|
699
698
|
test_files: []
|
data/spec/beaker/result_spec.rb
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module Beaker
|
|
4
|
-
describe Result do
|
|
5
|
-
subject(:result) { described_class.new(host, cmd) }
|
|
6
|
-
|
|
7
|
-
let(:host) { 'my_host' }
|
|
8
|
-
let(:cmd) { 'ls -la' }
|
|
9
|
-
|
|
10
|
-
# Command output reaches a Result the way net-ssh hands it over: as chunks
|
|
11
|
-
# of binary data, appended as they arrive.
|
|
12
|
-
def binary(string)
|
|
13
|
-
string.dup.force_encoding('ASCII-8BIT')
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
describe '#initialize' do
|
|
17
|
-
it 'starts with empty streams and no exit code' do
|
|
18
|
-
expect(result.stdout).to eq('')
|
|
19
|
-
expect(result.stderr).to eq('')
|
|
20
|
-
expect(result.output).to eq('')
|
|
21
|
-
expect(result.exit_code).to be_nil
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe '#convert' do
|
|
26
|
-
let(:valid_utf8) { "modules\n├── jimmy-appleseed (v1.1.0)\n└── jimmy-crakorn (v0.4.0)\n" }
|
|
27
|
-
|
|
28
|
-
it 'preserves valid utf-8' do
|
|
29
|
-
expect(result.convert(valid_utf8.dup)).to eq(valid_utf8)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'strips invalid utf-8 byte sequences' do
|
|
33
|
-
expect(result.convert(binary("ok\xFFbad"))).to eq('okbad')
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it 'strips a truncated multi-byte sequence' do
|
|
37
|
-
expect(result.convert(binary("ok\xE3\x81"))).to eq('ok')
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'returns utf-8 whatever encoding it was handed' do
|
|
41
|
-
expect(result.convert(binary('plain')).encoding).to eq(Encoding::UTF_8)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it 'modifies the argument encoding in place' do
|
|
45
|
-
string = binary('plain')
|
|
46
|
-
result.convert(string)
|
|
47
|
-
expect(string.encoding).to eq(Encoding::UTF_8)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'returns a new string rather than scrubbing the one it was given' do
|
|
51
|
-
string = binary("ok\xFFbad")
|
|
52
|
-
expect(result.convert(string)).not_to equal(string)
|
|
53
|
-
expect(string.bytes).to include(0xFF)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
context 'when handed String subclass' do
|
|
57
|
-
let(:string_subclass) { Class.new(String) }
|
|
58
|
-
|
|
59
|
-
it 'accepts String subclass' do
|
|
60
|
-
expect(result.convert(string_subclass.new('plain'))).to eq('plain')
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'leaves invalid encodings in place, as it always has' do
|
|
64
|
-
subclass = string_subclass.new(binary("ok\xFFbad"))
|
|
65
|
-
expect(result.convert(subclass).bytes).to include(0xFF)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'converts anything else that can describe itself' do
|
|
69
|
-
expect(result.convert(5)).to eq('5')
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it 'raises TypeError on nil' do
|
|
73
|
-
expect { result.convert(nil) }.to raise_error(TypeError, /cannot convert nil to a String/)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
describe '#normalize_line_endings' do
|
|
79
|
-
it 'converts crlf to lf' do
|
|
80
|
-
expect(result.normalize_line_endings("a\r\nb")).to eq("a\nb")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it 'converts a lone cr to lf' do
|
|
84
|
-
expect(result.normalize_line_endings("a\rb")).to eq("a\nb")
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it 'leaves lf alone' do
|
|
88
|
-
expect(result.normalize_line_endings("a\nb")).to eq("a\nb")
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
describe '#finalize!' do
|
|
93
|
-
before do
|
|
94
|
-
result.stdout << binary("out\xFF\r\n")
|
|
95
|
-
result.stderr << binary("err\xFF\r\n")
|
|
96
|
-
result.output << binary("out\xFF\r\nerr\xFF\r\n")
|
|
97
|
-
result.finalize!
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it 'scrubs and normalizes every stream' do
|
|
101
|
-
expect(result.stdout).to eq("out\n")
|
|
102
|
-
expect(result.stderr).to eq("err\n")
|
|
103
|
-
expect(result.output).to eq("out\nerr\n")
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it 'keeps the unscrubbed bytes in the raw_ attributes' do
|
|
107
|
-
expect(result.raw_stdout.bytes).to include(0xFF)
|
|
108
|
-
expect(result.raw_stderr.bytes).to include(0xFF)
|
|
109
|
-
expect(result.raw_output.bytes).to include(0xFF)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it 'leaves the raw_ line endings alone' do
|
|
113
|
-
expect(result.raw_stdout).to include("\r\n")
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
describe '#formatted_output' do
|
|
118
|
-
before do
|
|
119
|
-
result.output << (1..15).map { |i| "line #{i}" }.join("\n")
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it 'returns the last ten lines by default, tab indented' do
|
|
123
|
-
expect(result.formatted_output).to eq((6..15).map { |i| "\tline #{i}" }.join("\n"))
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'honours a limit' do
|
|
127
|
-
expect(result.formatted_output(2)).to eq("\tline 14\n\tline 15")
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
describe '#exit_code_in?' do
|
|
132
|
-
it 'is true when the exit code is in the range' do
|
|
133
|
-
result.exit_code = 2
|
|
134
|
-
expect(result.exit_code_in?([0, 2])).to be true
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
it 'is false when it is not' do
|
|
138
|
-
result.exit_code = 1
|
|
139
|
-
expect(result.exit_code_in?([0, 2])).to be false
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
describe '#success?' do
|
|
144
|
-
it 'is true only for an exit code of zero' do
|
|
145
|
-
result.exit_code = 0
|
|
146
|
-
expect(result).to be_success
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
it 'is false for a non-zero exit code' do
|
|
150
|
-
result.exit_code = 1
|
|
151
|
-
expect(result).not_to be_success
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
it 'is false when no exit code was collected' do
|
|
155
|
-
expect(result).not_to be_success
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
describe '#log' do
|
|
160
|
-
let(:logger) { instance_double(Beaker::Logger) }
|
|
161
|
-
|
|
162
|
-
it 'reports a non-zero exit code' do
|
|
163
|
-
result.exit_code = 1
|
|
164
|
-
expect(logger).to receive(:debug).with('Exited: 1')
|
|
165
|
-
result.log(logger)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
it 'says nothing for a successful command' do
|
|
169
|
-
result.exit_code = 0
|
|
170
|
-
expect(logger).not_to receive(:debug)
|
|
171
|
-
result.log(logger)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
it 'says nothing when no exit code was collected' do
|
|
175
|
-
expect(logger).not_to receive(:debug)
|
|
176
|
-
result.log(logger)
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
describe NullResult do
|
|
182
|
-
subject(:result) { described_class.new('my_host', 'ls -la') }
|
|
183
|
-
|
|
184
|
-
it 'succeeds without having run anything' do
|
|
185
|
-
expect(result.exit_code).to eq(0)
|
|
186
|
-
expect(result).to be_success
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|