beaker 4.22.1 → 4.25.0

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: 0a089feb0e8311631a3778e1839e5942694ec2e9f14bb873fbfb07d5ae854bca
4
- data.tar.gz: b0e75901ec90f523a2b2f276658e8ede706a0fb3df3f09fcd58779263a28d630
3
+ metadata.gz: 9a980145fbc318a89a888401bd94260c191604431b1eaa73b3fde746a4c405f5
4
+ data.tar.gz: 58a17db7a9772ff339511bb8e96bb71d121291df8fe328fc1e4f3e25d795c765
5
5
  SHA512:
6
- metadata.gz: bfb8cfe1965440e36c4e8093548a454c0de51100d1ec5c4a5d001c083fc20aa5b2715301abba1b2a4ddb3425701c51298e4cbcb41f965896a41f59c003c2b97d
7
- data.tar.gz: 39fb8a21b0e289c81b8967deb089bb50418a726d0bec337cec4ad6230d4b5ce3587b37c2ee1144cef61d1f944b77df1a1f6cc0a2ae79c9214efe66c55dcd463a
6
+ metadata.gz: a1e4d5183c9816d8259daa604c5ec0874c66e1373f7826dcb18745cf1436b9210be67cc79becd5e5a1cdf338f968a7b5daefc5aa3eb56118b8720910c7ec23dd
7
+ data.tar.gz: 94ba6fe73b1ca744dcaff5b4e010e992d995fc908ce8bb7951116a2853d268deb125a7e91923225d5c81d1685669e50a0ca3bbe82253b8a919868ea97a088309
@@ -20,7 +20,58 @@ 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.25.0...master)
24
+
25
+ # [4.25.0](https://github.com/puppetlabs/beaker/compare/4.24.0...4.25.0)
26
+
27
+ ### Added
28
+
29
+ - Execution of Beaker directly through ruby on localhost #1637 ([#1637](https://github.com/puppetlabs/beaker/pull/1637))
30
+
31
+ ### Fixed
32
+
33
+ - Reliability improvements to the `Host#reboot` method ([#1656](https://github.com/puppetlabs/beaker/pull/1656)) ([#1659](https://github.com/puppetlabs/beaker/pull/1659))
34
+
35
+ # [4.24.0](https://github.com/puppetlabs/beaker/compare/4.23.0...4.24.0) - 2020-06-05
36
+
37
+ ### Added
38
+
39
+ - Host method which ([#1651](https://github.com/puppetlabs/beaker/pull/1651))
40
+
41
+ ### Fixed
42
+
43
+ - Fixed implementation for cat and file_exists? host methods for PSWindows ([#1654](https://github.com/puppetlabs/beaker/pull/1654))
44
+ - Fixed implementation for mkdir_p host method for PSWindows ([#1657](https://github.com/puppetlabs/beaker/pull/1657))
45
+
46
+ # [4.23.2](https://github.com/puppetlabs/beaker/compare/4.23.1...4.23.2)
47
+
48
+ ### Fixed
49
+
50
+ - Fixed Beaker's behavior when the `strict_host_key_checking` option is
51
+ provided in the SSH config and Net-SSH > 5 is specified. (#1652)
52
+
53
+ # [4.23.1](https://github.com/puppetlabs/beaker/compare/4.23.0...4.23.1)
54
+
55
+ ### Changed/Removed
56
+
57
+ - Reversed the quoting changes on Unix from #1644 in favor of only quoting on Windows. (#1650)
58
+
59
+ # [4.23.0](https://github.com/puppetlabs/beaker/compare/4.22.1...4.23.0)
60
+
61
+ ### Added
62
+
63
+ - Relaxed dependency on `net-ssh` to `>= 5` to support newer versions. (#1648)
64
+ - `cat` DSL method added. Works on both Unix and Windows hosts. (#1645)
65
+
66
+ ### Changed
67
+
68
+ - 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.
69
+ - Change `reboot` method to use `who -b` for uptime detection (#1643)
70
+
71
+ ### Fixed
72
+
73
+ - Use Base64 UTF-16LE encoding for commands (#1626)
74
+ - Fix `tmpdir` method for Powershell on Windows (#1645)
24
75
 
25
76
  # [4.22.1](https://github.com/puppetlabs/beaker/compare/4.22.0...4.22.1)
26
77
 
@@ -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
@@ -6,7 +6,7 @@ require 'rsync'
6
6
  require 'beaker/dsl/helpers'
7
7
  require 'beaker/dsl/patterns'
8
8
 
9
- [ 'command', 'ssh_connection'].each do |lib|
9
+ [ 'command', 'ssh_connection', 'local_connection' ].each do |lib|
10
10
  require "beaker/#{lib}"
11
11
  end
12
12
 
@@ -294,6 +294,11 @@ module Beaker
294
294
 
295
295
  def connection
296
296
  # create new connection object if necessary
297
+ if self['hypervisor'] == 'none' && @name == 'localhost'
298
+ @connection ||= LocalConnection.connect( { :ssh_env_file => self['ssh_env_file'], :logger => @logger })
299
+ return @connection
300
+ end
301
+
297
302
  @connection ||= SshConnection.connect( { :ip => self['ip'], :vmhostname => self['vmhostname'], :hostname => @name },
298
303
  self['user'],
299
304
  self['ssh'], { :logger => @logger, :ssh_connection_preference => self[:ssh_connection_preference]} )
@@ -104,9 +104,9 @@ module PSWindows::Exec
104
104
  # @param [String] dir The directory structure to create on the host
105
105
  # @return [Boolean] True, if directory construction succeeded, otherwise False
106
106
  def mkdir_p dir
107
- windows_dirstring = dir.gsub('/','\\')
108
- cmd = "if not exist #{windows_dirstring} (md #{windows_dirstring})"
109
- result = exec(Beaker::Command.new(cmd), :acceptable_exit_codes => [0, 1])
107
+ normalized_path = dir.gsub('/','\\')
108
+ result = exec(powershell("New-Item -Path '#{normalized_path}' -ItemType 'directory'"),
109
+ :acceptable_exit_codes => [0, 1])
110
110
  result.exit_code == 0
111
111
  end
112
112
 
@@ -237,4 +237,19 @@ module PSWindows::Exec
237
237
  end
238
238
  end
239
239
 
240
+ #First path it finds for the command executable
241
+ #@param [String] command The command executable to search for
242
+ #
243
+ # @return [String] Path to the searched executable or empty string if not found
244
+ #
245
+ #@example
246
+ # host.which('ruby')
247
+ def which(command)
248
+ where_command = "cmd /C \"where #{command}\""
249
+
250
+ result = execute(where_command, :accept_all_exit_codes => true)
251
+ return '' if result.empty?
252
+
253
+ result
254
+ end
240
255
  end
@@ -7,16 +7,25 @@ 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}")).stdout
25
+ end
26
+
18
27
  def file_exist?(path)
19
- result = exec(Beaker::Command.new("if exist #{path} echo true"), :acceptable_exit_codes => [0, 1])
20
- result.stdout =~ /true/
28
+ result = exec(Beaker::Command.new("if exist #{path} echo true"), accept_all_exit_codes: true)
29
+ result.stdout.strip == 'true'
21
30
  end
22
31
  end
@@ -12,20 +12,35 @@ 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
+
17
+ attempts = 0
18
+
19
+ original_boot_time_str = nil
20
+ original_boot_time_line = nil
15
21
  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
22
+ original_boot_time_str = exec(Beaker::Command.new('who -b'), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
23
+ original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first
24
+
25
+ raise Beaker::Host::RebootFailure, "Could not find system boot time using 'who -b': '#{original_boot_time_str}'" unless original_boot_time_line
19
26
 
20
- if self['platform'] =~ /solaris/
21
- exec(Beaker::Command.new("reboot"), :expect_connection_failure => true)
27
+ original_boot_time = Time.parse(original_boot_time_line)
28
+
29
+ exec(Beaker::Command.new('/bin/systemctl reboot -i || reboot || /sbin/shutdown -r now'), :expect_connection_failure => true)
30
+ rescue Beaker::Host::RebootFailure => e
31
+ attempts += 1
32
+ if attempts < uptime_retries
33
+ @logger.debug("Could not get initial boot time. Will retry #{uptime_retries - attempts} more times.")
34
+ retry
22
35
  else
23
- exec(Beaker::Command.new("/sbin/shutdown -r now"), :expect_connection_failure => true)
36
+ raise
24
37
  end
25
38
  rescue Beaker::Host::CommandFailure => e
26
39
  raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
27
40
  rescue RuntimeError => e
28
41
  raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
42
+ rescue ArgumentError => e
43
+ raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
29
44
  end
30
45
 
31
46
  attempts = 0
@@ -34,18 +49,23 @@ module Unix::Exec
34
49
  @logger.debug("Waiting #{wait_time} for host to shut down.")
35
50
  sleep wait_time
36
51
 
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."
52
+ current_boot_time_str = exec(Beaker::Command.new('who -b'), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
53
+ current_boot_time_line = current_boot_time_str.lines.grep(/boot/).first
54
+
55
+ raise Beaker::Host::RebootFailure, "Could not find system boot time using 'who -b': '#{current_boot_time_str}'" unless current_boot_time_line
56
+
57
+ current_boot_time = Time.parse(current_boot_time_line)
58
+
59
+ @logger.debug("Original Boot Time: #{original_boot_time}")
60
+ @logger.debug("Current Boot Time: #{current_boot_time}")
61
+
62
+ unless current_boot_time > original_boot_time
63
+ raise Beaker::Host::RebootFailure, "Boot time did not reset. Reboot appears to have failed."
44
64
  end
45
65
  rescue Beaker::Host::RebootFailure => e
46
66
  attempts += 1
47
67
  if attempts < uptime_retries
48
- @logger.debug("Uptime did not reset. Will retry #{uptime_retries - attempts} more times.")
68
+ @logger.debug("Boot time did not reset. Will retry #{uptime_retries - attempts} more times.")
49
69
  retry
50
70
  else
51
71
  raise
@@ -54,45 +74,11 @@ module Unix::Exec
54
74
  raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
55
75
  rescue RuntimeError => e
56
76
  raise Beaker::Host::RebootFailure, "Unexpected exception in reboot: #{e.message}"
77
+ rescue ArgumentError => e
78
+ raise Beaker::Host::RebootFailure, "Unable to parse time: #{e.message}"
57
79
  end
58
80
  end
59
81
 
60
- def uptime_int(uptime_str)
61
- time_array = uptime_str.split(", ")
62
- accumulated_mins = 0
63
- time_array.each do |time_segment|
64
- value, unit = time_segment.split
65
- if unit.nil?
66
- # 20:47 case: hours & mins
67
- hours, mins = value.split(":")
68
- accumulated_mins += (hours.to_i * 60 + mins.to_i)
69
- elsif unit =~ /day(s)?/
70
- accumulated_mins += (value.to_i * 1440) # 60 * 24 = 1440
71
- elsif unit =~ /min(s)?/
72
- accumulated_mins += value.to_i
73
- else
74
- raise ArgumentError, "can't parse uptime segment: #{time_segment}"
75
- end
76
- end
77
-
78
- accumulated_mins
79
- end
80
-
81
- def parse_uptime(uptime)
82
- # get String from up to users
83
- # eg 19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31
84
- # 8:03 up 52 days, 20:47, 3 users, load averages: 1.36 1.42 1.40
85
- # 22:19 up 54 days, 1 min, 4 users, load averages: 2.08 2.06 2.27
86
- regexp = /.*up (.*)[[:space:]]+[[:digit:]]+ user.*/
87
- result = uptime.match regexp
88
- if self['platform'] =~ /solaris-/ && result[1].empty?
89
- return "0 min"
90
- end
91
- raise "Couldn't parse uptime: #{uptime}" if result.nil?
92
-
93
- result[1].strip.chomp(",")
94
- end
95
-
96
82
  def echo(msg, abs=true)
97
83
  (abs ? '/bin/echo' : 'echo') + " #{msg}"
98
84
  end
@@ -429,4 +415,19 @@ module Unix::Exec
429
415
  true
430
416
  end
431
417
 
418
+ #First path it finds for the command executable
419
+ #@param [String] command The command executable to search for
420
+ #
421
+ # @return [String] Path to the searched executable or empty string if not found
422
+ #
423
+ #@example
424
+ # host.which('ruby')
425
+ def which(command)
426
+ which_command = "which #{command}"
427
+
428
+ result = execute(which_command, :accept_all_exit_codes => true)
429
+ return '' if result.empty?
430
+
431
+ result
432
+ end
432
433
  end
@@ -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
@@ -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
  #
@@ -0,0 +1,86 @@
1
+ require 'open3'
2
+
3
+ module Beaker
4
+ class LocalConnection
5
+
6
+ attr_accessor :logger, :hostname, :ip
7
+
8
+ def initialize options = {}
9
+ @logger = options[:logger]
10
+ @ssh_env_file = File.expand_path(options[:ssh_env_file])
11
+ @hostname = 'localhost'
12
+ @ip = '127.0.0.1'
13
+ @options = options
14
+ end
15
+
16
+ def self.connect options = {}
17
+ connection = new options
18
+ connection.connect
19
+ connection
20
+ end
21
+
22
+ def connect options = {}
23
+ @logger.debug "Local connection, no connection to start"
24
+ end
25
+
26
+ def close
27
+ @logger.debug "Local connection, no connection to close"
28
+ end
29
+
30
+ def with_env(env)
31
+ backup = ENV.to_hash
32
+ ENV.replace(env)
33
+ yield
34
+ ensure
35
+ ENV.replace(backup)
36
+ end
37
+
38
+ def execute command, options = {}, stdout_callback = nil, stderr_callback = stdout_callback
39
+ result = Result.new(@hostname, command)
40
+ envs = {}
41
+ if File.readable?(@ssh_env_file)
42
+ File.foreach(@ssh_env_file) do |line|
43
+ key, value = line.split('=')
44
+ envs[key] = value
45
+ end
46
+ end
47
+
48
+ begin
49
+ clean_env = ENV.reject{ |k| k =~ /^BUNDLE|^RUBY|^GEM/ }
50
+
51
+ with_env(clean_env) do
52
+ std_out, std_err, status = Open3.capture3(envs, command)
53
+ result.stdout << std_out
54
+ result.stderr << std_err
55
+ result.exit_code = status.exitstatus
56
+ end
57
+ rescue => e
58
+ result.stderr << e.inspect
59
+ result.exit_code = 1
60
+ end
61
+
62
+ result.finalize!
63
+ @logger.last_result = result
64
+ result
65
+ end
66
+
67
+ def scp_to(source, target, _options = {})
68
+
69
+ result = Result.new(@hostname, [source, target])
70
+ begin
71
+ FileUtils.cp_r source, target
72
+ rescue Errno::ENOENT => e
73
+ @logger.warn "#{e.class} error in cp'ing. Forcing the connection to close, which should " \
74
+ "raise an error."
75
+ end
76
+
77
+ result.stdout << " CP'ed file #{source} to #{target}"
78
+ result.exit_code = 0
79
+ result
80
+ end
81
+
82
+ def scp_from(source, target, options = {})
83
+ scp_to(target, source, options)
84
+ end
85
+ end
86
+ end
@@ -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.22.1'
3
+ STRING = '4.25.0'
4
4
  end
5
5
  end
@@ -99,5 +99,59 @@ module Beaker
99
99
  to be == "set \"LD_PATH=/:/tmp\" && "
100
100
  end
101
101
  end
102
+
103
+ describe '#which' do
104
+ before do
105
+ allow(instance).to receive(:execute)
106
+ .with(where_command, :accept_all_exit_codes => true).and_return(result)
107
+ end
108
+ let(:where_command) { "cmd /C \"where ruby\"" }
109
+
110
+ context 'when only the environment variable PATH is used' do
111
+ let(:result) { "C:\\Ruby26-x64\\bin\\ruby.exe" }
112
+
113
+ it 'returns the correct path' do
114
+ response = instance.which('ruby')
115
+
116
+ expect(response).to eq(result)
117
+ end
118
+ end
119
+
120
+ context 'when command is not found' do
121
+ let(:where_command) { "cmd /C \"where unknown\"" }
122
+ let(:result) { '' }
123
+
124
+ it 'return empty string if command is not found' do
125
+ response = instance.which('unknown')
126
+
127
+ expect(response).to eq(result)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe '#mkdir_p' do
133
+ let(:dir_path) { "C:\\tmpdir\\my_dir" }
134
+ let(:beaker_command) { instance_spy(Beaker::Command) }
135
+ let(:command) {"-Command New-Item -Path '#{dir_path}' -ItemType 'directory'"}
136
+ let(:result) { instance_spy(Beaker::Result) }
137
+
138
+ before do
139
+ allow(Beaker::Command).to receive(:new).
140
+ with('powershell.exe', array_including(command)).and_return(beaker_command)
141
+ allow(instance).to receive(:exec).with(beaker_command, :acceptable_exit_codes => [0, 1]).and_return(result)
142
+ end
143
+
144
+ it 'returns true and creates folder structure' do
145
+ allow(result).to receive(:exit_code).and_return(0)
146
+
147
+ expect(instance.mkdir_p(dir_path)).to be(true)
148
+ end
149
+
150
+ it 'returns false if failed to create directory structure' do
151
+ allow(result).to receive(:exit_code).and_return(1)
152
+
153
+ expect(instance.mkdir_p(dir_path)).to be(false)
154
+ end
155
+ end
102
156
  end
103
157
  end
@@ -0,0 +1,106 @@
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
+ let(:path) { '/path/to/cat' }
29
+ let(:content) { 'file content' }
30
+ it 'reads output for file' do
31
+ expect(instance).to receive(:exec).and_return(double(stdout: content))
32
+ expect(Beaker::Command).to receive(:new).with('powershell.exe', array_including("-Command type #{path}"))
33
+ expect(instance.cat(path)).to eq(content)
34
+ end
35
+ end
36
+
37
+ describe '#file_exist?' do
38
+ let(:path) { '/path/to/test/file.txt' }
39
+ context 'file exists' do
40
+ it 'returns true' do
41
+ expect(instance).to receive(:exec).and_return(double(stdout: "true\n"))
42
+ expect(Beaker::Command).to receive(:new).with("if exist #{path} echo true")
43
+ expect(instance.file_exist?(path)).to eq(true)
44
+ end
45
+ end
46
+
47
+ context 'file does not exist' do
48
+ it 'returns false' do
49
+ expect(instance).to receive(:exec).and_return(double(stdout: ""))
50
+ expect(Beaker::Command).to receive(:new).with("if exist #{path} echo true")
51
+ expect(instance.file_exist?(path)).to eq(false)
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#tmpdir' do
57
+ let(:tmp_path) { 'C:\\tmpdir\\' }
58
+ let(:fake_command) { Beaker::Command.new('command1') }
59
+
60
+ before do
61
+ allow(instance).to receive(:execute).with(anything)
62
+ end
63
+
64
+ context 'with dirname sent' do
65
+ let(:name) { 'my_dir' }
66
+ it 'returns the path to my_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 New-Item -Path '#{tmp_path}' -Force -Name '#{name}' -ItemType 'directory'")).
74
+ and_return(fake_command)
75
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(true)
76
+
77
+ expect(instance.tmpdir(name)).to eq(File.join(tmp_path, name))
78
+ end
79
+ end
80
+
81
+ context 'without dirname sent' do
82
+ let(:name) { '' }
83
+ let(:random_dir) { 'dirname' }
84
+
85
+ it 'returns the path to random name dir' do
86
+ expect(Beaker::Command).to receive(:new).
87
+ with('powershell.exe', array_including('-Command [System.IO.Path]::GetTempPath()')).
88
+ and_return(fake_command)
89
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(double(stdout: tmp_path))
90
+
91
+ expect(Beaker::Command).to receive(:new).
92
+ with('powershell.exe', array_including('-Command [System.IO.Path]::GetRandomFileName()')).
93
+ and_return(fake_command)
94
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(double(stdout: random_dir))
95
+
96
+ expect(Beaker::Command).to receive(:new).
97
+ with('powershell.exe', array_including("-Command New-Item -Path '#{tmp_path}' -Force -Name '#{random_dir}' -ItemType 'directory'")).
98
+ and_return(fake_command)
99
+ expect(instance).to receive(:exec).with(instance_of(Beaker::Command)).and_return(true)
100
+
101
+ expect(instance.tmpdir).to eq(File.join(tmp_path, random_dir))
102
+ end
103
+ end
104
+ end
105
+ end
106
+ 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
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
228
247
 
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
248
+ context 'incorrect time string' do
249
+ context 'original time' do
250
+ let (:boot_time_initial_stdout) { 'boot bad' }
235
251
 
236
- expect(instance.reboot).to be(nil)
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
@@ -272,40 +313,32 @@ module Beaker
272
313
 
273
314
  end
274
315
 
275
- describe '#parse_uptime' do
276
- it 'parses variation of uptime string' do
277
- expect(instance.parse_uptime("19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31")).to be == "14 mins"
278
- end
279
- it 'parses variation 2 of uptime string' do
280
- expect(instance.parse_uptime("8:03 up 52 days, 20:47, 3 users, load averages: 1.36 1.42 1.40")).to be == "52 days, 20:47"
281
- end
282
- it 'parses variation 3 of uptime string' do
283
- expect(instance.parse_uptime("22:19 up 54 days, 1 min, 4 users, load averages: 2.08 2.06 2.27")).to be == "54 days, 1 min"
284
- end
285
- it 'parses variation 4 of uptime string' do
286
- expect(instance.parse_uptime("18:44:45 up 5 min, 0 users, load average: 0.14, 0.11, 0.05")).to be == "5 min"
316
+ describe '#which' do
317
+ before do
318
+ allow(instance).to receive(:execute)
319
+ .with(where_command, :accept_all_exit_codes => true).and_return(result)
287
320
  end
288
- it 'parses solaris\'s "just up" without time message' do
289
- opts['platform'] = 'solaris-11-x86_64'
290
- expect(instance.parse_uptime("10:05am up 0 users, load average: 0.66, 0.14, 0.05")).to be == "0 min"
291
- end
292
- end
293
321
 
294
- describe '#uptime_int' do
295
- it 'parses time segment variation into a minute value' do
296
- expect(instance.uptime_int("14 mins")).to be == 14
297
- end
298
- it 'parses time segment variation 2 into a minute value' do
299
- expect(instance.uptime_int("52 days, 20:47")).to be == 76127
300
- end
301
- it 'parses time segment variation 3 into a minute value' do
302
- expect(instance.uptime_int("54 days, 1 min")).to be == 77761
322
+ context 'when only the environment variable PATH is used' do
323
+ let(:where_command) { "which ruby" }
324
+ let(:result) { "/usr/bin/ruby.exe" }
325
+
326
+ it 'returns the correct path' do
327
+ response = instance.which('ruby')
328
+
329
+ expect(response).to eq(result)
303
330
  end
304
- it 'parses time segment variation 4 into a minute value' do
305
- expect(instance.uptime_int("54 days")).to be == 77760
306
331
  end
307
- it 'raises if we pass garbage to it' do
308
- expect { instance.uptime_int("solaris roxx my soxx") }.to raise_error
332
+
333
+ context 'when command is not found' do
334
+ let(:where_command) { "which unknown" }
335
+ let(:result) { '' }
336
+
337
+ it 'return empty string if command is not found' do
338
+ response = instance.which('unknown')
339
+
340
+ expect(response).to eq(result)
341
+ end
309
342
  end
310
343
  end
311
344
  end
@@ -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
@@ -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
@@ -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
@@ -349,7 +349,13 @@ module Beaker
349
349
  allow( result ).to receive( :exit_code ).and_return( 0 )
350
350
  allow( host ).to receive( :exec ).and_return( result )
351
351
 
352
- expect( Beaker::Command ).to receive(:new).with("if not exist test\\test\\test (md test\\test\\test)")
352
+ expect( Beaker::Command ).to receive(:new).
353
+ with("powershell.exe", ["-ExecutionPolicy Bypass",
354
+ "-InputFormat None",
355
+ "-NoLogo",
356
+ "-NoProfile",
357
+ "-NonInteractive",
358
+ "-Command New-Item -Path 'test\\test\\test' -ItemType 'directory'"])
353
359
  expect( host.mkdir_p('test/test/test') ).to be == true
354
360
 
355
361
  end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'net/ssh'
3
+
4
+ module Beaker
5
+ describe LocalConnection do
6
+ let( :options ) { { :logger => double('logger').as_null_object, :ssh_env_file => '/path/to/ssh/file'} }
7
+ subject(:connection) { LocalConnection.new(options) }
8
+
9
+ before :each do
10
+ allow( subject ).to receive(:sleep)
11
+ end
12
+
13
+ describe '#self.connect' do
14
+ it 'loggs message' do
15
+ expect(options[:logger]).to receive(:debug).with('Local connection, no connection to start')
16
+ connection_constructor = LocalConnection.connect(options)
17
+ expect( connection_constructor ).to be_a_kind_of LocalConnection
18
+ end
19
+ end
20
+
21
+ describe '#close' do
22
+ it 'logs message' do
23
+ expect(options[:logger]).to receive(:debug).with('Local connection, no connection to close')
24
+ connection.close
25
+ end
26
+ end
27
+
28
+ describe '#with_env' do
29
+ it 'sets envs temporarily' do
30
+ connection.connect
31
+ connection.with_env({'my_env' => 'my_env_value'}) do
32
+ expect(ENV.to_hash).to include({'my_env' => 'my_env_value'})
33
+ end
34
+ expect(ENV.to_hash).not_to include({'my_env' => 'my_env_value'})
35
+ end
36
+ end
37
+
38
+ describe '#execute' do
39
+ it 'calls open3' do
40
+ expect( Open3 ).to receive( :capture3 ).with({}, 'my_command')
41
+ connection.connect
42
+ expect(connection.execute('my_command')).to be_a_kind_of Result
43
+ end
44
+
45
+ it 'sets stdout, stderr and exitcode' do
46
+ allow(Open3).to receive(:capture3).and_return(['stdout', 'stderr', double({exitstatus: 0})])
47
+ connection.connect
48
+ result = connection.execute('my_command')
49
+ expect(result.exit_code).to eq(0)
50
+ expect(result.stdout).to eq('stdout')
51
+ expect(result.stderr).to eq('stderr')
52
+ end
53
+
54
+ it 'sets logger last_result' do
55
+ allow(Open3).to receive(:capture3).and_return(['stdout', 'stderr', double({exitstatus: 0})])
56
+ expect(options[:logger]).to receive(:last_result=).with(an_instance_of(Result))
57
+ connection.connect
58
+ connection.execute('my_command')
59
+ end
60
+
61
+ it 'sets exitcode to 1, when Open3 raises exeception' do
62
+ allow(Open3).to receive(:capture3).and_raise Errno::ENOENT
63
+ connection.connect
64
+ result = connection.execute('my_failing_command')
65
+ expect(result.exit_code).to eq(1)
66
+ end
67
+ end
68
+
69
+ describe '#scp_to' do
70
+ let(:source) { '/source/path' }
71
+ let(:dest) { '/dest/path' }
72
+
73
+ it 'calls FileUtils.cp_r' do
74
+ connection.connect
75
+ expect(FileUtils).to receive(:cp_r).with(source, dest)
76
+ connection.scp_to(source, dest)
77
+ end
78
+
79
+ it 'returns and Result object' do
80
+ expect(FileUtils).to receive(:cp_r).and_return(true)
81
+ connection.connect
82
+ result = connection.scp_to(source, dest)
83
+ expect(result.exit_code).to eq(0)
84
+ expect(result.stdout).to eq(" CP'ed file #{source} to #{dest}")
85
+ end
86
+
87
+ it 'catches exception and logs warning message' do
88
+ allow(FileUtils).to receive(:cp_r).and_raise Errno::ENOENT
89
+ expect(options[:logger]).to receive(:warn).with("Errno::ENOENT error in cp'ing. Forcing the connection to close, which should raise an error.")
90
+ connection.connect
91
+ connection.scp_to(source, dest)
92
+ end
93
+ end
94
+
95
+ describe '#scp_from' do
96
+ let(:source) { '/source/path' }
97
+ let(:dest) { '/dest/path' }
98
+
99
+ it 'callse scp_to with reversed params' do
100
+ expect(connection).to receive(:scp_to).with(dest, source, {})
101
+ connection.connect
102
+ connection.scp_from(source, dest)
103
+ end
104
+ end
105
+ end
106
+ 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.25.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-06-15 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
@@ -576,6 +576,7 @@ files:
576
576
  - lib/beaker/hypervisor.rb
577
577
  - lib/beaker/hypervisor/noop.rb
578
578
  - lib/beaker/junit.xsl
579
+ - lib/beaker/local_connection.rb
579
580
  - lib/beaker/logger.rb
580
581
  - lib/beaker/logger_junit.rb
581
582
  - lib/beaker/network_manager.rb
@@ -630,6 +631,7 @@ files:
630
631
  - spec/beaker/host/mac/user_spec.rb
631
632
  - spec/beaker/host/mac_spec.rb
632
633
  - spec/beaker/host/pswindows/exec_spec.rb
634
+ - spec/beaker/host/pswindows/file_spec.rb
633
635
  - spec/beaker/host/pswindows/user_spec.rb
634
636
  - spec/beaker/host/pswindows_spec.rb
635
637
  - spec/beaker/host/unix/exec_spec.rb
@@ -645,6 +647,7 @@ files:
645
647
  - spec/beaker/host_prebuilt_steps_spec.rb
646
648
  - spec/beaker/host_spec.rb
647
649
  - spec/beaker/hypervisor/hypervisor_spec.rb
650
+ - spec/beaker/localhost_connection_spec.rb
648
651
  - spec/beaker/logger_junit_spec.rb
649
652
  - spec/beaker/logger_spec.rb
650
653
  - spec/beaker/network_manager_spec.rb
@@ -698,7 +701,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
698
701
  - !ruby/object:Gem::Version
699
702
  version: '0'
700
703
  requirements: []
701
- rubygems_version: 3.0.6
704
+ rubygems_version: 3.0.8
702
705
  signing_key:
703
706
  specification_version: 4
704
707
  summary: Let's test Puppet!