beaker 4.22.1 → 4.23.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: 0a089feb0e8311631a3778e1839e5942694ec2e9f14bb873fbfb07d5ae854bca
4
- data.tar.gz: b0e75901ec90f523a2b2f276658e8ede706a0fb3df3f09fcd58779263a28d630
3
+ metadata.gz: 90b746c013603a55023f75c05cfa79a8301fa58729b82a1dcc677067dde77ab1
4
+ data.tar.gz: f76631826758f41afb1517224fed593bdf988278bb1c18a23dd6ddea0d74ca8a
5
5
  SHA512:
6
- metadata.gz: bfb8cfe1965440e36c4e8093548a454c0de51100d1ec5c4a5d001c083fc20aa5b2715301abba1b2a4ddb3425701c51298e4cbcb41f965896a41f59c003c2b97d
7
- data.tar.gz: 39fb8a21b0e289c81b8967deb089bb50418a726d0bec337cec4ad6230d4b5ce3587b37c2ee1144cef61d1f944b77df1a1f6cc0a2ae79c9214efe66c55dcd463a
6
+ metadata.gz: 24dc7d2592f0de06a51a6534f9f0014a5075851295926c696b5fd0d2ea835f7f95bf4f630f12c91f645fccf33ab43eb3acb8fe33fd1a841e0ae4bd52a529e3a8
7
+ data.tar.gz: 9556e24844dd480c3bab6b30bb6e29db3b34ae4e6a76fd53f47c76fb018d805804eb1e2de87a6798850e1880ea5960cfd90902a99856caff8284f172f0b5f4f6
@@ -20,7 +20,24 @@ The headers used in [Keep a Changelog](http://keepachangelog.com) are:
20
20
  - Fixed - for any bug fixes.
21
21
  - Security - in case of vulnerabilities.
22
22
 
23
- # [Unreleased](https://github.com/puppetlabs/beaker/compare/4.22.1...master)
23
+ # [Unreleased](https://github.com/puppetlabs/beaker/compare/4.23.0...master)
24
+
25
+ # [4.23.0](https://github.com/puppetlabs/beaker/compare/4.22.1...4.23.0)
26
+
27
+ ### Added
28
+
29
+ - Relaxed dependency on `net-ssh` to `>= 5` to support newer versions. (#1648)
30
+ - `cat` DSL method added. Works on both Unix and Windows hosts. (#1645)
31
+
32
+ ### Changed
33
+
34
+ - The `mkdir_p` and `mv` commands now double quote their file arguments. (#1644) If you rely on file globbing in these methods or elsewhere, please open an issue on the BEAKER project.
35
+ - Change `reboot` method to use `who -b` for uptime detection (#1643)
36
+
37
+ ### Fixed
38
+
39
+ - Use Base64 UTF-16LE encoding for commands (#1626)
40
+ - Fix `tmpdir` method for Powershell on Windows (#1645)
24
41
 
25
42
  # [4.22.1](https://github.com/puppetlabs/beaker/compare/4.22.0...4.22.1)
26
43
 
@@ -44,7 +44,7 @@ Gem::Specification.new do |s|
44
44
  s.add_runtime_dependency 'rb-readline', '~> 0.5.3'
45
45
 
46
46
  s.add_runtime_dependency 'hocon', '~> 1.0'
47
- s.add_runtime_dependency 'net-ssh', '~> 5.0'
47
+ s.add_runtime_dependency 'net-ssh', '>= 5.0'
48
48
  s.add_runtime_dependency 'net-scp', '~> 1.2'
49
49
  s.add_runtime_dependency 'inifile', '~> 3.0'
50
50
 
@@ -550,7 +550,6 @@ module Beaker
550
550
  file_contents = nil
551
551
 
552
552
  split_path = win_ads_path(file_path)
553
-
554
553
  if file_exists_on(host, split_path[:path])
555
554
  if host['platform'] =~ /windows/
556
555
  file_path.gsub!('/', '\\')
@@ -14,10 +14,11 @@ module Beaker
14
14
 
15
15
  #Determine is a given URL is accessible
16
16
  #@param [String] link The URL to examine
17
- #@return [Boolean] true if the URL has a '200' HTTP response code, false otherwise
17
+ #@param [Integer] limit redirect limit, will follow redirects that many times
18
+ #@return [Boolean] true if the ultimate URL after following redirects (301&302) has a '200' HTTP response code, false otherwise
18
19
  #@example
19
20
  # extension = link_exists?("#{URL}.tar.gz") ? ".tar.gz" : ".tar"
20
- def link_exists?(link)
21
+ def link_exists?(link, limit=10)
21
22
  begin
22
23
  require "net/http"
23
24
  require "net/https"
@@ -26,8 +27,12 @@ module Beaker
26
27
  http = Net::HTTP.new(url.host, url.port)
27
28
  http.use_ssl = (url.scheme == 'https')
28
29
  http.verify_mode = (OpenSSL::SSL::VERIFY_NONE)
29
- http.start do |http|
30
- return http.head(url.request_uri).code == "200"
30
+ response = http.start { |http| http.head(url.request_uri) }
31
+ if (['301', '302'].include? response.code) && limit > 0
32
+ logger.debug("#{__method__} following #{response.code} to #{response['location']}")
33
+ link_exists?(response['location'], limit - 1)
34
+ else
35
+ response.code == "200"
31
36
  end
32
37
  rescue
33
38
  return false
@@ -75,18 +75,14 @@ module Beaker
75
75
  Command.new("powershell.exe", ps_args)
76
76
  end
77
77
 
78
- # Convert the provided command string to Base64
78
+ # Convert the provided command string to Base64 encoded UTF-16LE command
79
79
  # @param [String] cmd The command to convert to Base64
80
80
  # @return [String] The converted string
81
81
  # @api private
82
82
  def encode_command(cmd)
83
- cmd = cmd.chars.to_a.join("\x00").chomp
84
- cmd << "\x00" unless cmd[-1].eql? "\x00"
85
83
  # use strict_encode because linefeeds are not correctly handled in our model
86
- cmd = Base64.strict_encode64(cmd).chomp
87
- cmd
84
+ Base64.strict_encode64(cmd.encode(Encoding::UTF_16LE)).chomp
88
85
  end
89
-
90
86
  end
91
87
  end
92
88
  end
@@ -7,14 +7,23 @@ module PSWindows::File
7
7
  end
8
8
 
9
9
  def tmpdir(name = '')
10
- result = exec(powershell('[System.IO.Path]::GetTempPath()'))
11
- result.stdout.chomp()
10
+ tmp_path = exec(powershell('[System.IO.Path]::GetTempPath()')).stdout.chomp()
11
+
12
+ if name == ''
13
+ name = exec(powershell('[System.IO.Path]::GetRandomFileName()')).stdout.chomp()
14
+ end
15
+ exec(powershell("New-Item -Path '#{tmp_path}' -Force -Name '#{name}' -ItemType 'directory'"))
16
+ File.join(tmp_path, name)
12
17
  end
13
18
 
14
19
  def path_split(paths)
15
20
  paths.split(';')
16
21
  end
17
22
 
23
+ def cat(path)
24
+ exec(powershell("type #{path}"))
25
+ end
26
+
18
27
  def file_exist?(path)
19
28
  result = exec(Beaker::Command.new("if exist #{path} echo true"), :acceptable_exit_codes => [0, 1])
20
29
  result.stdout =~ /true/
@@ -12,20 +12,23 @@ module Unix::Exec
12
12
  #
13
13
  # Will throw an exception RebootFailure if it fails
14
14
  def reboot(wait_time=10, max_connection_tries=9, uptime_retries=18)
15
+ require 'time'
16
+
15
17
  begin
16
- original_uptime = exec(Beaker::Command.new("uptime"))
17
- original_uptime_str = parse_uptime original_uptime.stdout
18
- original_uptime_int = uptime_int original_uptime_str
18
+ original_boot_time_str = exec(Beaker::Command.new('who -b'), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
19
+ original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first
19
20
 
20
- if self['platform'] =~ /solaris/
21
- exec(Beaker::Command.new("reboot"), :expect_connection_failure => true)
22
- else
23
- exec(Beaker::Command.new("/sbin/shutdown -r now"), :expect_connection_failure => true)
24
- end
21
+ raise Beaker::Host::RebootFailure, "Could not find system boot time using 'who -b': #{original_boot_time_str}" unless original_boot_time_line
22
+
23
+ original_boot_time = Time.parse(original_boot_time_line)
24
+
25
+ exec(Beaker::Command.new('/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now'), :expect_connection_failure => true)
25
26
  rescue Beaker::Host::CommandFailure => e
26
27
  raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
27
28
  rescue RuntimeError => e
28
29
  raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
30
+ rescue ArgumentError => e
31
+ raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
29
32
  end
30
33
 
31
34
  attempts = 0
@@ -34,18 +37,19 @@ module Unix::Exec
34
37
  @logger.debug("Waiting #{wait_time} for host to shut down.")
35
38
  sleep wait_time
36
39
 
37
- #use uptime to check if the host has rebooted
38
- current_uptime_exec = exec(Beaker::Command.new("uptime"), {:max_connection_tries => max_connection_tries, :silent => true})
39
- current_uptime = current_uptime_exec.stdout
40
- current_uptime_str = parse_uptime current_uptime
41
- current_uptime_int = uptime_int current_uptime_str
42
- unless original_uptime_int > current_uptime_int
43
- raise Beaker::Host::RebootFailure, "Uptime did not reset. Reboot appears to have failed."
40
+ current_boot_time_str = exec(Beaker::Command.new('who -b'), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
41
+ current_boot_time = Time.parse(current_boot_time_str.lines.grep(/boot/).first)
42
+
43
+ @logger.debug("Original Boot Time: #{original_boot_time}")
44
+ @logger.debug("Current Boot Time: #{current_boot_time}")
45
+
46
+ unless current_boot_time > original_boot_time
47
+ raise Beaker::Host::RebootFailure, "Boot time did not reset. Reboot appears to have failed."
44
48
  end
45
49
  rescue Beaker::Host::RebootFailure => e
46
50
  attempts += 1
47
51
  if attempts < uptime_retries
48
- @logger.debug("Uptime did not reset. Will retry #{uptime_retries - attempts} more times.")
52
+ @logger.debug("Boot time did not reset. Will retry #{uptime_retries - attempts} more times.")
49
53
  retry
50
54
  else
51
55
  raise
@@ -54,6 +58,8 @@ module Unix::Exec
54
58
  raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
55
59
  rescue RuntimeError => e
56
60
  raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
61
+ rescue ArgumentError => e
62
+ raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
57
63
  end
58
64
  end
59
65
 
@@ -127,7 +133,7 @@ module Unix::Exec
127
133
  # @param [String] dir The directory structure to create on the host
128
134
  # @return [Boolean] True, if directory construction succeeded, otherwise False
129
135
  def mkdir_p dir
130
- cmd = "mkdir -p #{dir}"
136
+ cmd = "mkdir -p \"#{dir}\""
131
137
  result = exec(Beaker::Command.new(cmd), :acceptable_exit_codes => [0, 1])
132
138
  result.exit_code == 0
133
139
  end
@@ -144,7 +150,7 @@ module Unix::Exec
144
150
  # @param [Boolean] rm Remove the destination prior to move
145
151
  def mv orig, dest, rm=true
146
152
  rm_rf dest unless !rm
147
- execute("mv #{orig} #{dest}")
153
+ execute("mv \"#{orig}\" \"#{dest}\"")
148
154
  end
149
155
 
150
156
  # Attempt to ping the provided target hostname
@@ -58,6 +58,10 @@ module Unix::File
58
58
  execute("ls -ld #{path}")
59
59
  end
60
60
 
61
+ def cat(path)
62
+ execute("cat #{path}")
63
+ end
64
+
61
65
  # Handles any changes needed in a path for SCP
62
66
  #
63
67
  # @param [String] path File path to SCP to
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '4.22.1'
3
+ STRING = '4.23.0'
4
4
  end
5
5
  end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ module Beaker
4
+ describe PSWindows::File do
5
+ class PSWindowsFileTest
6
+ include PSWindows::File
7
+ include Beaker::DSL::Wrappers
8
+
9
+ def initialize(hash, logger)
10
+ @hash = hash
11
+ @logger = logger
12
+ end
13
+
14
+ def [](k)
15
+ @hash[k]
16
+ end
17
+
18
+ def to_s
19
+ "me"
20
+ end
21
+ end
22
+
23
+ let (:opts) { @opts || {} }
24
+ let (:logger) { double( 'logger' ).as_null_object }
25
+ let (:instance) { PSWindowsFileTest.new(opts, logger) }
26
+
27
+ describe '#cat' do
28
+ it 'reads output for file' do
29
+ path = '/path/to/delete'
30
+ expect(instance).to receive(:exec)
31
+ expect(Beaker::Command).to receive(:new).with('powershell.exe', array_including("-Command type #{path}"))
32
+ instance.cat(path)
33
+ end
34
+ end
35
+
36
+ describe '#tmpdir' do
37
+ let(:tmp_path) { 'C:\\tmpdir\\' }
38
+ let(:fake_command) { Beaker::Command.new('command1') }
39
+
40
+ before do
41
+ allow(instance).to receive(:execute).with(anything)
42
+
43
+ end
44
+
45
+ context 'with dirname sent' do
46
+ let(:name) { 'my_dir' }
47
+ it 'returns the path to my_dir' do
48
+ expect(Beaker::Command).to receive(:new).
49
+ with('powershell.exe', array_including('-Command [System.IO.Path]::GetTempPath()')).
50
+ and_return(fake_command)
51
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(double(stdout: tmp_path))
52
+
53
+ expect(Beaker::Command).to receive(:new).
54
+ with('powershell.exe', array_including("-Command New-Item -Path '#{tmp_path}' -Force -Name '#{name}' -ItemType 'directory'")).
55
+ and_return(fake_command)
56
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(true)
57
+
58
+ expect(instance.tmpdir(name)).to eq(File.join(tmp_path, name))
59
+ end
60
+ end
61
+
62
+ context 'without dirname sent' do
63
+ let(:name) { '' }
64
+ let(:random_dir) { 'dirname' }
65
+
66
+ it 'returns the path to random name dir' do
67
+ expect(Beaker::Command).to receive(:new).
68
+ with('powershell.exe', array_including('-Command [System.IO.Path]::GetTempPath()')).
69
+ and_return(fake_command)
70
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(double(stdout: tmp_path))
71
+
72
+ expect(Beaker::Command).to receive(:new).
73
+ with('powershell.exe', array_including('-Command [System.IO.Path]::GetRandomFileName()')).
74
+ and_return(fake_command)
75
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(double(stdout: random_dir))
76
+
77
+ expect(Beaker::Command).to receive(:new).
78
+ with('powershell.exe', array_including("-Command New-Item -Path '#{tmp_path}' -Force -Name '#{random_dir}' -ItemType 'directory'")).
79
+ and_return(fake_command)
80
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(true)
81
+
82
+ expect(instance.tmpdir).to eq(File.join(tmp_path, random_dir))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -40,13 +40,13 @@ module Beaker
40
40
 
41
41
  it 'rm first' do
42
42
  expect( instance ).to receive(:execute).with("rm -rf #{destination}").and_return(0)
43
- expect( instance ).to receive(:execute).with("mv #{origin} #{destination}").and_return(0)
43
+ expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
44
44
  expect( instance.mv(origin, destination) ).to be === 0
45
45
 
46
46
  end
47
47
 
48
48
  it 'does not rm' do
49
- expect( instance ).to receive(:execute).with("mv #{origin} #{destination}").and_return(0)
49
+ expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
50
50
  expect( instance.mv(origin, destination, false) ).to be === 0
51
51
  end
52
52
  end
@@ -171,94 +171,135 @@ module Beaker
171
171
  describe '#reboot' do
172
172
  # no-op response
173
173
  let (:response) { double( 'response' ) }
174
- let (:uptime_initial_response) { double( 'response' ) }
175
- let (:uptime_initial_stdout) { '19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31' }
174
+ let (:boot_time_initial_response) { double( 'response' ) }
176
175
 
177
- let (:uptime_success_response) { double( 'response' ) }
178
- let (:uptime_success_stdout) { '19:52 up 0 mins, 2 users, load averages: 2.95 4.19 4.31' }
176
+ let (:boot_time_success_response) { double( 'response' ) }
179
177
  let (:sleep_time) { 10 }
180
178
 
181
179
  before :each do
182
- # stubs enough to survive the first uptime call & output parsing
180
+ # stubs enough to survive the first boot_time call & output parsing
183
181
  # note: just stubs input-chain between calls, parsing methods still run
184
- allow(Beaker::Command).to receive(:new).with("uptime").and_return(:uptime_command_stub)
182
+ allow(Beaker::Command).to receive(:new).with('who -b').and_return(:boot_time_command_stub)
185
183
 
186
- # mock initial uptime call
187
- allow(instance).to receive( :exec ).with(:uptime_command_stub).and_return(uptime_initial_response).once
188
- allow(uptime_initial_response).to receive(:stdout).and_return(uptime_initial_stdout)
189
-
190
- allow(uptime_success_response).to receive(:stdout).and_return(uptime_success_stdout)
184
+ allow(boot_time_initial_response).to receive(:stdout).and_return(boot_time_initial_stdout)
185
+ allow(boot_time_success_response).to receive(:stdout).and_return(boot_time_success_stdout)
191
186
 
192
187
  allow(instance).to receive(:sleep)
193
188
 
194
- allow(Beaker::Command).to receive(:new).with("/sbin/shutdown -r now").and_return(:shutdown_command_stub)
189
+ allow(Beaker::Command).to receive(:new).with("/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now").and_return(:shutdown_command_stub)
195
190
  end
196
191
 
197
- it 'raises a reboot failure when command fails' do
198
- expect(instance).not_to receive(:sleep)
199
- expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Host::CommandFailure).once
200
- expect{ instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Command failed when attempting to reboot: .*/)
201
- end
192
+ context 'new boot time greater than old boot time' do
193
+ let (:boot_time_initial_stdout) { ' system boot 2020-05-13 03:51' }
194
+ let (:boot_time_success_stdout) { ' system boot 2020-05-13 03:52' }
202
195
 
203
- it 'raises a reboot failure when we receive an unexpected error' do
204
- expect(instance).not_to receive(:sleep)
205
- expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Net::SSH::HostKeyError).once
206
- expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Unexpected exception in reboot: .*/)
207
- end
196
+ it 'passes with defaults' do
197
+ expect(instance).to receive(:sleep).with(sleep_time)
198
+ # bypass shutdown command itself
199
+ expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response)
200
+ # allow the second boot_time and the hash arguments in exec
201
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
202
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_success_response).once
208
203
 
209
- it 'raises RebootFailure if new uptime is never less than old uptime' do
210
- expect(instance).to receive(:sleep).with(sleep_time)
211
- # bypass shutdown command itself
212
- expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
213
- # allow the second uptime and the hash arguments in exec, repeated 18 times by default in order to replicate the previous behavior of the ping based Host.down?
214
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_initial_response).exactly(18).times
204
+ expect(instance.reboot).to be(nil)
205
+ end
215
206
 
216
- expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Uptime did not reset/)
217
- end
207
+ it 'passes with wait_time_parameter' do
208
+ expect(instance).to receive(:sleep).with(10)
209
+ # bypass shutdown command itself
210
+ expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
211
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
212
+ # allow the second boot_time and the hash arguments in exec
213
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_success_response).once
218
214
 
219
- it 'raises RebootFailure if new uptime is never less than old uptime when the number of retries is changed' do
220
- expect(instance).to receive(:sleep).with(sleep_time)
221
- # bypass shutdown command itself
222
- expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
223
- # allow the second uptime and the hash arguments in exec, repeated 10 times by default
224
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_initial_response).exactly(10).times
215
+ expect(instance.reboot(10)).to be(nil)
216
+ end
225
217
 
226
- expect { instance.reboot(wait_time=sleep_time, max_connection_tries=9, uptime_retries=10) }.to raise_error(Beaker::Host::RebootFailure, /Uptime did not reset/)
227
- end
218
+ it 'passes with max_connection_tries parameter' do
219
+ expect(instance).to receive(:sleep).with(sleep_time)
220
+ # bypass shutdown command itself
221
+ expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
222
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
223
+ # allow the second boot_time and the hash arguments in exec
224
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, hash_including(:max_connection_tries => 20)).and_return(boot_time_success_response).once
225
+
226
+ expect(instance.reboot(sleep_time, 20)).to be(nil)
227
+ end
228
+
229
+ context 'command errors' do
230
+ before :each do
231
+ allow(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
232
+ end
228
233
 
229
- it 'passes if new uptime is less than old uptime' do
230
- expect(instance).to receive(:sleep).with(sleep_time)
231
- # bypass shutdown command itself
232
- expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
233
- # allow the second uptime and the hash arguments in exec
234
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_success_response).once
234
+ it 'raises a reboot failure when command fails' do
235
+ expect(instance).not_to receive(:sleep)
236
+ expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Host::CommandFailure).once
235
237
 
236
- expect(instance.reboot).to be(nil)
238
+ expect{ instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Command failed when attempting to reboot: .*/)
239
+ end
240
+
241
+ it 'raises a reboot failure when we receive an unexpected error' do
242
+ expect(instance).not_to receive(:sleep)
243
+ expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Net::SSH::HostKeyError).once
244
+
245
+ expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Unexpected exception in reboot: .*/)
246
+ end
247
+
248
+ context 'incorrect time string' do
249
+ context 'original time' do
250
+ let (:boot_time_initial_stdout) { 'boot bad' }
251
+
252
+ it 'raises a reboot failure' do
253
+ expect(instance).not_to receive(:sleep)
254
+
255
+ expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Unable to parse time: .*/)
256
+ end
257
+ end
258
+
259
+ context 'current time' do
260
+ let (:boot_time_success_stdout) { 'boot bad' }
261
+
262
+ it 'raises a reboot failure' do
263
+ expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_return(response).once
264
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
265
+ # allow the second boot_time and the hash arguments in exec, repeated 10 times by default
266
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_success_response).once
267
+
268
+ expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Unable to parse time: .*/)
269
+ end
270
+ end
271
+ end
272
+ end
237
273
  end
238
274
 
239
- context 'with wait_time_parameter' do
240
- it 'passes if new uptime is less than old uptime' do
241
- expect(instance).to receive(:sleep).with(10)
275
+ context 'new boot time less than old boot time' do
276
+ let (:boot_time_initial_stdout) { ' system boot 2020-05-13 03:51' }
277
+ let (:boot_time_success_stdout) { ' system boot 2020-05-13 03:50' }
278
+
279
+ it 'raises RebootFailure' do
280
+ expect(instance).to receive(:sleep).with(sleep_time)
242
281
  # bypass shutdown command itself
243
282
  expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
244
- # allow the second uptime and the hash arguments in exec
245
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_success_response).once
246
283
 
247
- expect(instance.reboot(10)).to be(nil)
284
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
285
+ # allow the second boot_time and the hash arguments in exec, repeated 18 times by default in order to replicate the previous behavior of the ping based Host.down?
286
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_success_response).exactly(18).times
287
+
288
+ expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Boot time did not reset/)
248
289
  end
249
- end
250
290
 
251
- context 'with max_connection_tries parameter' do
252
- it 'passes if new uptime is less than old uptime' do
291
+ it 'raises RebootFailure if the number of retries is changed' do
253
292
  expect(instance).to receive(:sleep).with(sleep_time)
254
293
  # bypass shutdown command itself
255
294
  expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
256
- # allow the second uptime and the hash arguments in exec
257
- expect(instance).to receive( :exec ).with(:uptime_command_stub, hash_including(:max_connection_tries => 20)).and_return(uptime_success_response).once
295
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_initial_response).once
296
+ # allow the second boot_time and the hash arguments in exec, repeated 10 times by default
297
+ expect(instance).to receive( :exec ).with(:boot_time_command_stub, anything).and_return(boot_time_success_response).exactly(10).times
258
298
 
259
- expect(instance.reboot(sleep_time, 20)).to be(nil)
299
+ expect { instance.reboot(wait_time=sleep_time, max_connection_tries=9, boot_time_retries=10) }.to raise_error(Beaker::Host::RebootFailure, /Boot time did not reset/)
260
300
  end
261
301
  end
302
+
262
303
  end
263
304
 
264
305
  describe '#enable_remote_rsyslog' do
@@ -196,6 +196,14 @@ module Beaker
196
196
  end
197
197
  end
198
198
 
199
+ describe '#cat' do
200
+ let (:path) { '/path/to/cat/on' }
201
+ it 'calls cat for path' do
202
+ expect( instance ).to receive( :execute ).with( "cat #{path}" ).and_return( 0 )
203
+ expect( instance.cat( path ) ).to be === 0
204
+ end
205
+ end
206
+
199
207
  describe '#chmod' do
200
208
  context 'not recursive' do
201
209
  it 'calls execute with chmod' do
@@ -325,7 +325,7 @@ module Beaker
325
325
  allow( result ).to receive( :exit_code ).and_return( 0 )
326
326
  allow( host ).to receive( :exec ).and_return( result )
327
327
 
328
- expect( Beaker::Command ).to receive(:new).with("mkdir -p test/test/test")
328
+ expect( Beaker::Command ).to receive(:new).with("mkdir -p \"test/test/test\"")
329
329
  expect( host.mkdir_p('test/test/test') ).to be == true
330
330
 
331
331
  end
@@ -337,7 +337,7 @@ module Beaker
337
337
  allow( result ).to receive( :exit_code ).and_return( 0 )
338
338
  allow( host ).to receive( :exec ).and_return( result )
339
339
 
340
- expect( Beaker::Command ).to receive(:new).with("mkdir -p test/test/test")
340
+ expect( Beaker::Command ).to receive(:new).with("mkdir -p \"test/test/test\"")
341
341
  expect( host.mkdir_p('test/test/test') ).to be == true
342
342
 
343
343
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.22.1
4
+ version: 4.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-08 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -216,14 +216,14 @@ dependencies:
216
216
  name: net-ssh
217
217
  requirement: !ruby/object:Gem::Requirement
218
218
  requirements:
219
- - - "~>"
219
+ - - ">="
220
220
  - !ruby/object:Gem::Version
221
221
  version: '5.0'
222
222
  type: :runtime
223
223
  prerelease: false
224
224
  version_requirements: !ruby/object:Gem::Requirement
225
225
  requirements:
226
- - - "~>"
226
+ - - ">="
227
227
  - !ruby/object:Gem::Version
228
228
  version: '5.0'
229
229
  - !ruby/object:Gem::Dependency
@@ -630,6 +630,7 @@ files:
630
630
  - spec/beaker/host/mac/user_spec.rb
631
631
  - spec/beaker/host/mac_spec.rb
632
632
  - spec/beaker/host/pswindows/exec_spec.rb
633
+ - spec/beaker/host/pswindows/file_spec.rb
633
634
  - spec/beaker/host/pswindows/user_spec.rb
634
635
  - spec/beaker/host/pswindows_spec.rb
635
636
  - spec/beaker/host/unix/exec_spec.rb