beaker 4.23.0 → 4.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -1
- data/lib/beaker/host.rb +6 -1
- data/lib/beaker/host/pswindows/exec.rb +18 -3
- data/lib/beaker/host/pswindows/file.rb +3 -3
- data/lib/beaker/host/unix/exec.rb +35 -40
- data/lib/beaker/host/windows/exec.rb +19 -0
- data/lib/beaker/local_connection.rb +86 -0
- data/lib/beaker/ssh_connection.rb +10 -0
- data/lib/beaker/version.rb +1 -1
- data/spec/beaker/host/pswindows/exec_spec.rb +54 -0
- data/spec/beaker/host/pswindows/file_spec.rb +23 -4
- data/spec/beaker/host/unix/exec_spec.rb +24 -32
- data/spec/beaker/host/windows/exec_spec.rb +18 -0
- data/spec/beaker/host_spec.rb +7 -1
- data/spec/beaker/localhost_connection_spec.rb +106 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c39df762f99d0590a8a754edc8d6a3a411137df0980823ac7d008eda11f3a81d
|
4
|
+
data.tar.gz: 9e43461bed058372c69307cd73e69b0d8e72998a93fcd5dae345cb9a96aa09c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9abeaeb61ef396755e86fc5659ff252d7d7a3bf9fee664fab97411bce22313912e254708cd64ded4c6501d10d853ac2b5c58806be109113d6ba885350b87a7d5
|
7
|
+
data.tar.gz: a1e6c0542a97715a9d0cf50247b3625fc5e9936137a37235374cc0853e15b0b6726838034f4c5da8327bd00bdd2bf056310754c1993bbe26f4114ebe5501acea
|
data/CHANGELOG.md
CHANGED
@@ -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
|
+
# [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
|
|
data/lib/beaker/host.rb
CHANGED
@@ -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
|
-
|
108
|
-
|
109
|
-
|
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"), :
|
29
|
-
result.stdout
|
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
|
-
|
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
|
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
|
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
|
data/lib/beaker/version.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
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 '#
|
317
|
-
|
318
|
-
|
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
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
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
|
-
|
349
|
-
|
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
|
data/spec/beaker/host_spec.rb
CHANGED
@@ -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).
|
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.
|
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-
|
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.
|
704
|
+
rubygems_version: 3.0.8
|
703
705
|
signing_key:
|
704
706
|
specification_version: 4
|
705
707
|
summary: Let's test Puppet!
|