beaker 4.23.0 → 4.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90b746c013603a55023f75c05cfa79a8301fa58729b82a1dcc677067dde77ab1
4
- data.tar.gz: f76631826758f41afb1517224fed593bdf988278bb1c18a23dd6ddea0d74ca8a
3
+ metadata.gz: c39df762f99d0590a8a754edc8d6a3a411137df0980823ac7d008eda11f3a81d
4
+ data.tar.gz: 9e43461bed058372c69307cd73e69b0d8e72998a93fcd5dae345cb9a96aa09c7
5
5
  SHA512:
6
- metadata.gz: 24dc7d2592f0de06a51a6534f9f0014a5075851295926c696b5fd0d2ea835f7f95bf4f630f12c91f645fccf33ab43eb3acb8fe33fd1a841e0ae4bd52a529e3a8
7
- data.tar.gz: 9556e24844dd480c3bab6b30bb6e29db3b34ae4e6a76fd53f47c76fb018d805804eb1e2de87a6798850e1880ea5960cfd90902a99856caff8284f172f0b5f4f6
6
+ metadata.gz: 9abeaeb61ef396755e86fc5659ff252d7d7a3bf9fee664fab97411bce22313912e254708cd64ded4c6501d10d853ac2b5c58806be109113d6ba885350b87a7d5
7
+ data.tar.gz: a1e6c0542a97715a9d0cf50247b3625fc5e9936137a37235374cc0853e15b0b6726838034f4c5da8327bd00bdd2bf056310754c1993bbe26f4114ebe5501acea
@@ -20,7 +20,41 @@ 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.23.0...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)
24
58
 
25
59
  # [4.23.0](https://github.com/puppetlabs/beaker/compare/4.22.1...4.23.0)
26
60
 
@@ -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
@@ -21,11 +21,11 @@ module PSWindows::File
21
21
  end
22
22
 
23
23
  def cat(path)
24
- exec(powershell("type #{path}"))
24
+ exec(powershell("type #{path}")).stdout
25
25
  end
26
26
 
27
27
  def file_exist?(path)
28
- result = exec(Beaker::Command.new("if exist #{path} echo true"), :acceptable_exit_codes => [0, 1])
29
- result.stdout =~ /true/
28
+ result = exec(Beaker::Command.new("if exist #{path} echo true"), accept_all_exit_codes: true)
29
+ result.stdout.strip == 'true'
30
30
  end
31
31
  end
@@ -14,15 +14,27 @@ module Unix::Exec
14
14
  def reboot(wait_time=10, max_connection_tries=9, uptime_retries=18)
15
15
  require 'time'
16
16
 
17
+ attempts = 0
18
+
19
+ original_boot_time_str = nil
20
+ original_boot_time_line = nil
17
21
  begin
18
22
  original_boot_time_str = exec(Beaker::Command.new('who -b'), {:max_connection_tries => max_connection_tries, :silent => true}).stdout
19
23
  original_boot_time_line = original_boot_time_str.lines.grep(/boot/).first
20
24
 
21
- raise Beaker::Host::RebootFailure, "Could not find system boot time using 'who -b': #{original_boot_time_str}" unless original_boot_time_line
25
+ raise Beaker::Host::RebootFailure, "Could not find system boot time using 'who -b': '#{original_boot_time_str}'" unless original_boot_time_line
22
26
 
23
27
  original_boot_time = Time.parse(original_boot_time_line)
24
28
 
25
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
35
+ else
36
+ raise
37
+ end
26
38
  rescue Beaker::Host::CommandFailure => e
27
39
  raise Beaker::Host::RebootFailure, "Command failed when attempting to reboot: #{e.message}"
28
40
  rescue RuntimeError => e
@@ -38,7 +50,11 @@ module Unix::Exec
38
50
  sleep wait_time
39
51
 
40
52
  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)
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)
42
58
 
43
59
  @logger.debug("Original Boot Time: #{original_boot_time}")
44
60
  @logger.debug("Current Boot Time: #{current_boot_time}")
@@ -63,42 +79,6 @@ module Unix::Exec
63
79
  end
64
80
  end
65
81
 
66
- def uptime_int(uptime_str)
67
- time_array = uptime_str.split(", ")
68
- accumulated_mins = 0
69
- time_array.each do |time_segment|
70
- value, unit = time_segment.split
71
- if unit.nil?
72
- # 20:47 case: hours & mins
73
- hours, mins = value.split(":")
74
- accumulated_mins += (hours.to_i * 60 + mins.to_i)
75
- elsif unit =~ /day(s)?/
76
- accumulated_mins += (value.to_i * 1440) # 60 * 24 = 1440
77
- elsif unit =~ /min(s)?/
78
- accumulated_mins += value.to_i
79
- else
80
- raise ArgumentError, "can't parse uptime segment: #{time_segment}"
81
- end
82
- end
83
-
84
- accumulated_mins
85
- end
86
-
87
- def parse_uptime(uptime)
88
- # get String from up to users
89
- # eg 19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31
90
- # 8:03 up 52 days, 20:47, 3 users, load averages: 1.36 1.42 1.40
91
- # 22:19 up 54 days, 1 min, 4 users, load averages: 2.08 2.06 2.27
92
- regexp = /.*up (.*)[[:space:]]+[[:digit:]]+ user.*/
93
- result = uptime.match regexp
94
- if self['platform'] =~ /solaris-/ && result[1].empty?
95
- return "0 min"
96
- end
97
- raise "Couldn't parse uptime: #{uptime}" if result.nil?
98
-
99
- result[1].strip.chomp(",")
100
- end
101
-
102
82
  def echo(msg, abs=true)
103
83
  (abs ? '/bin/echo' : 'echo') + " #{msg}"
104
84
  end
@@ -133,7 +113,7 @@ module Unix::Exec
133
113
  # @param [String] dir The directory structure to create on the host
134
114
  # @return [Boolean] True, if directory construction succeeded, otherwise False
135
115
  def mkdir_p dir
136
- cmd = "mkdir -p \"#{dir}\""
116
+ cmd = "mkdir -p #{dir}"
137
117
  result = exec(Beaker::Command.new(cmd), :acceptable_exit_codes => [0, 1])
138
118
  result.exit_code == 0
139
119
  end
@@ -150,7 +130,7 @@ module Unix::Exec
150
130
  # @param [Boolean] rm Remove the destination prior to move
151
131
  def mv orig, dest, rm=true
152
132
  rm_rf dest unless !rm
153
- execute("mv \"#{orig}\" \"#{dest}\"")
133
+ execute("mv #{orig} #{dest}")
154
134
  end
155
135
 
156
136
  # Attempt to ping the provided target hostname
@@ -435,4 +415,19 @@ module Unix::Exec
435
415
  true
436
416
  end
437
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
438
433
  end
@@ -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,16 @@ 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
+ # Work around net-ssh 6+ incompatibilities
73
+ if ssh_opts.include?(:strict_host_key_checking) && (Net::SSH::Version::CURRENT.major > 5)
74
+ strict_host_key_checking = ssh_opts.delete(:strict_host_key_checking)
75
+
76
+ unless ssh_opts[:verify_host_key].is_a?(Symbol)
77
+ ssh_opts[:verify_host_key] ||= strict_host_key_checking ? :always : :never
78
+ end
79
+ end
80
+
71
81
  Net::SSH.start(host, user, ssh_opts)
72
82
  rescue *RETRYABLE_EXCEPTIONS => e
73
83
  if try <= max_connection_tries
@@ -1,5 +1,5 @@
1
1
  module Beaker
2
2
  module Version
3
- STRING = '4.23.0'
3
+ STRING = '4.26.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
@@ -25,11 +25,31 @@ module Beaker
25
25
  let (:instance) { PSWindowsFileTest.new(opts, logger) }
26
26
 
27
27
  describe '#cat' do
28
+ let(:path) { '/path/to/cat' }
29
+ let(:content) { 'file content' }
28
30
  it 'reads output for file' do
29
- path = '/path/to/delete'
30
- expect(instance).to receive(:exec)
31
+ expect(instance).to receive(:exec).and_return(double(stdout: content))
31
32
  expect(Beaker::Command).to receive(:new).with('powershell.exe', array_including("-Command type #{path}"))
32
- instance.cat(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
33
53
  end
34
54
  end
35
55
 
@@ -39,7 +59,6 @@ module Beaker
39
59
 
40
60
  before do
41
61
  allow(instance).to receive(:execute).with(anything)
42
-
43
62
  end
44
63
 
45
64
  context 'with dirname sent' do
@@ -40,13 +40,13 @@ module Beaker
40
40
 
41
41
  it 'rm first' do
42
42
  expect( instance ).to receive(:execute).with("rm -rf #{destination}").and_return(0)
43
- expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
43
+ expect( instance ).to receive(:execute).with("mv #{origin} #{destination}").and_return(0)
44
44
  expect( instance.mv(origin, destination) ).to be === 0
45
45
 
46
46
  end
47
47
 
48
48
  it 'does not rm' do
49
- expect( instance ).to receive(:execute).with("mv \"#{origin}\" \"#{destination}\"").and_return(0)
49
+ expect( instance ).to receive(:execute).with("mv #{origin} #{destination}").and_return(0)
50
50
  expect( instance.mv(origin, destination, false) ).to be === 0
51
51
  end
52
52
  end
@@ -313,40 +313,32 @@ module Beaker
313
313
 
314
314
  end
315
315
 
316
- describe '#parse_uptime' do
317
- it 'parses variation of uptime string' do
318
- expect(instance.parse_uptime("19:52 up 14 mins, 2 users, load averages: 2.95 4.19 4.31")).to be == "14 mins"
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)
319
320
  end
320
- it 'parses variation 2 of uptime string' do
321
- 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"
322
- end
323
- it 'parses variation 3 of uptime string' do
324
- 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"
325
- end
326
- it 'parses variation 4 of uptime string' do
327
- expect(instance.parse_uptime("18:44:45 up 5 min, 0 users, load average: 0.14, 0.11, 0.05")).to be == "5 min"
328
- end
329
- it 'parses solaris\'s "just up" without time message' do
330
- opts['platform'] = 'solaris-11-x86_64'
331
- expect(instance.parse_uptime("10:05am up 0 users, load average: 0.66, 0.14, 0.05")).to be == "0 min"
332
- end
333
- end
334
321
 
335
- describe '#uptime_int' do
336
- it 'parses time segment variation into a minute value' do
337
- expect(instance.uptime_int("14 mins")).to be == 14
338
- end
339
- it 'parses time segment variation 2 into a minute value' do
340
- expect(instance.uptime_int("52 days, 20:47")).to be == 76127
341
- end
342
- it 'parses time segment variation 3 into a minute value' do
343
- 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)
344
330
  end
345
- it 'parses time segment variation 4 into a minute value' do
346
- expect(instance.uptime_int("54 days")).to be == 77760
347
331
  end
348
- it 'raises if we pass garbage to it' do
349
- 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
350
342
  end
351
343
  end
352
344
  end
@@ -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
@@ -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.23.0
4
+ version: 4.26.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-19 00:00:00.000000000 Z
11
+ date: 2020-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -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
@@ -646,6 +647,7 @@ files:
646
647
  - spec/beaker/host_prebuilt_steps_spec.rb
647
648
  - spec/beaker/host_spec.rb
648
649
  - spec/beaker/hypervisor/hypervisor_spec.rb
650
+ - spec/beaker/localhost_connection_spec.rb
649
651
  - spec/beaker/logger_junit_spec.rb
650
652
  - spec/beaker/logger_spec.rb
651
653
  - spec/beaker/network_manager_spec.rb
@@ -699,7 +701,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
699
701
  - !ruby/object:Gem::Version
700
702
  version: '0'
701
703
  requirements: []
702
- rubygems_version: 3.0.6
704
+ rubygems_version: 3.0.8
703
705
  signing_key:
704
706
  specification_version: 4
705
707
  summary: Let's test Puppet!