sshkit 1.7.1 → 1.8.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/.travis.yml +2 -2
- data/BREAKING_API_WISHLIST.md +14 -0
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +43 -0
- data/EXAMPLES.md +265 -169
- data/Gemfile +7 -0
- data/README.md +274 -9
- data/RELEASING.md +16 -8
- data/Rakefile +8 -0
- data/lib/sshkit.rb +0 -9
- data/lib/sshkit/all.rb +6 -4
- data/lib/sshkit/backends/abstract.rb +42 -42
- data/lib/sshkit/backends/connection_pool.rb +57 -8
- data/lib/sshkit/backends/local.rb +21 -50
- data/lib/sshkit/backends/netssh.rb +45 -98
- data/lib/sshkit/backends/printer.rb +3 -23
- data/lib/sshkit/backends/skipper.rb +4 -8
- data/lib/sshkit/color.rb +51 -20
- data/lib/sshkit/command.rb +68 -47
- data/lib/sshkit/configuration.rb +38 -5
- data/lib/sshkit/deprecation_logger.rb +17 -0
- data/lib/sshkit/formatters/abstract.rb +28 -4
- data/lib/sshkit/formatters/black_hole.rb +1 -2
- data/lib/sshkit/formatters/dot.rb +3 -10
- data/lib/sshkit/formatters/pretty.rb +31 -56
- data/lib/sshkit/formatters/simple_text.rb +6 -44
- data/lib/sshkit/host.rb +5 -6
- data/lib/sshkit/logger.rb +0 -1
- data/lib/sshkit/mapping_interaction_handler.rb +47 -0
- data/lib/sshkit/runners/parallel.rb +1 -1
- data/lib/sshkit/runners/sequential.rb +1 -1
- data/lib/sshkit/version.rb +1 -1
- data/sshkit.gemspec +0 -1
- data/test/functional/backends/test_local.rb +14 -1
- data/test/functional/backends/test_netssh.rb +58 -50
- data/test/helper.rb +2 -2
- data/test/unit/backends/test_abstract.rb +145 -0
- data/test/unit/backends/test_connection_pool.rb +27 -2
- data/test/unit/backends/test_printer.rb +47 -47
- data/test/unit/formatters/test_custom.rb +65 -0
- data/test/unit/formatters/test_dot.rb +25 -32
- data/test/unit/formatters/test_pretty.rb +114 -22
- data/test/unit/formatters/test_simple_text.rb +83 -0
- data/test/unit/test_color.rb +69 -5
- data/test/unit/test_command.rb +53 -18
- data/test/unit/test_command_map.rb +0 -4
- data/test/unit/test_configuration.rb +47 -7
- data/test/unit/test_coordinator.rb +45 -52
- data/test/unit/test_deprecation_logger.rb +38 -0
- data/test/unit/test_host.rb +3 -4
- data/test/unit/test_logger.rb +0 -1
- data/test/unit/test_mapping_interaction_handler.rb +101 -0
- metadata +37 -41
- data/lib/sshkit/utils/capture_output_methods.rb +0 -13
- data/test/functional/test_coordinator.rb +0 -17
@@ -1,54 +1,16 @@
|
|
1
|
-
|
2
1
|
module SSHKit
|
3
2
|
|
4
3
|
module Formatter
|
5
4
|
|
6
|
-
class SimpleText <
|
7
|
-
|
8
|
-
def write(obj)
|
9
|
-
return if obj.verbosity < SSHKit.config.output_verbosity
|
10
|
-
case obj
|
11
|
-
when SSHKit::Command then write_command(obj)
|
12
|
-
when SSHKit::LogMessage then write_log_message(obj)
|
13
|
-
else
|
14
|
-
original_output << "Output formatter doesn't know how to handle #{obj.class}\n"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
alias :<< :write
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def write_command(command)
|
22
|
-
unless command.started?
|
23
|
-
original_output << "Running #{String(command)} #{command.host.user ? "as #{command.host.user}@" : "on "}#{command.host}\n"
|
24
|
-
if SSHKit.config.output_verbosity == Logger::DEBUG
|
25
|
-
original_output << "Command: #{command.to_command}" + "\n"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
if SSHKit.config.output_verbosity == Logger::DEBUG
|
30
|
-
unless command.stdout.empty?
|
31
|
-
command.stdout.lines.each do |line|
|
32
|
-
original_output << "\t" + line
|
33
|
-
original_output << "\n" unless line[-1] == "\n"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
unless command.stderr.empty?
|
38
|
-
command.stderr.lines.each do |line|
|
39
|
-
original_output << "\t" + line
|
40
|
-
original_output << "\n" unless line[-1] == "\n"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
5
|
+
class SimpleText < Pretty
|
44
6
|
|
45
|
-
|
46
|
-
|
47
|
-
|
7
|
+
# Historically, SimpleText formatter was used to disable coloring, so we maintain that behaviour
|
8
|
+
def colorize(obj, _color, _mode=nil)
|
9
|
+
obj.to_s
|
48
10
|
end
|
49
11
|
|
50
|
-
def
|
51
|
-
|
12
|
+
def format_message(_verbosity, message, _uuid=nil)
|
13
|
+
message
|
52
14
|
end
|
53
15
|
|
54
16
|
end
|
data/lib/sshkit/host.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'ostruct'
|
2
|
-
require 'etc'
|
3
2
|
|
4
3
|
module SSHKit
|
5
4
|
|
@@ -26,7 +25,7 @@ module SSHKit
|
|
26
25
|
if host_string_or_options_hash == :local
|
27
26
|
@local = true
|
28
27
|
@hostname = "localhost"
|
29
|
-
@user =
|
28
|
+
@user = ENV['USER'] || ENV['LOGNAME'] || ENV['USERNAME']
|
30
29
|
elsif !host_string_or_options_hash.is_a?(Hash)
|
31
30
|
suitable_parsers = [
|
32
31
|
SimpleHostParser,
|
@@ -100,7 +99,7 @@ module SSHKit
|
|
100
99
|
class SimpleHostParser
|
101
100
|
|
102
101
|
def self.suitable?(host_string)
|
103
|
-
!host_string.match
|
102
|
+
!host_string.match(/[:|@]/)
|
104
103
|
end
|
105
104
|
|
106
105
|
def initialize(host_string)
|
@@ -128,7 +127,7 @@ module SSHKit
|
|
128
127
|
class HostWithPortParser < SimpleHostParser
|
129
128
|
|
130
129
|
def self.suitable?(host_string)
|
131
|
-
!host_string.match
|
130
|
+
!host_string.match(/[@|\[|\]]/)
|
132
131
|
end
|
133
132
|
|
134
133
|
def port
|
@@ -145,7 +144,7 @@ module SSHKit
|
|
145
144
|
# :nodoc:
|
146
145
|
class HostWithUsernameAndPortParser < SimpleHostParser
|
147
146
|
def self.suitable?(host_string)
|
148
|
-
host_string.match
|
147
|
+
host_string.match(/@.*:\d+/)
|
149
148
|
end
|
150
149
|
def username
|
151
150
|
@host_string.split(/:|@/)[0]
|
@@ -163,7 +162,7 @@ module SSHKit
|
|
163
162
|
class IPv6HostWithPortParser < SimpleHostParser
|
164
163
|
|
165
164
|
def self.suitable?(host_string)
|
166
|
-
host_string.match
|
165
|
+
host_string.match(/[a-fA-F0-9:]+:\d+/)
|
167
166
|
end
|
168
167
|
|
169
168
|
def port
|
data/lib/sshkit/logger.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
module SSHKit
|
2
|
+
|
3
|
+
class MappingInteractionHandler
|
4
|
+
|
5
|
+
def initialize(mapping, log_level=nil)
|
6
|
+
@log_level = log_level
|
7
|
+
@mapping_proc = case mapping
|
8
|
+
when Hash
|
9
|
+
lambda do |server_output|
|
10
|
+
first_matching_key_value = mapping.find { |k, _v| k === server_output }
|
11
|
+
first_matching_key_value.nil? ? nil : first_matching_key_value.last
|
12
|
+
end
|
13
|
+
when Proc
|
14
|
+
mapping
|
15
|
+
else
|
16
|
+
raise "Unsupported mapping type: #{mapping.class} - only Hash and Proc mappings are supported"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_data(_command, stream_name, data, channel)
|
21
|
+
log("Looking up response for #{stream_name} message #{data.inspect}")
|
22
|
+
|
23
|
+
response_data = @mapping_proc.call(data)
|
24
|
+
|
25
|
+
if response_data.nil?
|
26
|
+
log("Unable to find interaction handler mapping for #{stream_name}: #{data.inspect} so no response was sent")
|
27
|
+
else
|
28
|
+
log("Sending #{response_data.inspect}")
|
29
|
+
if channel.respond_to?(:send_data) # Net SSH Channel
|
30
|
+
channel.send_data(response_data)
|
31
|
+
elsif channel.respond_to?(:write) # Local IO
|
32
|
+
channel.write(response_data)
|
33
|
+
else
|
34
|
+
raise "Unable to write response data to channel #{channel.inspect} - does not support 'send_data' or 'write'"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def log(message)
|
42
|
+
SSHKit.config.output.send(@log_level, message) unless @log_level.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -11,7 +11,7 @@ module SSHKit
|
|
11
11
|
threads << Thread.new(host) do |h|
|
12
12
|
begin
|
13
13
|
backend(h, &block).run
|
14
|
-
rescue
|
14
|
+
rescue StandardError => e
|
15
15
|
e2 = ExecuteError.new e
|
16
16
|
raise e2, "Exception while executing #{host.user ? "as #{host.user}@" : "on host "}#{host}: #{e.message}"
|
17
17
|
end
|
@@ -19,7 +19,7 @@ module SSHKit
|
|
19
19
|
private
|
20
20
|
def run_backend(host, &block)
|
21
21
|
backend(host, &block).run
|
22
|
-
rescue
|
22
|
+
rescue StandardError => e
|
23
23
|
e2 = ExecuteError.new e
|
24
24
|
raise e2, "Exception while executing #{host.user ? "as #{host.user}@" : "on host "}#{host}: #{e.message}"
|
25
25
|
end
|
data/lib/sshkit/version.rb
CHANGED
data/sshkit.gemspec
CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_runtime_dependency('net-ssh', '>= 2.8.0')
|
21
21
|
gem.add_runtime_dependency('net-scp', '>= 1.1.2')
|
22
|
-
gem.add_runtime_dependency('colorize', '>= 0.7.0')
|
23
22
|
|
24
23
|
gem.add_development_dependency('minitest', ['>= 2.11.3', '< 2.12.0'])
|
25
24
|
gem.add_development_dependency('rake')
|
@@ -6,13 +6,14 @@ module SSHKit
|
|
6
6
|
class TestLocal < MiniTest::Unit::TestCase
|
7
7
|
|
8
8
|
def setup
|
9
|
+
super
|
9
10
|
SSHKit.config.output = SSHKit::Formatter::BlackHole.new($stdout)
|
10
11
|
end
|
11
12
|
|
12
13
|
def test_capture
|
13
14
|
captured_command_result = ''
|
14
15
|
Local.new do
|
15
|
-
captured_command_result = capture(:echo, 'foo')
|
16
|
+
captured_command_result = capture(:echo, 'foo', strip: false)
|
16
17
|
end.run
|
17
18
|
assert_equal "foo\n", captured_command_result
|
18
19
|
end
|
@@ -35,6 +36,18 @@ module SSHKit
|
|
35
36
|
assert_equal true, succeeded_test_result
|
36
37
|
assert_equal false, failed_test_result
|
37
38
|
end
|
39
|
+
|
40
|
+
def test_interaction_handler
|
41
|
+
captured_command_result = nil
|
42
|
+
Local.new do
|
43
|
+
command = 'echo Enter Data; read the_data; echo Captured $the_data;'
|
44
|
+
captured_command_result = capture(command, interaction_handler: {
|
45
|
+
"Enter Data\n" => "SOME DATA\n",
|
46
|
+
"Captured SOME DATA\n" => nil
|
47
|
+
})
|
48
|
+
end.run
|
49
|
+
assert_equal("Enter Data\nCaptured SOME DATA", captured_command_result)
|
50
|
+
end
|
38
51
|
end
|
39
52
|
end
|
40
53
|
end
|
@@ -10,59 +10,45 @@ module SSHKit
|
|
10
10
|
|
11
11
|
def setup
|
12
12
|
super
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def block_to_run
|
17
|
-
lambda do |host|
|
18
|
-
execute 'date'
|
19
|
-
execute :ls, '-l', '/some/directory'
|
20
|
-
with rails_env: :production do
|
21
|
-
within '/tmp' do
|
22
|
-
as :root do
|
23
|
-
execute :touch, 'restart.txt'
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
13
|
+
@output = String.new
|
14
|
+
SSHKit.config.output_verbosity = :debug
|
15
|
+
SSHKit.config.output = SSHKit::Formatter::SimpleText.new(@output)
|
28
16
|
end
|
29
17
|
|
30
18
|
def a_host
|
31
19
|
VagrantWrapper.hosts['one']
|
32
20
|
end
|
33
21
|
|
34
|
-
def
|
35
|
-
Netssh.new(a_host
|
36
|
-
|
22
|
+
def test_simple_netssh
|
23
|
+
Netssh.new(a_host) do
|
24
|
+
execute 'date'
|
25
|
+
execute :ls, '-l'
|
26
|
+
with rails_env: :production do
|
27
|
+
within '/tmp' do
|
28
|
+
as :root do
|
29
|
+
execute :touch, 'restart.txt'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end.run
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
if test ! -d /opt/sites/example.com; then echo "Directory does not exist '/opt/sites/example.com'" 2>&1; false; fi
|
46
|
-
cd /opt/sites/example.com && /usr/bin/env date
|
47
|
-
cd /opt/sites/example.com && /usr/bin/env ls -l /some/directory
|
48
|
-
if test ! -d /opt/sites/example.com/tmp; then echo "Directory does not exist '/opt/sites/example.com/tmp'" 2>&1; false; fi
|
49
|
-
if ! sudo su -u root whoami > /dev/null; then echo "You cannot switch to user 'root' using sudo, please check the sudoers file" 2>&1; false; fi
|
50
|
-
cd /opt/sites/example.com/tmp && ( RAILS_ENV=production ( sudo su -u root /usr/bin/env touch restart.txt ) )
|
35
|
+
command_lines = @output.lines.select { |line| line.start_with?('Command:') }
|
36
|
+
assert_equal <<-EOEXPECTED.unindent, command_lines.join
|
37
|
+
Command: /usr/bin/env date
|
38
|
+
Command: /usr/bin/env ls -l
|
39
|
+
Command: if test ! -d /tmp; then echo \"Directory does not exist '/tmp'\" 1>&2; false; fi
|
40
|
+
Command: if ! sudo -u root whoami > /dev/null; then echo \"You cannot switch to user 'root' using sudo, please check the sudoers file\" 1>&2; false; fi
|
41
|
+
Command: cd /tmp && ( export RAILS_ENV="production" ; sudo -u root RAILS_ENV="production" -- sh -c '/usr/bin/env touch restart.txt' )
|
51
42
|
EOEXPECTED
|
52
43
|
end
|
53
44
|
|
54
45
|
def test_capture
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
assert captured_command_result
|
63
|
-
assert_match captured_command_result, /Linux|Darwin/
|
64
|
-
end
|
65
|
-
end
|
46
|
+
captured_command_result = nil
|
47
|
+
Netssh.new(a_host) do |_host|
|
48
|
+
captured_command_result = capture(:uname)
|
49
|
+
end.run
|
50
|
+
|
51
|
+
assert_includes %W(Linux Darwin), captured_command_result
|
66
52
|
end
|
67
53
|
|
68
54
|
def test_ssh_option_merge
|
@@ -76,9 +62,19 @@ module SSHKit
|
|
76
62
|
assert_equal({ forward_agent: false, paranoid: true }, host_ssh_options)
|
77
63
|
end
|
78
64
|
|
65
|
+
def test_env_vars_substituion_in_subshell
|
66
|
+
captured_command_result = nil
|
67
|
+
Netssh.new(a_host) do |_host|
|
68
|
+
with some_env_var: :some_value do
|
69
|
+
captured_command_result = capture(:echo, '$SOME_ENV_VAR')
|
70
|
+
end
|
71
|
+
end.run
|
72
|
+
assert_equal "some_value", captured_command_result
|
73
|
+
end
|
74
|
+
|
79
75
|
def test_execute_raises_on_non_zero_exit_status_and_captures_stdout_and_stderr
|
80
76
|
err = assert_raises SSHKit::Command::Failed do
|
81
|
-
Netssh.new(a_host) do |
|
77
|
+
Netssh.new(a_host) do |_host|
|
82
78
|
execute :echo, "'Test capturing stderr' 1>&2; false"
|
83
79
|
end.run
|
84
80
|
end
|
@@ -86,27 +82,27 @@ module SSHKit
|
|
86
82
|
end
|
87
83
|
|
88
84
|
def test_test_does_not_raise_on_non_zero_exit_status
|
89
|
-
Netssh.new(a_host) do |
|
85
|
+
Netssh.new(a_host) do |_host|
|
90
86
|
test :false
|
91
87
|
end.run
|
92
88
|
end
|
93
89
|
|
94
|
-
def
|
95
|
-
|
90
|
+
def test_upload_and_then_capture_file_contents
|
91
|
+
actual_file_contents = ""
|
96
92
|
file_name = File.join("/tmp", SecureRandom.uuid)
|
97
93
|
File.open file_name, 'w+' do |f|
|
98
|
-
f.write
|
94
|
+
f.write "Some Content\nWith a newline and trailing spaces \n "
|
99
95
|
end
|
100
96
|
Netssh.new(a_host) do
|
101
97
|
upload!(file_name, file_name)
|
102
|
-
|
98
|
+
actual_file_contents = capture(:cat, file_name, strip: false)
|
103
99
|
end.run
|
104
|
-
assert_equal "
|
100
|
+
assert_equal "Some Content\nWith a newline and trailing spaces \n ", actual_file_contents
|
105
101
|
end
|
106
102
|
|
107
103
|
def test_upload_string_io
|
108
104
|
file_contents = ""
|
109
|
-
Netssh.new(a_host) do |
|
105
|
+
Netssh.new(a_host) do |_host|
|
110
106
|
file_name = File.join("/tmp", SecureRandom.uuid)
|
111
107
|
upload!(StringIO.new('example_io'), file_name)
|
112
108
|
file_contents = download!(file_name)
|
@@ -128,6 +124,18 @@ module SSHKit
|
|
128
124
|
end.run
|
129
125
|
assert_equal File.open(file_name).read, file_contents
|
130
126
|
end
|
127
|
+
|
128
|
+
def test_interaction_handler
|
129
|
+
captured_command_result = nil
|
130
|
+
Netssh.new(a_host) do
|
131
|
+
command = 'echo Enter Data; read the_data; echo Captured $the_data;'
|
132
|
+
captured_command_result = capture(command, interaction_handler: {
|
133
|
+
"Enter Data\n" => "SOME DATA\n",
|
134
|
+
"Captured SOME DATA\n" => nil
|
135
|
+
})
|
136
|
+
end.run
|
137
|
+
assert_equal("Enter Data\nCaptured SOME DATA", captured_command_result)
|
138
|
+
end
|
131
139
|
end
|
132
140
|
|
133
141
|
end
|
data/test/helper.rb
CHANGED
@@ -40,7 +40,7 @@ class FunctionalTest < MiniTest::Unit::TestCase
|
|
40
40
|
def create_user_with_key(username, password = :secret)
|
41
41
|
username, password = username.to_s, password.to_s
|
42
42
|
|
43
|
-
keys = VagrantWrapper.hosts.collect do |
|
43
|
+
keys = VagrantWrapper.hosts.collect do |_name, host|
|
44
44
|
Net::SSH.start(host.hostname, host.user, port: host.port, password: host.password) do |ssh|
|
45
45
|
|
46
46
|
# Remove the user, make it again, force-generate a key for him
|
@@ -70,7 +70,7 @@ class FunctionalTest < MiniTest::Unit::TestCase
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
Hash[VagrantWrapper.hosts.collect { |n,
|
73
|
+
Hash[VagrantWrapper.hosts.collect { |n, _h| n.to_sym }.zip(keys)]
|
74
74
|
end
|
75
75
|
|
76
76
|
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module SSHKit
|
4
|
+
|
5
|
+
module Backend
|
6
|
+
|
7
|
+
class TestAbstract < UnitTest
|
8
|
+
|
9
|
+
def test_make
|
10
|
+
backend = ExampleBackend.new do
|
11
|
+
make %w(some command)
|
12
|
+
end
|
13
|
+
|
14
|
+
backend.run
|
15
|
+
|
16
|
+
assert_equal '/usr/bin/env make some command', backend.executed_command.to_command
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_rake
|
20
|
+
backend = ExampleBackend.new do
|
21
|
+
rake %w(a command)
|
22
|
+
end
|
23
|
+
|
24
|
+
backend.run
|
25
|
+
|
26
|
+
assert_equal '/usr/bin/env rake a command', backend.executed_command.to_command
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_execute_creates_and_executes_command_with_default_options
|
30
|
+
backend = ExampleBackend.new do
|
31
|
+
execute :ls, '-l', '/some/directory'
|
32
|
+
end
|
33
|
+
|
34
|
+
backend.run
|
35
|
+
|
36
|
+
assert_equal '/usr/bin/env ls -l /some/directory', backend.executed_command.to_command
|
37
|
+
assert_equal(
|
38
|
+
{:raise_on_non_zero_exit=>true, :run_in_background=>false, :in=>nil, :env=>nil, :host=>ExampleBackend.example_host, :user=>nil, :group=>nil},
|
39
|
+
backend.executed_command.options
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_test_method_creates_and_executes_command_with_false_raise_on_non_zero_exit
|
44
|
+
backend = ExampleBackend.new do
|
45
|
+
test '[ -d /some/file ]'
|
46
|
+
end
|
47
|
+
|
48
|
+
backend.run
|
49
|
+
|
50
|
+
assert_equal '[ -d /some/file ]', backend.executed_command.to_command
|
51
|
+
assert_equal false, backend.executed_command.options[:raise_on_non_zero_exit], 'raise_on_non_zero_exit option'
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_capture_creates_and_executes_command_and_returns_stripped_output
|
55
|
+
output = nil
|
56
|
+
backend = ExampleBackend.new do
|
57
|
+
output = capture :cat, '/a/file'
|
58
|
+
end
|
59
|
+
backend.full_stdout = "Some stdout\n "
|
60
|
+
|
61
|
+
backend.run
|
62
|
+
|
63
|
+
assert_equal '/usr/bin/env cat /a/file', backend.executed_command.to_command
|
64
|
+
assert_equal 'Some stdout', output
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_capture_supports_disabling_strip
|
68
|
+
output = nil
|
69
|
+
backend = ExampleBackend.new do
|
70
|
+
output = capture :cat, '/a/file', :strip => false
|
71
|
+
end
|
72
|
+
backend.full_stdout = "Some stdout\n "
|
73
|
+
|
74
|
+
backend.run
|
75
|
+
|
76
|
+
assert_equal '/usr/bin/env cat /a/file', backend.executed_command.to_command
|
77
|
+
assert_equal "Some stdout\n ", output
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_background_logs_deprecation_warnings
|
81
|
+
deprecation_out = ''
|
82
|
+
SSHKit.config.deprecation_output = deprecation_out
|
83
|
+
|
84
|
+
ExampleBackend.new do
|
85
|
+
background :ls
|
86
|
+
end.run
|
87
|
+
|
88
|
+
lines = deprecation_out.lines.to_a
|
89
|
+
|
90
|
+
assert_equal 2, lines.length
|
91
|
+
|
92
|
+
assert_equal("[Deprecated] The background method is deprecated. Blame badly behaved pseudo-daemons!\n", lines[0])
|
93
|
+
assert_match(/ \(Called from.*test_abstract.rb:\d+:in `block in test_background_logs_deprecation_warnings'\)\n/, lines[1])
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_calling_abstract_with_undefined_execute_command_raises_exception
|
97
|
+
abstract = Abstract.new(ExampleBackend.example_host) do
|
98
|
+
execute(:some_command)
|
99
|
+
end
|
100
|
+
|
101
|
+
assert_raises(SSHKit::Backend::MethodUnavailableError) do
|
102
|
+
abstract.run
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_abstract_backend_can_be_configured
|
107
|
+
Abstract.configure do |config|
|
108
|
+
config.some_option = 100
|
109
|
+
end
|
110
|
+
|
111
|
+
assert_equal 100, Abstract.config.some_option
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_invoke_raises_no_method_error
|
115
|
+
assert_raises NoMethodError do
|
116
|
+
ExampleBackend.new.invoke :echo
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Use a concrete ExampleBackend rather than a mock for improved assertion granularity
|
121
|
+
class ExampleBackend < Abstract
|
122
|
+
attr_writer :full_stdout
|
123
|
+
attr_reader :executed_command
|
124
|
+
|
125
|
+
def initialize(&block)
|
126
|
+
block = block.nil? ? lambda {} : block
|
127
|
+
super(ExampleBackend.example_host, &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
def execute_command(command)
|
131
|
+
@executed_command = command
|
132
|
+
command.on_stdout(nil, @full_stdout) unless @full_stdout.nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
def ExampleBackend.example_host
|
136
|
+
Host.new(:'example.com')
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|