beaker 4.21.0 → 4.23.2

Sign up to get free protection for your applications and to get access to all the features.
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