net-ssh 3.0.1 → 3.0.2.rc1
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
- checksums.yaml.gz.sig +1 -1
- data.tar.gz.sig +0 -0
- data/CHANGES.txt +4 -0
- data/README.rdoc +1 -1
- data/Rakefile +5 -1
- data/lib/net/ssh.rb +5 -2
- data/lib/net/ssh/authentication/key_manager.rb +1 -4
- data/lib/net/ssh/connection/channel.rb +26 -7
- data/lib/net/ssh/connection/session.rb +11 -2
- data/lib/net/ssh/proxy/command.rb +17 -2
- data/lib/net/ssh/version.rb +2 -2
- data/net-ssh-public_cert.pem +15 -15
- data/net-ssh.gemspec +7 -5
- data/test/README.txt +0 -22
- data/test/connection/test_channel.rb +3 -0
- data/test/connection/test_session.rb +14 -5
- data/test/integration/README.txt +2 -4
- data/test/integration/common.rb +6 -0
- data/test/integration/playbook.yml +8 -0
- data/test/integration/test_forward.rb +435 -0
- data/test/integration/test_id_rsa_keys.rb +18 -6
- data/test/integration/test_proxy.rb +93 -0
- data/test/start/test_user_nil.rb +27 -0
- data/test/test_all.rb +1 -1
- metadata +22 -20
- metadata.gz.sig +0 -0
- data/test/manual/test_forward.rb +0 -285
@@ -0,0 +1,93 @@
|
|
1
|
+
require_relative './common'
|
2
|
+
require 'net/ssh/buffer'
|
3
|
+
require 'net/ssh'
|
4
|
+
require 'timeout'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'net/ssh/proxy/command'
|
7
|
+
|
8
|
+
class TestProxy < Test::Unit::TestCase
|
9
|
+
include IntegrationTestHelpers
|
10
|
+
|
11
|
+
def localhost
|
12
|
+
'localhost'
|
13
|
+
end
|
14
|
+
|
15
|
+
def user
|
16
|
+
'net_ssh_1'
|
17
|
+
end
|
18
|
+
|
19
|
+
def ssh_start_params(options)
|
20
|
+
[localhost ,user , {:keys => @key_id_rsa, :verbose => :debug}.merge(options)]
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_ssh_env(&block)
|
24
|
+
tmpdir do |dir|
|
25
|
+
@key_id_rsa = "#{dir}/id_rsa"
|
26
|
+
sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub"
|
27
|
+
sh "ssh-keygen -f #{@key_id_rsa} -t rsa -N ''"
|
28
|
+
set_authorized_key(user,"#{@key_id_rsa}.pub")
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_smoke
|
34
|
+
setup_ssh_env do
|
35
|
+
proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost 22")
|
36
|
+
msg = 'echo123'
|
37
|
+
ret = Net::SSH.start(*ssh_start_params(:proxy => proxy)) do |ssh|
|
38
|
+
ssh.exec! "echo \"$USER:#{msg}\""
|
39
|
+
end
|
40
|
+
assert_equal "net_ssh_1:#{msg}\n", ret
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_spurious_write_wakeup_emulate(rate=99,&block)
|
45
|
+
orig_io_select = Net::SSH::Compat.method(:io_select)
|
46
|
+
count = 0
|
47
|
+
Net::SSH::Compat.singleton_class.send(:define_method,:io_select) do |*params|
|
48
|
+
count += 1
|
49
|
+
if (count % rate != 0)
|
50
|
+
if params && params[1] && !params[1].empty?
|
51
|
+
return [[],params[1],[]]
|
52
|
+
end
|
53
|
+
#if params && params[0] && !params[0].empty?
|
54
|
+
#return [params[0],[],[]]
|
55
|
+
#end
|
56
|
+
end
|
57
|
+
IO.select(*params)
|
58
|
+
end
|
59
|
+
begin
|
60
|
+
yield
|
61
|
+
ensure
|
62
|
+
Net::SSH::Compat.singleton_class.send(:define_method,:io_select,&orig_io_select)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_with_rate_limit_and_spurious_wakeup
|
67
|
+
system("sudo sh -c 'echo 4096 > /proc/sys/fs/pipe-max-size'")
|
68
|
+
begin
|
69
|
+
setup_ssh_env do
|
70
|
+
proxy = Net::SSH::Proxy::Command.new("/usr/bin/pv --rate-limit 100k | /bin/nc localhost 22")
|
71
|
+
#proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost 22")
|
72
|
+
begin
|
73
|
+
large_msg = 'echo123'*30000
|
74
|
+
ok = Net::SSH.start(*ssh_start_params(:proxy => proxy)) do |ssh|
|
75
|
+
with_spurious_write_wakeup_emulate do
|
76
|
+
ret = ssh.exec! "echo \"$USER:#{large_msg}\""
|
77
|
+
#assert_equal "net_ssh_1:#{large_msg}\n", ret
|
78
|
+
assert_equal "/bin/sh: Argument list too long\n", ret
|
79
|
+
hello_count = 1000
|
80
|
+
ret = ssh.exec! "ruby -e 'puts \"Hello\"*#{hello_count}'"
|
81
|
+
assert_equal "Hello"*hello_count+"\n", ret
|
82
|
+
end
|
83
|
+
:ok
|
84
|
+
end
|
85
|
+
end
|
86
|
+
assert_equal :ok, ok
|
87
|
+
end
|
88
|
+
ensure
|
89
|
+
system("sudo sh -c 'echo 1048576 > /proc/sys/fs/pipe-max-size'")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'common'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
module NetSSH
|
5
|
+
class TestStartUserNil < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@authentication_session = mock('authentication_session')
|
8
|
+
Net::SSH::Authentication::Session.stubs(:new).returns(@authentication_session)
|
9
|
+
Net::SSH::Transport::Session.stubs(:new).returns(mock('transport_session'))
|
10
|
+
Net::SSH::Connection::Session.stubs(:new).returns(mock('connection_session'))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_start_should_accept_nil_user
|
14
|
+
@authentication_session.stubs(:authenticate).returns(true)
|
15
|
+
assert_nothing_raised do
|
16
|
+
Net::SSH.start('localhost')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_start_should_use_default_user_when_nil
|
21
|
+
@authentication_session.stubs(:authenticate).with() {|_next_service, user, _password| user == Etc.getlogin }.returns(true)
|
22
|
+
assert_nothing_raised do
|
23
|
+
Net::SSH.start('localhost')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/test_all.rb
CHANGED
@@ -4,7 +4,7 @@ $: << '.'
|
|
4
4
|
# $ ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb
|
5
5
|
Dir.chdir(File.dirname(__FILE__)) do
|
6
6
|
test_files = Dir['**/test_*.rb']-['test_all.rb'] # prevent circular require
|
7
|
-
test_files -= Dir['integration/test_*.rb']
|
7
|
+
test_files -= Dir['integration/test_*.rb'] unless ENV['NET_SSH_RUN_INTEGRATION_TESTS']
|
8
8
|
test_files = test_files.reject { |f| f =~ /^manual/ }
|
9
9
|
test_files = test_files.select { |f| f =~ Regexp.new(ENV['ONLY']) } if ENV['ONLY']
|
10
10
|
test_files = test_files.reject { |f| f =~ Regexp.new(ENV['EXCEPT']) } if ENV['EXCEPT']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-ssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.2.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
@@ -14,24 +14,24 @@ cert_chain:
|
|
14
14
|
-----BEGIN CERTIFICATE-----
|
15
15
|
MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt
|
16
16
|
c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD
|
17
|
-
|
17
|
+
Y29tMB4XDTE1MTIwNjIxMDYyNFoXDTE2MTIwNTIxMDYyNFowQjEQMA4GA1UEAwwH
|
18
18
|
bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
19
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMYnhNtn0f6p
|
20
|
+
nTylB8mE8lMdoMLJC8KwpMWsvk73Pe2WVDsH/OSwwwz6oUGk1i70cJyDjIEBNpwT
|
21
|
+
88GpVXJSumvqVsf9fCg3mWNeb5t0J+aeNm9MIvYVMTqj5tydoXQiwnILRDYHV9tZ
|
22
|
+
1c3o59/VlahSTpZ7YEgzVufpAkvEGkbJiG849exiipK7MN/ZIkMOxYVnyRXk43Xc
|
23
|
+
6GYlsHOfSgPwcXwW5g57DCwLQLWrjDsTka28dxDmO7B5Lv5EqzINxVxWsu43OgZG
|
24
|
+
21Io/jIyf5PNpeKPKNGDuAQJ8mvdMYBJoDhtCwgsUYbl0BZzA7g4ytl51HtIeP+j
|
25
|
+
Qp/eAvs/RrECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBfKiwO2eM4NE
|
26
|
+
iRrVG793qEPLYyMwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQCfZFdb
|
27
|
+
p4jzkfIzGDbiOxd0R8sdqJoC4nMLEgnQ7dLulawwA3IXe3sHAKgA5kmH3prsKc5H
|
28
|
+
zVmM5NlH2P1nRbegIkQTYiIod1hZQCNxdmVG/fprMqPq0ybpUOjjrP5pj0OtszE1
|
29
|
+
F2dQia1hOEstMR+n0nAtWII9HJAEyeZjVV0s2Cl7Pt85XJ3hxFcCKwzqsK5xRI7a
|
30
|
+
B3vwh3/JJYrFonIohQ//Lg9qTZASEkoKLlq1/hFeICoCGGIGLq45ZB7CzXLooCKi
|
31
|
+
s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH
|
32
|
+
e2C9M1m/2odPZo8h
|
33
33
|
-----END CERTIFICATE-----
|
34
|
-
date: 2015-
|
34
|
+
date: 2015-12-10 00:00:00.000000000 Z
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: test-unit
|
@@ -195,14 +195,16 @@ files:
|
|
195
195
|
- test/integration/Vagrantfile
|
196
196
|
- test/integration/common.rb
|
197
197
|
- test/integration/playbook.yml
|
198
|
+
- test/integration/test_forward.rb
|
198
199
|
- test/integration/test_id_rsa_keys.rb
|
200
|
+
- test/integration/test_proxy.rb
|
199
201
|
- test/known_hosts/github
|
200
202
|
- test/known_hosts/github_hash
|
201
|
-
- test/manual/test_forward.rb
|
202
203
|
- test/manual/test_pageant.rb
|
203
204
|
- test/start/test_connection.rb
|
204
205
|
- test/start/test_options.rb
|
205
206
|
- test/start/test_transport.rb
|
207
|
+
- test/start/test_user_nil.rb
|
206
208
|
- test/test_all.rb
|
207
209
|
- test/test_buffer.rb
|
208
210
|
- test/test_buffered_io.rb
|
@@ -249,9 +251,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
249
251
|
version: '2.0'
|
250
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
251
253
|
requirements:
|
252
|
-
- - "
|
254
|
+
- - ">"
|
253
255
|
- !ruby/object:Gem::Version
|
254
|
-
version:
|
256
|
+
version: 1.3.1
|
255
257
|
requirements: []
|
256
258
|
rubyforge_project: net-ssh
|
257
259
|
rubygems_version: 2.4.6
|
metadata.gz.sig
CHANGED
Binary file
|
data/test/manual/test_forward.rb
DELETED
@@ -1,285 +0,0 @@
|
|
1
|
-
# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb
|
2
|
-
|
3
|
-
# Tests for the following patch:
|
4
|
-
#
|
5
|
-
# http://github.com/net-ssh/net-ssh/tree/portfwfix
|
6
|
-
#
|
7
|
-
# It fixes 3 issues, regarding closing forwarded ports:
|
8
|
-
#
|
9
|
-
# 1.) if client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed.
|
10
|
-
# 2.) if client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with
|
11
|
-
# 3.) if server closes the sending side, the on_eof is not handled.
|
12
|
-
#
|
13
|
-
# More info:
|
14
|
-
#
|
15
|
-
# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
|
16
|
-
|
17
|
-
require 'common'
|
18
|
-
require 'net/ssh/buffer'
|
19
|
-
require 'net/ssh'
|
20
|
-
require 'timeout'
|
21
|
-
require 'tempfile'
|
22
|
-
|
23
|
-
class TestForward < Test::Unit::TestCase
|
24
|
-
|
25
|
-
def localhost
|
26
|
-
'localhost'
|
27
|
-
end
|
28
|
-
|
29
|
-
def ssh_start_params
|
30
|
-
[localhost ,ENV['USER'], {:keys => "~/.ssh/id_rsa", :verbose => :debug}]
|
31
|
-
end
|
32
|
-
|
33
|
-
def start_server_sending_lot_of_data(exceptions)
|
34
|
-
server = TCPServer.open(0)
|
35
|
-
Thread.start do
|
36
|
-
loop do
|
37
|
-
Thread.start(server.accept) do |client|
|
38
|
-
begin
|
39
|
-
10000.times do |i|
|
40
|
-
client.puts "item#{i}"
|
41
|
-
end
|
42
|
-
client.close
|
43
|
-
rescue
|
44
|
-
exceptions << $!
|
45
|
-
raise
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
return server
|
51
|
-
end
|
52
|
-
|
53
|
-
def start_server_closing_soon(exceptions=nil)
|
54
|
-
server = TCPServer.open(0)
|
55
|
-
Thread.start do
|
56
|
-
loop do
|
57
|
-
Thread.start(server.accept) do |client|
|
58
|
-
begin
|
59
|
-
client.recv(1024)
|
60
|
-
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
|
61
|
-
client.close
|
62
|
-
rescue
|
63
|
-
exceptions << $!
|
64
|
-
raise
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
return server
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_local_ephemeral_port_should_work_correctly
|
73
|
-
session = Net::SSH.start(*ssh_start_params)
|
74
|
-
|
75
|
-
assert_nothing_raised do
|
76
|
-
assigned_port = session.forward.local(0, localhost, 22)
|
77
|
-
assert_not_nil assigned_port
|
78
|
-
assert_operator assigned_port, :>, 0
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_remote_ephemeral_port_should_work_correctly
|
83
|
-
session = Net::SSH.start(*ssh_start_params)
|
84
|
-
|
85
|
-
assert_nothing_raised do
|
86
|
-
session.forward.remote(22, localhost, 0, localhost)
|
87
|
-
session.loop { !(session.forward.active_remotes.length > 0) }
|
88
|
-
assigned_port = session.forward.active_remotes.first[0]
|
89
|
-
assert_not_nil assigned_port
|
90
|
-
assert_operator assigned_port, :>, 0
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_remote_callback_should_fire
|
95
|
-
session = Net::SSH.start(*ssh_start_params)
|
96
|
-
|
97
|
-
assert_nothing_raised do
|
98
|
-
got_port = nil
|
99
|
-
session.forward.remote(22, localhost, 0, localhost) do |port|
|
100
|
-
got_port = port
|
101
|
-
end
|
102
|
-
session.loop { !(session.forward.active_remotes.length > 0) }
|
103
|
-
assert_operator session.forward.active_remote_destinations.length, :==, 1
|
104
|
-
assert_operator session.forward.active_remote_destinations.keys.first, :==, [ 22, localhost ]
|
105
|
-
assert_operator session.forward.active_remote_destinations.values.first, :==, [ got_port, localhost ]
|
106
|
-
assert_operator session.forward.active_remotes.first, :==, [ got_port, localhost ]
|
107
|
-
assigned_port = session.forward.active_remotes.first[0]
|
108
|
-
assert_operator got_port, :==, assigned_port
|
109
|
-
assert_not_nil assigned_port
|
110
|
-
assert_operator assigned_port, :>, 0
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_remote_callback_should_fire_on_error_and_still_throw_exception
|
115
|
-
session = Net::SSH.start(*ssh_start_params)
|
116
|
-
|
117
|
-
assert_nothing_raised do
|
118
|
-
session.forward.remote(22, localhost, 22, localhost) do |port|
|
119
|
-
assert_operator port, :==, :error
|
120
|
-
end
|
121
|
-
end
|
122
|
-
assert_raises(Net::SSH::Exception) do
|
123
|
-
session.loop { true }
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def test_remote_callback_should_fire_on_error_but_not_throw_exception_if_asked_not_to
|
128
|
-
session = Net::SSH.start(*ssh_start_params)
|
129
|
-
|
130
|
-
assert_nothing_raised do
|
131
|
-
got_port = nil
|
132
|
-
session.forward.remote(22, localhost, 22, localhost) do |port|
|
133
|
-
assert_operator port, :==, :error
|
134
|
-
got_port = port
|
135
|
-
:no_exception
|
136
|
-
end
|
137
|
-
session.loop { !got_port }
|
138
|
-
assert_operator port, :==, :error
|
139
|
-
assert_operator session.forward.active_remotes.length, :==, 0
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_loop_should_not_abort_when_local_side_of_forward_is_closed
|
144
|
-
session = Net::SSH.start(*ssh_start_params)
|
145
|
-
server_exc = Queue.new
|
146
|
-
server = start_server_sending_lot_of_data(server_exc)
|
147
|
-
remote_port = server.addr[1]
|
148
|
-
local_port = 0 # request ephemeral port
|
149
|
-
session.forward.local(local_port, localhost, remote_port)
|
150
|
-
client_done = Queue.new
|
151
|
-
Thread.start do
|
152
|
-
begin
|
153
|
-
client = TCPSocket.new(localhost, local_port)
|
154
|
-
client.recv(1024)
|
155
|
-
client.close
|
156
|
-
sleep(0.2)
|
157
|
-
ensure
|
158
|
-
client_done << true
|
159
|
-
end
|
160
|
-
end
|
161
|
-
session.loop(0.1) { client_done.empty? }
|
162
|
-
assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
|
163
|
-
end
|
164
|
-
|
165
|
-
def test_loop_should_not_abort_when_local_side_of_forward_is_reset
|
166
|
-
session = Net::SSH.start(*ssh_start_params)
|
167
|
-
server_exc = Queue.new
|
168
|
-
server = start_server_sending_lot_of_data(server_exc)
|
169
|
-
remote_port = server.addr[1]
|
170
|
-
local_port = 0 # request ephemeral port
|
171
|
-
session.forward.local(local_port, localhost, remote_port)
|
172
|
-
client_done = Queue.new
|
173
|
-
Thread.start do
|
174
|
-
begin
|
175
|
-
client = TCPSocket.new(localhost, local_port)
|
176
|
-
client.recv(1024)
|
177
|
-
client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii"))
|
178
|
-
client.close
|
179
|
-
sleep(0.1)
|
180
|
-
ensure
|
181
|
-
client_done << true
|
182
|
-
end
|
183
|
-
end
|
184
|
-
session.loop(0.1) { client_done.empty? }
|
185
|
-
assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty?
|
186
|
-
end
|
187
|
-
|
188
|
-
def create_local_socket(&blk)
|
189
|
-
tempfile = Tempfile.new("net_ssh_forward_test")
|
190
|
-
path = tempfile.path
|
191
|
-
tempfile.delete
|
192
|
-
yield UNIXServer.open(path)
|
193
|
-
File.delete(path)
|
194
|
-
end if defined?(UNIXServer)
|
195
|
-
|
196
|
-
def test_forward_local_unix_socket_to_remote_port
|
197
|
-
session = Net::SSH.start(*ssh_start_params)
|
198
|
-
server_exc = Queue.new
|
199
|
-
server = start_server_sending_lot_of_data(server_exc)
|
200
|
-
remote_port = server.addr[1]
|
201
|
-
client_data = nil
|
202
|
-
|
203
|
-
create_local_socket do |local_socket|
|
204
|
-
session.forward.local(local_socket, localhost, remote_port)
|
205
|
-
client_done = Queue.new
|
206
|
-
|
207
|
-
Thread.start do
|
208
|
-
begin
|
209
|
-
client = UNIXSocket.new(local_socket.path)
|
210
|
-
client_data = client.recv(1024)
|
211
|
-
client.close
|
212
|
-
sleep(0.2)
|
213
|
-
ensure
|
214
|
-
client_done << true
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
session.loop(0.1) { client_done.empty? }
|
219
|
-
end
|
220
|
-
|
221
|
-
assert_not_nil(client_data, "client should have received data")
|
222
|
-
assert(client_data.match(/item\d/), 'client should have received the string item')
|
223
|
-
end if defined?(UNIXSocket)
|
224
|
-
|
225
|
-
def test_loop_should_not_abort_when_server_side_of_forward_is_closed
|
226
|
-
session = Net::SSH.start(*ssh_start_params)
|
227
|
-
server = start_server_closing_soon
|
228
|
-
remote_port = server.addr[1]
|
229
|
-
local_port = 0 # request ephemeral port
|
230
|
-
session.forward.local(local_port, localhost, remote_port)
|
231
|
-
client_done = Queue.new
|
232
|
-
Thread.start do
|
233
|
-
begin
|
234
|
-
client = TCPSocket.new(localhost, local_port)
|
235
|
-
1.times do |i|
|
236
|
-
client.puts "item#{i}"
|
237
|
-
end
|
238
|
-
client.close
|
239
|
-
sleep(0.1)
|
240
|
-
ensure
|
241
|
-
client_done << true
|
242
|
-
end
|
243
|
-
end
|
244
|
-
session.loop(0.1) { client_done.empty? }
|
245
|
-
end
|
246
|
-
|
247
|
-
def start_server
|
248
|
-
server = TCPServer.open(0)
|
249
|
-
Thread.start do
|
250
|
-
loop do
|
251
|
-
Thread.start(server.accept) do |client|
|
252
|
-
yield(client)
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
return server
|
257
|
-
end
|
258
|
-
|
259
|
-
def test_server_eof_should_be_handled
|
260
|
-
session = Net::SSH.start(*ssh_start_params)
|
261
|
-
server = start_server do |client|
|
262
|
-
client.write "This is a small message!"
|
263
|
-
client.close
|
264
|
-
end
|
265
|
-
client_done = Queue.new
|
266
|
-
client_exception = Queue.new
|
267
|
-
client_data = Queue.new
|
268
|
-
remote_port = server.addr[1]
|
269
|
-
local_port = session.forward.local(0, localhost, remote_port)
|
270
|
-
Thread.start do
|
271
|
-
begin
|
272
|
-
client = TCPSocket.new(localhost, local_port)
|
273
|
-
data = client.read(4096)
|
274
|
-
client.close
|
275
|
-
client_done << data
|
276
|
-
rescue
|
277
|
-
client_done << $!
|
278
|
-
end
|
279
|
-
end
|
280
|
-
timeout(5) do
|
281
|
-
session.loop(0.1) { client_done.empty? }
|
282
|
-
assert_equal "This is a small message!", client_done.pop
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|