beaker 4.23.1 → 4.27.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 +4 -4
- data/.github/dependabot.yml +8 -0
- data/.travis.yml +2 -4
- data/CHANGELOG.md +49 -1
- data/CODEOWNERS +0 -2
- data/Rakefile +1 -4
- data/beaker.gemspec +2 -2
- 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 +33 -38
- 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 +22 -30
- data/spec/beaker/host_spec.rb +7 -1
- data/spec/beaker/localhost_connection_spec.rb +106 -0
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b7bc325aade2e41145790de7c1c5d8c3f07b054dc22999762cbbe812f81deeca
|
|
4
|
+
data.tar.gz: 403bc79d97df6b8b30d59a5caa8ef26434e1adfc6420025cc15d3267c149aaef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe7a3e52bc3db292ae174f97f2c93b2455e032693956931b60e6bc5cc1c0caf84be93f92d877d9bcdb7698f77e3367c08e0781e2e858b5c9a5d335d99d6b059f
|
|
7
|
+
data.tar.gz: 6616a6a1bb3399a30defc9536b64b67d7f742d67dddf09f8dad70604a0df9b9c4460c414080e70f42001495bdb47e1dcab8a9354210fb67348453ea065933707
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -20,7 +20,55 @@ 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.27.0...master)
|
|
24
|
+
|
|
25
|
+
# [4.27.0](https://github.com/puppetlabs/beaker/compare/4.26.0...4.27.0) - 07-24-2020
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Updated dependency versions and minimum Ruby version in gemspec to Ruby 2.4, which is the minimum
|
|
30
|
+
version Beaker will run with.
|
|
31
|
+
- Added Travis unit testing and disabled Jenkins integrations in preparation for transferring the
|
|
32
|
+
repo to Vox Pupuli
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# [4.26.0](https://github.com/puppetlabs/beaker/compare/4.25.0...4.26.0)
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Fixed deprecated SSH option handling for `verify_ssh_key` being passed into Net::SSH. #1655
|
|
40
|
+
|
|
41
|
+
### Removed
|
|
42
|
+
|
|
43
|
+
- Removed deprecated use of `paranoid` flag with Net::SSH. #1655
|
|
44
|
+
|
|
45
|
+
# [4.25.0](https://github.com/puppetlabs/beaker/compare/4.24.0...4.25.0)
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- Execution of Beaker directly through ruby on localhost #1637 ([#1637](https://github.com/puppetlabs/beaker/pull/1637))
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Reliability improvements to the `Host#reboot` method ([#1656](https://github.com/puppetlabs/beaker/pull/1656)) ([#1659](https://github.com/puppetlabs/beaker/pull/1659))
|
|
54
|
+
|
|
55
|
+
# [4.24.0](https://github.com/puppetlabs/beaker/compare/4.23.0...4.24.0) - 2020-06-05
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- Host method which ([#1651](https://github.com/puppetlabs/beaker/pull/1651))
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- Fixed implementation for cat and file_exists? host methods for PSWindows ([#1654](https://github.com/puppetlabs/beaker/pull/1654))
|
|
64
|
+
- Fixed implementation for mkdir_p host method for PSWindows ([#1657](https://github.com/puppetlabs/beaker/pull/1657))
|
|
65
|
+
|
|
66
|
+
# [4.23.2](https://github.com/puppetlabs/beaker/compare/4.23.1...4.23.2)
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- Fixed Beaker's behavior when the `strict_host_key_checking` option is
|
|
71
|
+
provided in the SSH config and Net-SSH > 5 is specified. (#1652)
|
|
24
72
|
|
|
25
73
|
# [4.23.1](https://github.com/puppetlabs/beaker/compare/4.23.0...4.23.1)
|
|
26
74
|
|
data/CODEOWNERS
CHANGED
data/Rakefile
CHANGED
|
@@ -26,10 +26,7 @@ task :history do
|
|
|
26
26
|
Rake::Task['history:gen'].invoke
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
task :
|
|
30
|
-
Rake::Task['yard'].invoke if !Beaker::Shared::Semvar.version_is_less(RUBY_VERSION, '2.0.0')
|
|
31
|
-
Rake::Task['spec'].invoke
|
|
32
|
-
end
|
|
29
|
+
task travis: [:yard, :test]
|
|
33
30
|
|
|
34
31
|
module HarnessOptions
|
|
35
32
|
defaults = {
|
data/beaker.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
s.required_ruby_version = Gem::Requirement.new('>= 2.
|
|
21
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.4')
|
|
22
22
|
|
|
23
23
|
# Testing dependencies
|
|
24
24
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
@@ -39,7 +39,7 @@ Gem::Specification.new do |s|
|
|
|
39
39
|
# Run time dependencies
|
|
40
40
|
s.add_runtime_dependency 'minitest', '~> 5.4'
|
|
41
41
|
s.add_runtime_dependency 'minitar', '~> 0.6'
|
|
42
|
-
s.add_runtime_dependency 'pry-byebug', '~> 3.
|
|
42
|
+
s.add_runtime_dependency 'pry-byebug', '~> 3.9'
|
|
43
43
|
# pry-byebug can have issues with native readline libs so add rb-readline
|
|
44
44
|
s.add_runtime_dependency 'rb-readline', '~> 0.5.3'
|
|
45
45
|
|
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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
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.27.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-07-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -176,14 +176,14 @@ dependencies:
|
|
|
176
176
|
requirements:
|
|
177
177
|
- - "~>"
|
|
178
178
|
- !ruby/object:Gem::Version
|
|
179
|
-
version: '3.
|
|
179
|
+
version: '3.9'
|
|
180
180
|
type: :runtime
|
|
181
181
|
prerelease: false
|
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
|
183
183
|
requirements:
|
|
184
184
|
- - "~>"
|
|
185
185
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: '3.
|
|
186
|
+
version: '3.9'
|
|
187
187
|
- !ruby/object:Gem::Dependency
|
|
188
188
|
name: rb-readline
|
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -352,6 +352,7 @@ executables:
|
|
|
352
352
|
extensions: []
|
|
353
353
|
extra_rdoc_files: []
|
|
354
354
|
files:
|
|
355
|
+
- ".github/dependabot.yml"
|
|
355
356
|
- ".gitignore"
|
|
356
357
|
- ".rspec"
|
|
357
358
|
- ".simplecov"
|
|
@@ -576,6 +577,7 @@ files:
|
|
|
576
577
|
- lib/beaker/hypervisor.rb
|
|
577
578
|
- lib/beaker/hypervisor/noop.rb
|
|
578
579
|
- lib/beaker/junit.xsl
|
|
580
|
+
- lib/beaker/local_connection.rb
|
|
579
581
|
- lib/beaker/logger.rb
|
|
580
582
|
- lib/beaker/logger_junit.rb
|
|
581
583
|
- lib/beaker/network_manager.rb
|
|
@@ -646,6 +648,7 @@ files:
|
|
|
646
648
|
- spec/beaker/host_prebuilt_steps_spec.rb
|
|
647
649
|
- spec/beaker/host_spec.rb
|
|
648
650
|
- spec/beaker/hypervisor/hypervisor_spec.rb
|
|
651
|
+
- spec/beaker/localhost_connection_spec.rb
|
|
649
652
|
- spec/beaker/logger_junit_spec.rb
|
|
650
653
|
- spec/beaker/logger_spec.rb
|
|
651
654
|
- spec/beaker/network_manager_spec.rb
|
|
@@ -692,14 +695,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
692
695
|
requirements:
|
|
693
696
|
- - ">="
|
|
694
697
|
- !ruby/object:Gem::Version
|
|
695
|
-
version: 2.
|
|
698
|
+
version: '2.4'
|
|
696
699
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
697
700
|
requirements:
|
|
698
701
|
- - ">="
|
|
699
702
|
- !ruby/object:Gem::Version
|
|
700
703
|
version: '0'
|
|
701
704
|
requirements: []
|
|
702
|
-
rubygems_version: 3.0.
|
|
705
|
+
rubygems_version: 3.0.8
|
|
703
706
|
signing_key:
|
|
704
707
|
specification_version: 4
|
|
705
708
|
summary: Let's test Puppet!
|