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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f34a28e10b3448ee6294cdfd53903ec145d6c81d28b95dc7370a30936922e80c
4
- data.tar.gz: 7e7ba934516ed374c96c97357047d56693dddbd23a45be3a6b088b5dcdbae52a
3
+ metadata.gz: a52a04e5317c78954859cef26c1988cf66a832ad0f62de9d78c69ffbe23c108c
4
+ data.tar.gz: 4de10d9e282aaa62986410393d440278c5821d042505436131ba5d6ac92a2fdd
5
5
  SHA512:
6
- metadata.gz: b7a2345337cec50941ba9aa8c20a8f4cfab3bd0c84e1bb74f0e8c506ff29f894568562c423aa815fcaaf16b423dbde3150117a579c3463481802b91d3bb159eb
7
- data.tar.gz: ba81525b5f025ad793d7175b694a2a95702af799282ddcec8f060e3c4e0badd5ded71a905b2239c7230d4161056c0a9a69511fd7e318eb675605bcfde0aa3aa5
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@v4
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@v4
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@v4
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@v4
95
+ uses: actions/download-artifact@v5
96
96
  with:
97
97
  name: gem-artifact
98
98
  - name: Install Ruby
data/.rubocop.yml CHANGED
@@ -4,6 +4,9 @@ inherit_from: .rubocop_todo.yml
4
4
  inherit_gem:
5
5
  voxpupuli-rubocop: rubocop.yml
6
6
 
7
+ AllCops:
8
+ TargetRubyVersion: 3.2
9
+
7
10
  Layout/LineLength:
8
11
  Exclude:
9
12
  - acceptance/**/*.rb
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.7.
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: 104
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
- ## [6.9.0](https://github.com/voxpupuli/beaker/tree/6.9.0) (2026-08-14)
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...6.9.0)
5
+ [Full Changelog](https://github.com/voxpupuli/beaker/compare/6.8.1...7.0.0)
6
6
 
7
- **Implemented enhancements:**
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
- - Ensure correct encoding for logging and fix performance bugs [\#2027](https://github.com/voxpupuli/beaker/pull/2027) ([bastelfreak](https://github.com/bastelfreak))
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
- **Closed issues:**
11
+ **Implemented enhancements:**
18
12
 
19
- - The tmpfile method in pswindows needs to implement the use of the extension parameter [\#1955](https://github.com/voxpupuli/beaker/issues/1955)
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 = '6.x'
195
- config.exclude_tags_regex = /^v?[4,7]\./
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.7')
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', '~> 3.1.0'
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', '~> 2.0'
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 = {}, &block)
122
- on(default, command, opts, &block)
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 = {}, &block)
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 host, remote_path, opts, &block
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 = {}, &block)
326
- run_script_on(default, script, opts, &block)
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 = {}, &block)
519
- on host, "curl --tlsv1 %s" % cmd, opts, &block
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 = {}, &block)
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 host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &block
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 host, command, { :accept_all_exit_codes => true, :silent => !verbose }, &block
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)
@@ -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 hosts_or_filter, opts = {}, &block
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 block_hosts, filter, opts, &block
36
+ run_block_on(block_hosts, filter, opts, &)
37
37
  end
38
38
  end
39
39
  end
@@ -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 manual_test_name, &block
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 manual_test_name, &block
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, &block)
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, &block) + hosts_not_modified
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, &block) + hosts_not_modified
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, &block)
30
- execute("if ! lsgroup #{name}; then mkgroup #{name}; fi", {}, &block)
29
+ def group_present(name, &)
30
+ execute("if ! lsgroup #{name}; then mkgroup #{name}; fi", {}, &)
31
31
  end
32
32
 
33
- def group_absent(name, &block)
34
- execute("if lsgroup #{name}; then rmgroup #{name}; fi", {}, &block)
33
+ def group_absent(name, &)
34
+ execute("if lsgroup #{name}; then rmgroup #{name}; fi", {}, &)
35
35
  end
36
36
  end
@@ -23,11 +23,11 @@ module Aix::User
23
23
  end
24
24
  end
25
25
 
26
- def user_present(name, &block)
27
- execute("if ! lsuser #{name}; then mkuser #{name}; fi", {}, &block)
26
+ def user_present(name, &)
27
+ execute("if ! lsuser #{name}; then mkuser #{name}; fi", {}, &)
28
28
  end
29
29
 
30
- def user_absent(name, &block)
31
- execute("if lsuser #{name}; then rmuser #{name}; fi", {}, &block)
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, &block)
87
- execute("if dscl . -list /Groups/#{name}; then dscl . -delete /Groups/#{name}; fi", {}, &block)
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
@@ -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, &block)
70
- execute("if dscl . -list /Users/#{name}; then dscl . -delete /Users/#{name}; fi", {}, &block)
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, &block)
31
- execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
35
- execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
27
- execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
31
- execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
35
- execute("if ! getent group #{name}; then groupadd #{name}; fi", {}, &block)
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, &block)
39
- execute("if getent group #{name}; then groupdel #{name}; fi", {}, &block)
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, &block)
27
- execute("if ! getent passwd #{name}; then useradd #{name}; fi", {}, &block)
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, &block)
31
- execute("if getent passwd #{name}; then userdel #{name}; fi", {}, &block)
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, &block)
45
- execute("net localgroup /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
49
- execute("net localgroup /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
41
- execute("net user /add \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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, &block)
45
- execute("net user /delete \"#{name}\"", { :acceptable_exit_codes => [0, 2] }, &block)
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
@@ -197,7 +197,7 @@ module Beaker
197
197
  else
198
198
  # Remove invalid and undefined UTF-8 character encodings
199
199
  string = string.to_s.dup.force_encoding('UTF-8')
200
- string.scrub('')
200
+ return string.to_s.chars.select { |i| i.valid_encoding? }.join
201
201
  end
202
202
  end
203
203
 
@@ -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
- # Bytes that are not valid in their own encoding cannot be represented in
137
- # xml at all, and would make the gsub below raise. Drop them, the same
138
- # way Logger#convert does further upstream. Raising matters more here
139
- # than it might look: TestSuiteResult calls #format_cdata from inside a
140
- # blanket rescue that abandons the whole junit document, so one stray
141
- # byte in one sublog loses every test result for the run.
142
- string = string.dup.force_encoding(Encoding::UTF_8) unless string.encoding == Encoding::UTF_8
143
- string = string.scrub('') unless string.valid_encoding?
144
-
145
- # This walked the string a character at a time, unpacking each one into
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
@@ -11,8 +11,7 @@ module Beaker
11
11
  "bookworm" => "12",
12
12
  "bullseye" => "11",
13
13
  "buster" => "10", },
14
- :ubuntu => { "resolute" => "2604",
15
- "noble" => "2404",
14
+ :ubuntu => { "noble" => "2404",
16
15
  "jammy" => "2204",
17
16
  "focal" => "2004",
18
17
  "bionic" => "1804", },
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
- # This method behaves differently when given a string instance, subclass
35
- # or something else. The latter two cases should be deprecated.
36
- def convert(string)
37
- # guard against nil, which never worked on accident
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 seconds, &block
4
+ def repeat_for(seconds, &)
5
5
  # do not peg CPU if &block takes less than 1 second
6
- repeat_for_and_wait seconds, 1, &block
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, &task_block)
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, &task_block)
39
+ define(args, &)
40
40
  end
41
41
 
42
42
  private
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '6.9.0'
3
+ STRING = '7.0.0'
4
4
  end
5
5
  end
@@ -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
- include_examples 'find domain name'
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
- include_examples 'find domain name'
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
- include_examples 'find domain name'
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
- include_examples 'find domain name'
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
- include_examples 'find domain name'
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
- include_examples 'find domain name'
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
@@ -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)) # rubocop:disable Security/YAMLLoad
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: 6.9.0
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: 3.1.0
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: 3.1.0
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: '2.0'
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: '2.0'
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.7'
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: 4.0.16
695
+ rubygems_version: 3.6.9
697
696
  specification_version: 4
698
697
  summary: Let's test Puppet!
699
698
  test_files: []
@@ -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