beaker 4.21.0 → 4.23.2

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: 92aa5f010caeb1dc51e07fda6804186857ce5d3d74c9f8391ff3d6f3cd720f7a
4
- data.tar.gz: 8c6903944cf9c77f166edec11fe1503085a048f70119456a5680339771564558
3
+ metadata.gz: d7a6dab8f2bbd3711c1807aa31ef4947cfffb0c80cfe291dfc3261a677c9d618
4
+ data.tar.gz: 16dc6decc29e71095f4525b7aa3f301bda493a4cf124695bebeefa6cb695f3fa
5
5
  SHA512:
6
- metadata.gz: bf304b5107c82a834e86fd4123aa36f89ea8933571f35d2abe5cb3a934447f0a4c154fe8006b315cc4a90404c170a42a4a256b2d90542b1f4ad34024ad248601
7
- data.tar.gz: c4331359a27c7b880fbd34213983337f0c79374b353d8f5581def07196df83d7ad0209a7694de4ba8989520cc25fe2210f35ade13d048e5290d98e63e8e240eb
6
+ metadata.gz: 1ad64e24fd5672ff23b86fc601b7a50d0b1f7b048fde2c8f2af5eb45699ab22bbce0dac53ea1dc8ab4bd887279079a6689f74a1748e03206234f100f5ce08b88
7
+ data.tar.gz: 5d32208fd3bff7fe6cc06482ccbb7407318a54dafc3141765e32baf726913c9f7b9af4421e30217642fa993cbc1bdef239afe530b35cb3986017a5bef346f696
@@ -20,7 +20,53 @@ 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.21.0...master)
23
+ # [Unreleased](https://github.com/puppetlabs/beaker/compare/4.23.2...master)
24
+
25
+ # [4.23.2](https://github.com/puppetlabs/beaker/compare/4.23.1...4.23.2)
26
+
27
+ ### Fixed
28
+
29
+ - Fixed Beaker's behavior when the `strict_host_key_checking` option is
30
+ provided in the SSH config and Net-SSH > 5 is specified. (#1652)
31
+
32
+ # [4.23.1](https://github.com/puppetlabs/beaker/compare/4.23.0...4.23.1)
33
+
34
+ ### Changed/Removed
35
+
36
+ - Reversed the quoting changes on Unix from #1644 in favor of only quoting on Windows. (#1650)
37
+
38
+ # [4.23.0](https://github.com/puppetlabs/beaker/compare/4.22.1...4.23.0)
39
+
40
+ ### Added
41
+
42
+ - Relaxed dependency on `net-ssh` to `>= 5` to support newer versions. (#1648)
43
+ - `cat` DSL method added. Works on both Unix and Windows hosts. (#1645)
44
+
45
+ ### Changed
46
+
47
+ - 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.
48
+ - Change `reboot` method to use `who -b` for uptime detection (#1643)
49
+
50
+ ### Fixed
51
+
52
+ - Use Base64 UTF-16LE encoding for commands (#1626)
53
+ - Fix `tmpdir` method for Powershell on Windows (#1645)
54
+
55
+ # [4.22.1](https://github.com/puppetlabs/beaker/compare/4.22.0...4.22.1)
56
+
57
+ ### Fixed
58
+
59
+ - Removed single quotes around paths for file operation commands on `Host` https://github.com/puppetlabs/beaker/pull/1642
60
+
61
+ # [4.22.0](https://github.com/puppetlabs/beaker/compare/4.21.0...4.22.0) - 2020-05-08
62
+
63
+ ### Added
64
+
65
+ - Host methods chmod and modified_at. ([#1638](https://github.com/puppetlabs/beaker/pull/1638))
66
+
67
+ ### Removed
68
+
69
+ - Support for EL-5. ([#1639](https://github.com/puppetlabs/beaker/pull/1639)) ([#1640](https://github.com/puppetlabs/beaker/pull/1640))
24
70
 
25
71
  # [4.21.0](https://github.com/puppetlabs/beaker/compare/4.20.0...4.21.0) - 2020-03-31
26
72
 
@@ -43,7 +89,7 @@ The headers used in [Keep a Changelog](http://keepachangelog.com) are:
43
89
 
44
90
  ### Changed
45
91
 
46
- - The `wait_time`, `max_connection_tries`, and `uptime_retries` parameters have been added to `Host::Unix::Exec.reboot`. This allows for more fine-grained control over how the reboot is handled. ([#1625](https://github.com/puppetlabs/beaker/pull/1625))
92
+ - The `wait_time`, `max_connection_tries`, and `uptime_retries` parameters have been added to `Host::Unix::Exec.reboot`. This allows for more fine-grained control over how the reboot is handled. ([#1625](https://github.com/puppetlabs/beaker/pull/1625))
47
93
 
48
94
  ### Fixed
49
95
 
@@ -2,7 +2,6 @@ test_name 'External Resources Test' do
2
2
  step 'Verify EPEL resources are up and available' do
3
3
  def build_url(el_version)
4
4
  url_base = options[:epel_url]
5
- url_base = options[:epel_url_archive] if el_version == 5
6
5
  "#{url_base}/epel-release-latest-#{el_version}.noarch.rpm"
7
6
  end
8
7
 
@@ -23,11 +22,10 @@ test_name 'External Resources Test' do
23
22
  assert_match(/200 OK/, curl_headers_result.stdout, "EPEL #{el_version} should be reachable at #{url}")
24
23
  end
25
24
 
26
- step 'Verify el_version numbers 5,6,7 are found on the epel resource' do
27
- [5,6,7].each do |el_version|
25
+ step 'Verify el_version numbers 6,7,8 are found on the epel resource' do
26
+ [6,7,8].each do |el_version|
28
27
  epel_url_test(el_version)
29
28
  end
30
29
  end
31
-
32
30
  end
33
31
  end
@@ -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
@@ -35,4 +35,13 @@ module Mac::Exec
35
35
  false
36
36
  end
37
37
 
38
+ # Update ModifiedDate on a file
39
+ # @param [String] file Path to the file
40
+ # @param [String] timestamp Timestamp to set
41
+ def modified_at(file, timestamp = nil)
42
+ require 'date'
43
+ time = timestamp ? DateTime.parse("#{timestamp}") : DateTime.now
44
+ timestamp = time.strftime('%Y%m%d%H%M')
45
+ execute("touch -mt #{timestamp} #{file}")
46
+ end
38
47
  end
@@ -37,6 +37,28 @@ module PSWindows::Exec
37
37
  execute("move /y #{orig} #{dest}")
38
38
  end
39
39
 
40
+ # Update ModifiedDate on a file
41
+ # @param [String] file Path to the file
42
+ # @param [String] timestamp Timestamp to set
43
+ def modified_at(file, timestamp = nil)
44
+ require 'date'
45
+ time = timestamp ? DateTime.parse("#{timestamp}") : DateTime.now
46
+
47
+ result = execute("powershell Test-Path #{file} -PathType Leaf")
48
+
49
+ if result.include? 'False'
50
+ execute("powershell New-Item -ItemType file #{file}")
51
+ end
52
+ execute("powershell (gci #{file}).LastWriteTime = Get-Date " \
53
+ "-Year '#{time.year}'" \
54
+ "-Month '#{time.month}'" \
55
+ "-Day '#{time.day}'" \
56
+ "-Hour '#{time.hour}'" \
57
+ "-Minute '#{time.minute}'" \
58
+ "-Second '#{time.second}'"
59
+ )
60
+ end
61
+
40
62
  def path
41
63
  'c:/windows/system32;c:/windows'
42
64
  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/
@@ -2,9 +2,9 @@ module Unix::Exec
2
2
  include Beaker::CommandFactory
3
3
 
4
4
  # Reboots the host, comparing uptime values to verify success
5
- # @param [Integer] wait_time How long to wait after sending the reboot
5
+ # @param [Integer] wait_time How long to wait after sending the reboot
6
6
  # command before attempting to check in on the host
7
- # @param [Integer] max_connection_tries How many times to retry connecting to
7
+ # @param [Integer] max_connection_tries How many times to retry connecting to
8
8
  # host after reboot. Note that there is an fibbonacci
9
9
  # backoff when attempting retries so the time spent
10
10
  # waiting on this can grow quickly.
@@ -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
 
@@ -89,7 +95,7 @@ module Unix::Exec
89
95
  return "0 min"
90
96
  end
91
97
  raise "Couldn't parse uptime: #{uptime}" if result.nil?
92
-
98
+
93
99
  result[1].strip.chomp(",")
94
100
  end
95
101
 
@@ -101,6 +107,16 @@ module Unix::Exec
101
107
  (abs ? '/bin/touch' : 'touch') + " #{file}"
102
108
  end
103
109
 
110
+ # Update ModifiedDate on a file
111
+ # @param [String] file Path to the file
112
+ # @param [String] timestamp Timestamp to set
113
+ def modified_at(file, timestamp = nil)
114
+ require 'date'
115
+ time = timestamp ? DateTime.parse("#{timestamp}") : DateTime.now
116
+ timestamp = time.strftime('%Y%m%d%H%M')
117
+ execute("/bin/touch -mt #{timestamp} #{file}")
118
+ end
119
+
104
120
  def path
105
121
  '/bin:/usr/bin'
106
122
  end
@@ -30,6 +30,10 @@ module Unix::File
30
30
  execute("chown #{recursive ? '-R ' : ''}#{user} #{path}")
31
31
  end
32
32
 
33
+ def chmod(mod, path, recursive=false)
34
+ execute("chmod #{recursive ? '-R ' : ''}#{mod} #{path}")
35
+ end
36
+
33
37
  # Change group ownership of a path
34
38
  #
35
39
  # @see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/chgrp.html
@@ -54,6 +58,10 @@ module Unix::File
54
58
  execute("ls -ld #{path}")
55
59
  end
56
60
 
61
+ def cat(path)
62
+ execute("cat #{path}")
63
+ end
64
+
57
65
  # Handles any changes needed in a path for SCP
58
66
  #
59
67
  # @param [String] path File path to SCP to
@@ -119,6 +119,25 @@ module Windows::Exec
119
119
  false
120
120
  end
121
121
 
122
+ # Create the provided directory structure on the host
123
+ # @param [String] dir The directory structure to create on the host
124
+ # @return [Boolean] True, if directory construction succeeded, otherwise False
125
+ def mkdir_p dir
126
+ cmd = "mkdir -p \"#{dir}\""
127
+ result = exec(Beaker::Command.new(cmd), :acceptable_exit_codes => [0, 1])
128
+ result.exit_code == 0
129
+ end
130
+
131
+ # Move the origin to destination. The destination is removed prior to moving.
132
+ # @param [String] orig The origin path
133
+ # @param [String] dest the destination path
134
+ # @param [Boolean] rm Remove the destination prior to move
135
+ def mv orig, dest, rm=true
136
+ rm_rf dest unless !rm
137
+ execute("mv \"#{orig}\" \"#{dest}\"")
138
+ end
139
+
140
+
122
141
  # Determine if cygwin is actually installed on the SUT. Differs from
123
142
  # is_cygwin?, which is just a type check for a Windows::Host.
124
143
  #
@@ -35,6 +35,9 @@ module Windows::File
35
35
  super(group, cygpath, recursive)
36
36
  end
37
37
 
38
+ # Not needed on windows
39
+ def chmod(mod, path, recursive=false); end
40
+
38
41
  # (see {Beaker::Host::Unix::File#ls_ld})
39
42
  # @note Cygwin's `ls_ld` implementation does not support
40
43
  # windows-, DOS-, or mixed-style paths, only UNIX/POSIX-style.
@@ -244,7 +244,7 @@ module Beaker
244
244
  report_and_raise(logger, e, "proxy_config")
245
245
  end
246
246
 
247
- #Install EPEL on host or hosts with platform = /el-(5|6|7)/. Do nothing on host or hosts of other platforms.
247
+ #Install EPEL on host or hosts with platform = /el-(6|7)/. Do nothing on host or hosts of other platforms.
248
248
  # @param [Host, Array<Host>] host One or more hosts to act upon. Will use individual host epel_url, epel_arch
249
249
  # and epel_pkg before using defaults provided in opts.
250
250
  # @param [Hash{Symbol=>String}] opts Options to alter execution.
@@ -258,11 +258,10 @@ module Beaker
258
258
  debug_opt = opts[:debug] ? 'vh' : ''
259
259
  block_on host do |host|
260
260
  case
261
- when el_based?(host) && ['5','6','7'].include?(host['platform'].version)
261
+ when el_based?(host) && ['6','7'].include?(host['platform'].version)
262
262
  result = host.exec(Command.new('rpm -qa | grep epel-release'), :acceptable_exit_codes => [0,1])
263
263
  if result.exit_code == 1
264
264
  url_base = opts[:epel_url]
265
- url_base = opts[:epel_url_archive] if host['platform'].version == '5'
266
265
  host.install_package_with_rpm("#{url_base}/epel-release-latest-#{host['platform'].version}.noarch.rpm", '--replacepkgs', { :package_proxy => opts[:package_proxy] })
267
266
  #update /etc/yum.repos.d/epel.repo for new baseurl
268
267
  host.exec(Command.new("sed -i -e 's;#baseurl.*$;baseurl=#{Regexp.escape("#{url_base}/#{host['platform'].version}")}/\$basearch;' /etc/yum.repos.d/epel.repo"))
@@ -174,7 +174,6 @@ module Beaker
174
174
  :package_proxy => false,
175
175
  :add_el_extras => false,
176
176
  :epel_url => "http://dl.fedoraproject.org/pub/epel",
177
- :epel_url_archive => 'http://archive.fedoraproject.org/pub/archive/epel',
178
177
  :consoleport => 443,
179
178
  :pe_dir => '/opt/enterprise/dists',
180
179
  :pe_version_file => 'LATEST',
@@ -68,6 +68,11 @@ module Beaker
68
68
  max_connection_tries = options[:max_connection_tries] || 11
69
69
  begin
70
70
  @logger.debug "Attempting ssh connection to #{host}, user: #{user}, opts: #{ssh_opts}"
71
+
72
+ if ssh_opts.include?(:strict_host_key_checking) && (Net::SSH::Version::CURRENT.major > 5)
73
+ ssh_opts[:paranoid] = ssh_opts.delete(:strict_host_key_checking)
74
+ end
75
+
71
76
  Net::SSH.start(host, user, ssh_opts)
72
77
  rescue *RETRYABLE_EXCEPTIONS => e
73
78
  if try <= max_connection_tries
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '4.21.0'
3
+ STRING = '4.23.2'
4
4
  end
5
5
  end
@@ -31,5 +31,15 @@ module Beaker
31
31
  expect(instance.selinux_enabled?).to be === false
32
32
  end
33
33
  end
34
+
35
+ describe '#modified_at' do
36
+ it 'calls execute with touch and timestamp' do
37
+ time = '190101010000'
38
+ path = '/path/to/file'
39
+ expect( instance ).to receive(:execute).with("touch -mt #{time} #{path}").and_return(0)
40
+
41
+ instance.modified_at(path, time)
42
+ end
43
+ end
34
44
  end
35
45
  end
@@ -50,6 +50,38 @@ module Beaker
50
50
  expect( instance.mv(origin, destination, false) ).to be === 0
51
51
  end
52
52
  end
53
+
54
+ describe '#modified_at' do
55
+ before do
56
+ allow(instance).to receive(:execute).and_return(stdout)
57
+ end
58
+
59
+ context 'file exists' do
60
+ let(:stdout) { 'True' }
61
+ it 'sets the modified_at date' do
62
+ file = 'C:\path\to\file'
63
+ expect(instance).to receive(:execute).with("powershell Test-Path #{file} -PathType Leaf")
64
+ expect(instance).to receive(:execute).with(
65
+ "powershell (gci C:\\path\\to\\file).LastWriteTime = Get-Date -Year '1970'-Month '1'-Day '1'-Hour '0'-Minute '0'-Second '0'"
66
+ )
67
+ instance.modified_at(file, '197001010000')
68
+ end
69
+ end
70
+
71
+ context 'file does not exist' do
72
+ let(:stdout) { 'False' }
73
+ it 'creates it and sets the modified_at date' do
74
+ file = 'C:\path\to\file'
75
+ expect(instance).to receive(:execute).with("powershell Test-Path #{file} -PathType Leaf")
76
+ expect(instance).to receive(:execute).with("powershell New-Item -ItemType file #{file}")
77
+ expect(instance).to receive(:execute).with(
78
+ "powershell (gci C:\\path\\to\\file).LastWriteTime = Get-Date -Year '1970'-Month '1'-Day '1'-Hour '0'-Minute '0'-Second '0'"
79
+ )
80
+ instance.modified_at(file, '197001010000')
81
+ end
82
+ end
83
+ end
84
+
53
85
  describe '#environment_string' do
54
86
  let(:host) { {'pathseparator' => ':'} }
55
87
 
@@ -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
@@ -51,6 +51,16 @@ module Beaker
51
51
  end
52
52
  end
53
53
 
54
+ describe '#modified_at' do
55
+ it 'calls execute with touch and timestamp' do
56
+ time = '190101010000'
57
+ path = '/path/to/file'
58
+ expect( instance ).to receive(:execute).with("/bin/touch -mt #{time} #{path}").and_return(0)
59
+
60
+ instance.modified_at(path, time)
61
+ end
62
+ end
63
+
54
64
  describe '#environment_string' do
55
65
  let(:host) { {'pathseparator' => ':'} }
56
66
 
@@ -161,94 +171,135 @@ module Beaker
161
171
  describe '#reboot' do
162
172
  # no-op response
163
173
  let (:response) { double( 'response' ) }
164
- let (:uptime_initial_response) { double( 'response' ) }
165
- 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' ) }
166
175
 
167
- let (:uptime_success_response) { double( 'response' ) }
168
- 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' ) }
169
177
  let (:sleep_time) { 10 }
170
178
 
171
179
  before :each do
172
- # stubs enough to survive the first uptime call & output parsing
180
+ # stubs enough to survive the first boot_time call & output parsing
173
181
  # note: just stubs input-chain between calls, parsing methods still run
174
- allow(Beaker::Command).to receive(:new).with("uptime").and_return(:uptime_command_stub)
175
-
176
- # mock initial uptime call
177
- allow(instance).to receive( :exec ).with(:uptime_command_stub).and_return(uptime_initial_response).once
178
- allow(uptime_initial_response).to receive(:stdout).and_return(uptime_initial_stdout)
182
+ allow(Beaker::Command).to receive(:new).with('who -b').and_return(:boot_time_command_stub)
179
183
 
180
- 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)
181
186
 
182
187
  allow(instance).to receive(:sleep)
183
188
 
184
- 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)
185
190
  end
186
191
 
187
- it 'raises a reboot failure when command fails' do
188
- expect(instance).not_to receive(:sleep)
189
- expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Host::CommandFailure).once
190
- expect{ instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Command failed when attempting to reboot: .*/)
191
- 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' }
192
195
 
193
- it 'raises a reboot failure when we receive an unexpected error' do
194
- expect(instance).not_to receive(:sleep)
195
- expect(instance).to receive(:exec).with(:shutdown_command_stub, anything).and_raise(Net::SSH::HostKeyError).once
196
- expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Unexpected exception in reboot: .*/)
197
- 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
198
203
 
199
- it 'raises RebootFailure if new uptime is never less than old uptime' do
200
- expect(instance).to receive(:sleep).with(sleep_time)
201
- # bypass shutdown command itself
202
- expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
203
- # 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?
204
- 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
205
206
 
206
- expect { instance.reboot }.to raise_error(Beaker::Host::RebootFailure, /Uptime did not reset/)
207
- 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
208
214
 
209
- it 'raises RebootFailure if new uptime is never less than old uptime when the number of retries is changed' 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 10 times by default
214
- 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
215
217
 
216
- expect { instance.reboot(wait_time=sleep_time, max_connection_tries=9, uptime_retries=10) }.to raise_error(Beaker::Host::RebootFailure, /Uptime did not reset/)
217
- 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
218
225
 
219
- it 'passes if new uptime is less than old uptime' 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
224
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_success_response).once
226
+ expect(instance.reboot(sleep_time, 20)).to be(nil)
227
+ end
225
228
 
226
- expect(instance.reboot).to be(nil)
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
233
+
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
237
+
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
227
273
  end
228
274
 
229
- context 'with wait_time_parameter' do
230
- it 'passes if new uptime is less than old uptime' do
231
- 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)
232
281
  # bypass shutdown command itself
233
282
  expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
234
- # allow the second uptime and the hash arguments in exec
235
- expect(instance).to receive( :exec ).with(:uptime_command_stub, anything).and_return(uptime_success_response).once
236
283
 
237
- 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/)
238
289
  end
239
- end
240
290
 
241
- context 'with max_connection_tries parameter' do
242
- it 'passes if new uptime is less than old uptime' do
291
+ it 'raises RebootFailure if the number of retries is changed' do
243
292
  expect(instance).to receive(:sleep).with(sleep_time)
244
293
  # bypass shutdown command itself
245
294
  expect(instance).to receive( :exec ).with(:shutdown_command_stub, anything).and_return(response).once
246
- # allow the second uptime and the hash arguments in exec
247
- 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
248
298
 
249
- 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/)
250
300
  end
251
301
  end
302
+
252
303
  end
253
304
 
254
305
  describe '#enable_remote_rsyslog' do
@@ -196,6 +196,36 @@ 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
+
207
+ describe '#chmod' do
208
+ context 'not recursive' do
209
+ it 'calls execute with chmod' do
210
+ path = '/path/to/file'
211
+ mod = '+x'
212
+
213
+ expect( instance ).to receive(:execute).with("chmod #{mod} #{path}")
214
+ instance.chmod(mod, path)
215
+ end
216
+ end
217
+
218
+ context 'recursive' do
219
+ it 'calls execute with chmod' do
220
+ path = '/path/to/file'
221
+ mod = '+x'
222
+
223
+ expect( instance ).to receive(:execute).with("chmod -R #{mod} #{path}")
224
+ instance.chmod(mod, path, true)
225
+ end
226
+ end
227
+ end
228
+
199
229
  describe '#chgrp' do
200
230
  let (:group) { 'somegroup' }
201
231
  let (:path) { '/path/to/chgrp/on' }
@@ -3,6 +3,7 @@ require 'spec_helper'
3
3
  module Beaker
4
4
  describe Windows::Exec do
5
5
  class WindowsExecTest
6
+ include Unix::Exec
6
7
  include Windows::Exec
7
8
 
8
9
  def initialize(hash, logger)
@@ -78,5 +79,22 @@ module Beaker
78
79
  expect(instance.cygwin_installed?).to eq(false)
79
80
  end
80
81
  end
82
+
83
+ context 'mv' do
84
+ let(:origin) { '/origin/path/of/content' }
85
+ let(:destination) { '/destination/path/of/content' }
86
+
87
+ it 'rm first' do
88
+ expect( instance ).to receive(:execute).with("rm -rf #{destination}").and_return(0)
89
+ expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
90
+ expect( instance.mv(origin, destination) ).to be === 0
91
+
92
+ end
93
+
94
+ it 'does not rm' do
95
+ expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
96
+ expect( instance.mv(origin, destination, false) ).to be === 0
97
+ end
98
+ end
81
99
  end
82
100
  end
@@ -329,33 +329,6 @@ describe Beaker do
329
329
  context "add_el_extras" do
330
330
  subject { dummy_class.new }
331
331
 
332
- it 'adds archived extras for el-5 hosts' do
333
-
334
- hosts = make_hosts( { :platform => Beaker::Platform.new('el-5-arch'), :exit_code => 1 }, 2 )
335
- hosts[1][:platform] = Beaker::Platform.new('oracle-5-arch')
336
-
337
- expect( Beaker::Command ).to receive( :new ).with(
338
- "rpm -qa | grep epel-release"
339
- ).exactly( 2 ).times
340
- hosts.each do |host|
341
- expect(host).to receive( :install_package_with_rpm ).with(
342
- "http://archive.fedoraproject.org/pub/archive/epel/epel-release-latest-5.noarch.rpm", "--replacepkgs", {:package_proxy => false}
343
- ).once
344
- end
345
- expect( Beaker::Command ).to receive( :new ).with(
346
- "sed -i -e 's;#baseurl.*$;baseurl=http://archive\\.fedoraproject\\.org/pub/archive/epel/5/$basearch;' /etc/yum.repos.d/epel.repo"
347
- ).exactly( 2 ).times
348
- expect( Beaker::Command ).to receive( :new ).with(
349
- "sed -i -e '/mirrorlist/d' /etc/yum.repos.d/epel.repo"
350
- ).exactly( 2 ).times
351
- expect( Beaker::Command ).to receive( :new ).with(
352
- "yum clean all && yum makecache"
353
- ).exactly( 2 ).times
354
-
355
- subject.add_el_extras( hosts, options )
356
-
357
- end
358
-
359
332
  it 'adds extras for el-6 hosts' do
360
333
 
361
334
  hosts = make_hosts( { :platform => Beaker::Platform.new('el-6-arch'), :exit_code => 1 }, 4 )
@@ -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.21.0
4
+ version: 4.23.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-31 00:00:00.000000000 Z
11
+ date: 2020-05-26 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