Hello community, here is the log from the commit of package rubygem-net-ssh for openSUSE:Factory checked in at 2016-02-05 00:31:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-net-ssh (Old) and /work/SRC/openSUSE:Factory/.rubygem-net-ssh.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "rubygem-net-ssh" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-net-ssh/rubygem-net-ssh.changes 2015-09-30 05:53:22.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-net-ssh.new/rubygem-net-ssh.changes 2016-02-05 00:31:31.000000000 +0100 @@ -1,0 +2,13 @@ +Thu Jan 21 05:40:56 UTC 2016 - coolo@suse.com + +- updated to version 3.0.2 + see installed CHANGES.txt + + === 3.0.2 + === 3.0.2.rc1 + + * fixed rare WaitWritable error with proxy commands [Miklos Fazkas, Andre Meij]] + * if Net::SSH.start user is nil and config has no entry we default to Etc.getlogin + * Bugfix: CHANNEL_CLOSE was sent before draining ouput buffer #280 [Christopher F. Auston] + +------------------------------------------------------------------- Old: ---- net-ssh-3.0.1.gem New: ---- net-ssh-3.0.2.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-net-ssh.spec ++++++ --- /var/tmp/diff_new_pack.nTQb5r/_old 2016-02-05 00:31:32.000000000 +0100 +++ /var/tmp/diff_new_pack.nTQb5r/_new 2016-02-05 00:31:32.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package rubygem-net-ssh # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ # Name: rubygem-net-ssh -Version: 3.0.1 +Version: 3.0.2 Release: 0 %define mod_name net-ssh %define mod_full_name %{mod_name}-%{version} ++++++ net-ssh-3.0.1.gem -> net-ssh-3.0.2.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGES.txt new/CHANGES.txt --- old/CHANGES.txt 2015-09-25 21:35:53.000000000 +0200 +++ new/CHANGES.txt 2015-12-30 10:07:47.000000000 +0100 @@ -1,3 +1,10 @@ +=== 3.0.2 +=== 3.0.2.rc1 + +* fixed rare WaitWritable error with proxy commands [Miklos Fazkas, Andre Meij]] +* if Net::SSH.start user is nil and config has no entry we default to Etc.getlogin +* Bugfix: CHANNEL_CLOSE was sent before draining ouput buffer #280 [Christopher F. Auston] + === 3.0.1 === 3.0.1.rc1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.rdoc new/README.rdoc --- old/README.rdoc 2015-09-25 21:35:53.000000000 +0200 +++ new/README.rdoc 2015-12-30 10:07:47.000000000 +0100 @@ -1,4 +1,4 @@ -= Net::SSH 2.x += Net::SSH 3.x <em><b>Please note: this project is in maintenance mode. It is not under active development but pull requests are very much welcome. Just be sure to include tests! -- delano</b></em> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Rakefile new/Rakefile --- old/Rakefile 2015-09-25 21:35:53.000000000 +0200 +++ new/Rakefile 2015-12-30 10:07:47.000000000 +0100 @@ -74,7 +74,11 @@ require 'rake/testtask' Rake::TestTask.new do |t| - t.libs = ["lib", "test"] + if ENV['NET_SSH_RUN_INTEGRATION_TESTS'] + t.libs = ["lib","test","test/integration"] + else + t.libs = ["lib", "test"] + end end Rake::TestTask.new(:'integration-test') do |t| Files old/checksums.yaml.gz and new/checksums.yaml.gz differ Files old/checksums.yaml.gz.sig and new/checksums.yaml.gz.sig differ Files old/data.tar.gz.sig and new/data.tar.gz.sig differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/key_manager.rb new/lib/net/ssh/authentication/key_manager.rb --- old/lib/net/ssh/authentication/key_manager.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh/authentication/key_manager.rb 2015-12-30 10:07:47.000000000 +0100 @@ -232,16 +232,13 @@ identity end - rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError => e + rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, ArgumentError => e if ignore_decryption_errors identity else process_identity_loading_error(identity, e) nil end - rescue ArgumentError => e - process_identity_loading_error(identity, e) - nil rescue Exception => e process_identity_loading_error(identity, e) nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/connection/channel.rb new/lib/net/ssh/connection/channel.rb --- old/lib/net/ssh/connection/channel.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh/connection/channel.rb 2015-12-30 10:07:47.000000000 +0100 @@ -126,7 +126,7 @@ @pending_requests = [] @on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil @on_request = {} - @closing = @eof = @sent_eof = false + @closing = @eof = @sent_eof = @local_closed = @remote_closed = false end # A shortcut for accessing properties of the channel (see #properties). @@ -269,14 +269,28 @@ connection.loop { active? } end - # Returns true if the channel is currently closing, but not actually - # closed. A channel is closing when, for instance, #close has been - # invoked, but the server has not yet responded with a CHANNEL_CLOSE - # packet of its own. + # True if close() has been called; NOTE: if the channel has data waiting to + # be sent then the channel will close after all the data is sent. See + # closed?() to determine if we have actually sent CHANNEL_CLOSE to server. + # This may be true for awhile before closed? returns true if we are still + # sending buffered output to server. def closing? @closing end + # True if we have sent CHANNEL_CLOSE to the remote server. + def local_closed? + @local_closed + end + + def remote_closed? + @remote_closed + end + + def remote_closed! + @remote_closed = true + end + # Requests that the channel be closed. If the channel is already closing, # this does nothing, nor does it do anything if the channel has not yet # been confirmed open (see #do_open_confirmation). Otherwise, it sends a @@ -285,7 +299,6 @@ return if @closing if remote_id @closing = true - connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id)) end end @@ -311,10 +324,16 @@ @on_process.call(self) if @on_process enqueue_pending_output - if @eof and not @sent_eof and output.empty? and remote_id + if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id)) @sent_eof = true end + + if @closing and not @local_closed and output.empty? and remote_id + connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id)) + @local_closed = true + connection.cleanup_channel(self) + end end # Registers a callback to be invoked when data packets are received by the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/connection/session.rb new/lib/net/ssh/connection/session.rb --- old/lib/net/ssh/connection/session.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh/connection/session.rb 2015-12-30 10:07:47.000000000 +0100 @@ -220,7 +220,7 @@ def preprocess return false if block_given? && !yield(self) dispatch_incoming_packets - channels.each { |id, channel| channel.process unless channel.closing? } + channels.each { |id, channel| channel.process unless channel.local_closed? } return false if block_given? && !yield(self) return true end @@ -455,6 +455,14 @@ old end + def cleanup_channel(channel) + if channel.local_closed? and channel.remote_closed? + info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" } + channels.delete(channel.local_id) + end + end + + private # Read all pending packets from the connection and dispatch them as @@ -583,9 +591,10 @@ info { "channel_close: #{packet[:local_id]}" } channel = channels[packet[:local_id]] + channel.remote_closed! channel.close - channels.delete(packet[:local_id]) + cleanup_channel(channel) channel.do_close end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/proxy/command.rb new/lib/net/ssh/proxy/command.rb --- old/lib/net/ssh/proxy/command.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh/proxy/command.rb 2015-12-30 10:07:47.000000000 +0100 @@ -79,11 +79,26 @@ end else def io.send(data, flag) - write_nonblock(data) + begin + result = write_nonblock(data) + rescue IO::WaitWritable, Errno::EINTR + IO.select(nil, [self]) + retry + end + result end def io.recv(size) - read_nonblock(size) + begin + result = read_nonblock(size) + rescue IO::WaitReadable, Errno::EINTR + timeout_in_seconds = 20 + if IO.select([self], nil, [self], timeout_in_seconds) == nil + raise "Unexpected spurious read wakeup" + end + retry + end + result end end io diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/version.rb new/lib/net/ssh/version.rb --- old/lib/net/ssh/version.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh/version.rb 2015-12-30 10:07:47.000000000 +0100 @@ -51,7 +51,7 @@ MINOR = 0 # The tiny component of this version of the Net::SSH library - TINY = 1 + TINY = 2 # The prerelease component of this version of the Net::SSH library # nil allowed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh.rb new/lib/net/ssh.rb --- old/lib/net/ssh.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/lib/net/ssh.rb 2015-12-30 10:07:47.000000000 +0100 @@ -188,7 +188,10 @@ # password auth method # * :non_interactive => non interactive applications should set it to true # to prefer failing a password/etc auth methods vs asking for password - def self.start(host, user, options={}, &block) + # + # If +user+ parameter is nil it defaults to USER from ssh_config, or + # local username + def self.start(host, user=nil, options={}, &block) invalid_options = options.keys - VALID_OPTIONS if invalid_options.any? raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}" @@ -222,7 +225,7 @@ transport = Transport::Session.new(host, options) auth = Authentication::Session.new(transport, options) - user = options.fetch(:user, user) + user = options.fetch(:user, user) || Etc.getlogin if auth.authenticate("ssh-connection", user, options[:password]) connection = Connection::Session.new(transport, options) if block_given? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-09-25 21:35:53.000000000 +0200 +++ new/metadata 2015-12-30 10:07:47.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: net-ssh version: !ruby/object:Gem::Version - version: 3.0.1 + version: 3.0.2 platform: ruby authors: - Jamis Buck @@ -14,24 +14,24 @@ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD - Y29tMB4XDTE0MTIwMjE3MzkyMFoXDTE1MTIwMjE3MzkyMFowQjEQMA4GA1UEAwwH + Y29tMB4XDTE1MTIwNjIxMDYyNFoXDTE2MTIwNTIxMDYyNFowQjEQMA4GA1UEAwwH bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk - ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0qnw4JV5JN - MWelqu7pnW2z6GZJ7+zLFYJQNETJyF0U5zo7aCRK08OeUxnpu/TCCXK8iQVkNLfz - 9pVIhF+X8pMEIruAkYGwBt1aWfuSNeyodyMk0vpZdxBHbOTJ4qBRUc6qOtNOeOzv - 8ObYUX52P/EMMaeXTRU+e7MGkB9pb6FvPPNx5akxwIaoRvtcMsc/hJnQuP5r96w6 - t06MgKbXhWAX6gev0RVlrQqzxXst6iuvsrgZGjFqzob5wbTiX9M0+bFAB0EI7tJC - sv5keEbtNRaU7p3ZbMm4wTHHJLOtD+BpUCSzwv4ToNj9mZtJBMYw2Eeo7z1DklEG - mr95zbe+zNMCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1bTfpzmitXwv - LmTXi0IO5vd8NGYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQA0Aps8 - UPINGa8XUUtrZtzrgX0/iyXNkKY1ld85g1N3WKEAVLfQI7TlGr0Qv2Ekx6RqlxbR - Vyq08pytSnghW2otR3bIGMGQzqxAeRLb25cjEwH7YIJ32n7ZC1fpMnBZOBDmueWA - B9EonmoO3ne7AJSgIvBbZzBPhzM4HrQGRW8LsPFsuj+dcJI43HOQwkmv2TRz0+t6 - mGZldmqLcK0abv4JepLfB9XTue3kuyA29NGBibqyvRwlKckLpvKfHZX6Jxad8xxm - MbvRpzgROzyfw1qYi4dnIyMwTtXFFcZ0a2jpxHPkcTYFK6TzvFgDLAP0Y/u9jqUQ - eZ7/3CdSi/isZHEw + ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMYnhNtn0f6p + nTylB8mE8lMdoMLJC8KwpMWsvk73Pe2WVDsH/OSwwwz6oUGk1i70cJyDjIEBNpwT + 88GpVXJSumvqVsf9fCg3mWNeb5t0J+aeNm9MIvYVMTqj5tydoXQiwnILRDYHV9tZ + 1c3o59/VlahSTpZ7YEgzVufpAkvEGkbJiG849exiipK7MN/ZIkMOxYVnyRXk43Xc + 6GYlsHOfSgPwcXwW5g57DCwLQLWrjDsTka28dxDmO7B5Lv5EqzINxVxWsu43OgZG + 21Io/jIyf5PNpeKPKNGDuAQJ8mvdMYBJoDhtCwgsUYbl0BZzA7g4ytl51HtIeP+j + Qp/eAvs/RrECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBfKiwO2eM4NE + iRrVG793qEPLYyMwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQCfZFdb + p4jzkfIzGDbiOxd0R8sdqJoC4nMLEgnQ7dLulawwA3IXe3sHAKgA5kmH3prsKc5H + zVmM5NlH2P1nRbegIkQTYiIod1hZQCNxdmVG/fprMqPq0ybpUOjjrP5pj0OtszE1 + F2dQia1hOEstMR+n0nAtWII9HJAEyeZjVV0s2Cl7Pt85XJ3hxFcCKwzqsK5xRI7a + B3vwh3/JJYrFonIohQ//Lg9qTZASEkoKLlq1/hFeICoCGGIGLq45ZB7CzXLooCKi + s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH + e2C9M1m/2odPZo8h -----END CERTIFICATE----- -date: 2015-09-25 00:00:00.000000000 Z +date: 2015-12-30 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: test-unit @@ -195,14 +195,16 @@ - test/integration/Vagrantfile - test/integration/common.rb - test/integration/playbook.yml +- test/integration/test_forward.rb - test/integration/test_id_rsa_keys.rb +- test/integration/test_proxy.rb - test/known_hosts/github - test/known_hosts/github_hash -- test/manual/test_forward.rb - test/manual/test_pageant.rb - test/start/test_connection.rb - test/start/test_options.rb - test/start/test_transport.rb +- test/start/test_user_nil.rb - test/test_all.rb - test/test_buffer.rb - test/test_buffered_io.rb Files old/metadata.gz.sig and new/metadata.gz.sig differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/net-ssh-public_cert.pem new/net-ssh-public_cert.pem --- old/net-ssh-public_cert.pem 2015-09-25 21:35:53.000000000 +0200 +++ new/net-ssh-public_cert.pem 2015-12-30 10:07:47.000000000 +0100 @@ -1,20 +1,20 @@ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRAwDgYDVQQDDAduZXQt c3NoMRkwFwYKCZImiZPyLGQBGRYJc29sdXRpb3VzMRMwEQYKCZImiZPyLGQBGRYD -Y29tMB4XDTE0MTIwMjE3MzkyMFoXDTE1MTIwMjE3MzkyMFowQjEQMA4GA1UEAwwH +Y29tMB4XDTE1MTIwNjIxMDYyNFoXDTE2MTIwNTIxMDYyNFowQjEQMA4GA1UEAwwH bmV0LXNzaDEZMBcGCgmSJomT8ixkARkWCXNvbHV0aW91czETMBEGCgmSJomT8ixk -ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0qnw4JV5JN -MWelqu7pnW2z6GZJ7+zLFYJQNETJyF0U5zo7aCRK08OeUxnpu/TCCXK8iQVkNLfz -9pVIhF+X8pMEIruAkYGwBt1aWfuSNeyodyMk0vpZdxBHbOTJ4qBRUc6qOtNOeOzv -8ObYUX52P/EMMaeXTRU+e7MGkB9pb6FvPPNx5akxwIaoRvtcMsc/hJnQuP5r96w6 -t06MgKbXhWAX6gev0RVlrQqzxXst6iuvsrgZGjFqzob5wbTiX9M0+bFAB0EI7tJC -sv5keEbtNRaU7p3ZbMm4wTHHJLOtD+BpUCSzwv4ToNj9mZtJBMYw2Eeo7z1DklEG -mr95zbe+zNMCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQU1bTfpzmitXwv -LmTXi0IO5vd8NGYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQA0Aps8 -UPINGa8XUUtrZtzrgX0/iyXNkKY1ld85g1N3WKEAVLfQI7TlGr0Qv2Ekx6RqlxbR -Vyq08pytSnghW2otR3bIGMGQzqxAeRLb25cjEwH7YIJ32n7ZC1fpMnBZOBDmueWA -B9EonmoO3ne7AJSgIvBbZzBPhzM4HrQGRW8LsPFsuj+dcJI43HOQwkmv2TRz0+t6 -mGZldmqLcK0abv4JepLfB9XTue3kuyA29NGBibqyvRwlKckLpvKfHZX6Jxad8xxm -MbvRpzgROzyfw1qYi4dnIyMwTtXFFcZ0a2jpxHPkcTYFK6TzvFgDLAP0Y/u9jqUQ -eZ7/3CdSi/isZHEw +ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMYnhNtn0f6p +nTylB8mE8lMdoMLJC8KwpMWsvk73Pe2WVDsH/OSwwwz6oUGk1i70cJyDjIEBNpwT +88GpVXJSumvqVsf9fCg3mWNeb5t0J+aeNm9MIvYVMTqj5tydoXQiwnILRDYHV9tZ +1c3o59/VlahSTpZ7YEgzVufpAkvEGkbJiG849exiipK7MN/ZIkMOxYVnyRXk43Xc +6GYlsHOfSgPwcXwW5g57DCwLQLWrjDsTka28dxDmO7B5Lv5EqzINxVxWsu43OgZG +21Io/jIyf5PNpeKPKNGDuAQJ8mvdMYBJoDhtCwgsUYbl0BZzA7g4ytl51HtIeP+j +Qp/eAvs/RrECAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBfKiwO2eM4NE +iRrVG793qEPLYyMwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQCfZFdb +p4jzkfIzGDbiOxd0R8sdqJoC4nMLEgnQ7dLulawwA3IXe3sHAKgA5kmH3prsKc5H +zVmM5NlH2P1nRbegIkQTYiIod1hZQCNxdmVG/fprMqPq0ybpUOjjrP5pj0OtszE1 +F2dQia1hOEstMR+n0nAtWII9HJAEyeZjVV0s2Cl7Pt85XJ3hxFcCKwzqsK5xRI7a +B3vwh3/JJYrFonIohQ//Lg9qTZASEkoKLlq1/hFeICoCGGIGLq45ZB7CzXLooCKi +s/ZUKye79ELwFYKJOhjW5g725OL3hy+llhEleytwKRwgXFQBPTC4f5UkdxZVVWGH +e2C9M1m/2odPZo8h -----END CERTIFICATE----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/net-ssh.gemspec new/net-ssh.gemspec --- old/net-ssh.gemspec 2015-09-25 21:35:53.000000000 +0200 +++ new/net-ssh.gemspec 2015-12-30 10:07:47.000000000 +0100 @@ -2,17 +2,17 @@ # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- -# stub: net-ssh 3.0.1 ruby lib +# stub: net-ssh 3.0.2 ruby lib Gem::Specification.new do |s| s.name = "net-ssh" - s.version = "3.0.1" + s.version = "3.0.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Jamis Buck", "Delano Mandelbaum", "Mikl\u{f3}s Fazekas"] s.cert_chain = ["net-ssh-public_cert.pem"] - s.date = "2015-09-25" + s.date = "2015-12-30" s.description = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2." s.email = "net-ssh@solutious.com" s.extra_rdoc_files = [ @@ -144,14 +144,16 @@ "test/integration/Vagrantfile", "test/integration/common.rb", "test/integration/playbook.yml", + "test/integration/test_forward.rb", "test/integration/test_id_rsa_keys.rb", + "test/integration/test_proxy.rb", "test/known_hosts/github", "test/known_hosts/github_hash", - "test/manual/test_forward.rb", "test/manual/test_pageant.rb", "test/start/test_connection.rb", "test/start/test_options.rb", "test/start/test_transport.rb", + "test/start/test_user_nil.rb", "test/test_all.rb", "test/test_buffer.rb", "test/test_buffered_io.rb", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/README.txt new/test/README.txt --- old/test/README.txt 2015-09-25 21:35:53.000000000 +0200 +++ new/test/README.txt 2015-12-30 10:07:47.000000000 +0100 @@ -16,25 +16,3 @@ brew install ansible ; ansible-galaxy install rvm_io.rvm1-ruby ; vagrant up ; vagrant ssh cd /net-ssh ; rake integration-test - -PORT FORWARDING TESTS - - ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb - -test_forward.rb must be run separately from the test suite because -it requires authorizing your public SSH keys on you localhost. - -If you already have keys you can do this: - - cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys - -If you don't have keys see: - - http://kimmo.suominen.com/docs/ssh/#ssh-keygen - -You should now be able to login to your localhost with out -bring prompted for a password: - - ssh localhost - --Delano diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/connection/test_channel.rb new/test/connection/test_channel.rb --- old/test/connection/test_channel.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/connection/test_channel.rb 2015-12-30 10:07:47.000000000 +0100 @@ -74,8 +74,11 @@ assert !channel.closing? connection.expect { |t,packet| assert_equal CHANNEL_CLOSE, packet.type } + connection.expects(:cleanup_channel).with(channel) channel.close + channel.process + assert channel.closing? end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/connection/test_session.rb new/test/connection/test_session.rb --- old/test/connection/test_session.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/connection/test_session.rb 2015-12-30 10:07:47.000000000 +0100 @@ -117,14 +117,14 @@ end def test_process_should_exit_after_processing_if_block_is_true_then_false - session.channels[0] = stub("channel", :closing? => false) + session.channels[0] = stub("channel", :local_closed? => false) session.channels[0].expects(:process) IO.expects(:select).never process_times(2) end def test_process_should_not_process_channels_that_are_closing - session.channels[0] = stub("channel", :closing? => true) + session.channels[0] = stub("channel", :local_closed? => true) session.channels[0].expects(:process).never IO.expects(:select).never process_times(2) @@ -299,8 +299,17 @@ end def test_channel_close_packet_should_be_routed_to_corresponding_channel_and_channel_should_be_closed_and_removed - channel_at(14).expects(:do_close).with() - session.channels[14].expects(:close).with() + session.channels[14] = stub("channel") do + # this simulates the case where we closed the channel first, sent + # CHANNEL_CLOSE to server and are waiting for server's response. + expects(:local_closed?).returns(true) + expects(:do_close) + expects(:close).with() + expects(:remote_closed!).with() + expects(:remote_closed?).with().returns(true) + expects(:local_id).returns(14) + end + transport.return(CHANNEL_CLOSE, :long, 14) process_times(2) assert session.channels.empty? @@ -526,7 +535,7 @@ end def channel_at(local_id) - session.channels[local_id] = stub("channel", :process => true, :closing? => false) + session.channels[local_id] = stub("channel", :process => true, :local_closed? => false) end def transport(options={}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/README.txt new/test/integration/README.txt --- old/test/integration/README.txt 2015-09-25 21:35:53.000000000 +0200 +++ new/test/integration/README.txt 2015-12-30 10:07:47.000000000 +0100 @@ -8,10 +8,8 @@ Setup: ansible-galaxy install rvm_io.rvm1-ruby - vagrant up - vagrant ssh - cd /net-ssh - rake integration-test + vagrant up ; vagrant ssh + rake test # TODO diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/common.rb new/test/integration/common.rb --- old/test/integration/common.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/integration/common.rb 2015-12-30 10:07:47.000000000 +0100 @@ -14,6 +14,12 @@ raise "Command: #{command} failed:#{status.exitstatus}" unless res end + def tmpdir(&block) + Dir.mktmpdir do |dir| + yield(dir) + end + end + def set_authorized_key(user,pubkey) authorized_key = "/home/#{user}/.ssh/authorized_keys" sh "sudo cp #{pubkey} #{authorized_key}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/playbook.yml new/test/integration/playbook.yml --- old/test/integration/playbook.yml 2015-09-25 21:35:53.000000000 +0200 +++ new/test/integration/playbook.yml 2015-12-30 10:07:47.000000000 +0100 @@ -14,7 +14,7 @@ roles: - { role: rvm_io.rvm1-ruby, tags: ruby, sudo: True, - rvm1_rubies: ["ruby-{{ruby_version}}"], + rvm1_rubies: ["ruby-{{ruby_version}}","ruby-2.3.0"], rvm1_install_path: "{{rvm1_install_path}}", rvm1_gpg_key_server: pool.sks-keyservers.net, when: "'{{current_ruby_version.stdout|default()}}' != '{{ruby_version}}'" } @@ -34,6 +34,14 @@ - name: sshd debug lineinfile: dest='/etc/ssh/sshd_config' line='LogLevel DEBUG' regexp=LogLevel notify: restart sshd + - name: put NET_SSH_RUN_INTEGRATION_TESTS=YES environment + lineinfile: dest='/etc/environment' line='NET_SSH_RUN_INTEGRATION_TESTS=YES' + - name: change dir in bashrc + lineinfile: dest=/home/vagrant/.bashrc owner=vagrant mode=0644 + regexp='^cd ' line='cd /net-ssh' + - apt: name="{{item}}" state=present + with_items: + - pv - gem: name="{{item}}" state=present executable=/usr/local/rvm/rubies/ruby-{{ruby_version}}/bin/gem with_items: - byebug diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/test_forward.rb new/test/integration/test_forward.rb --- old/test/integration/test_forward.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/integration/test_forward.rb 2015-12-30 10:07:47.000000000 +0100 @@ -0,0 +1,435 @@ +# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb + +# Tests for the following patch: +# +# http://github.com/net-ssh/net-ssh/tree/portfwfix +# +# It fixes 3 issues, regarding closing forwarded ports: +# +# 1.) if client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed. +# 2.) if client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with +# 3.) if server closes the sending side, the on_eof is not handled. +# +# More info: +# +# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7 + +require_relative './common' +require 'net/ssh/buffer' +require 'net/ssh' +require 'timeout' +require 'tempfile' + +class TestForward < Test::Unit::TestCase + include IntegrationTestHelpers + + def localhost + 'localhost' + end + + def user + 'net_ssh_1' + end + + def ssh_start_params + [localhost ,user , {:keys => @key_id_rsa, :verbose => :debug}] + end + + def setup_ssh_env(&block) + tmpdir do |dir| + @key_id_rsa = "#{dir}/id_rsa" + sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub" + sh "ssh-keygen -f #{@key_id_rsa} -t rsa -N ''" + set_authorized_key(user,"#{@key_id_rsa}.pub") + yield + end + end + + def start_server_sending_lot_of_data(exceptions) + server = TCPServer.open(0) + Thread.start do + loop do + Thread.start(server.accept) do |client| + begin + 10000.times do |i| + client.puts "item#{i}" + end + client.close + rescue + exceptions << $! + raise + end + end + end + end + return server + end + + def start_server_closing_soon(exceptions=nil) + server = TCPServer.open(0) + Thread.start do + loop do + Thread.start(server.accept) do |client| + begin + client.recv(1024) + client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) + client.close + rescue + exceptions << $! + raise + end + end + end + end + return server + end + + def test_in_file_no_password + setup_ssh_env do + ret = Net::SSH.start(*ssh_start_params) do |ssh| + #ret = Net::SSH.start("localhost", "net_ssh_1", {keys: @key_id_rsa}) do |ssh| + ssh.exec! 'echo "hello from:$USER"' + end + assert_equal "hello from:net_ssh_1\n", ret + end + end + + def test_local_ephemeral_port_should_work_correctly + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + + assert_nothing_raised do + assigned_port = session.forward.local(0, localhost, 22) + assert_not_nil assigned_port + assert_operator assigned_port, :>, 0 + end + end + end + + def test_remote_ephemeral_port_should_work_correctly + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + + assert_nothing_raised do + session.forward.remote(22, localhost, 0, localhost) + session.loop { !(session.forward.active_remotes.length > 0) } + assigned_port = session.forward.active_remotes.first[0] + assert_not_nil assigned_port + assert_operator assigned_port, :>, 0 + end + end + end + + def test_remote_callback_should_fire + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + + assert_nothing_raised do + got_port = nil + session.forward.remote(22, localhost, 0, localhost) do |port| + got_port = port + end + session.loop { !(session.forward.active_remotes.length > 0) } + assert_operator session.forward.active_remote_destinations.length, :==, 1 + assert_operator session.forward.active_remote_destinations.keys.first, :==, [ 22, localhost ] + assert_operator session.forward.active_remote_destinations.values.first, :==, [ got_port, localhost ] + assert_operator session.forward.active_remotes.first, :==, [ got_port, localhost ] + assigned_port = session.forward.active_remotes.first[0] + assert_operator got_port, :==, assigned_port + assert_not_nil assigned_port + assert_operator assigned_port, :>, 0 + end + end + end + + def test_remote_callback_should_fire_on_error_and_still_throw_exception + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + + assert_nothing_raised do + session.forward.remote(22, localhost, 22, localhost) do |port| + assert_operator port, :==, :error + end + end + assert_raises(Net::SSH::Exception) do + session.loop { true } + end + end + end + + def test_remote_callback_should_fire_on_error_but_not_throw_exception_if_asked_not_to + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + + assert_nothing_raised do + got_port = nil + session.forward.remote(22, localhost, 22, localhost) do |port| + assert_operator port, :==, :error + got_port = port + :no_exception + end + session.loop { !got_port } + assert_operator got_port, :==, :error + assert_operator session.forward.active_remotes.length, :==, 0 + end + end + end + + def test_loop_should_not_abort_when_local_side_of_forward_is_closed + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + server_exc = Queue.new + server = start_server_sending_lot_of_data(server_exc) + remote_port = server.addr[1] + local_port = 0 # request ephemeral port + session.forward.local(local_port, localhost, remote_port) + client_done = Queue.new + Thread.start do + begin + client = TCPSocket.new(localhost, local_port) + client.recv(1024) + client.close + sleep(0.2) + ensure + client_done << true + end + end + session.loop(0.1) { client_done.empty? } + assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty? + end + end + + def test_loop_should_not_abort_when_local_side_of_forward_is_reset + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + server_exc = Queue.new + server = start_server_sending_lot_of_data(server_exc) + remote_port = server.addr[1] + local_port = 0 # request ephemeral port + session.forward.local(local_port, localhost, remote_port) + client_done = Queue.new + Thread.start do + begin + client = TCPSocket.new(localhost, local_port) + client.recv(1024) + client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) + client.close + sleep(0.1) + ensure + client_done << true + end + end + session.loop(0.1) { client_done.empty? } + assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty? + end + end + + def create_local_socket(&blk) + tempfile = Tempfile.new("net_ssh_forward_test") + path = tempfile.path + tempfile.delete + yield UNIXServer.open(path) + File.delete(path) + end if defined?(UNIXServer) + + def test_forward_local_unix_socket_to_remote_port + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + server_exc = Queue.new + server = start_server_sending_lot_of_data(server_exc) + remote_port = server.addr[1] + client_data = nil + + create_local_socket do |local_socket| + session.forward.local(local_socket, localhost, remote_port) + client_done = Queue.new + + Thread.start do + begin + client = UNIXSocket.new(local_socket.path) + client_data = client.recv(1024) + client.close + sleep(0.2) + ensure + client_done << true + end + end + + session.loop(0.1) { client_done.empty? } + end + + assert_not_nil(client_data, "client should have received data") + assert(client_data.match(/item\d/), 'client should have received the string item') + end + end if defined?(UNIXSocket) + + def test_loop_should_not_abort_when_server_side_of_forward_is_closed + setup_ssh_env do + session = Net::SSH.start(*ssh_start_params) + server = start_server_closing_soon + remote_port = server.addr[1] + local_port = 0 # request ephemeral port + session.forward.local(local_port, localhost, remote_port) + client_done = Queue.new + Thread.start do + begin + client = TCPSocket.new(localhost, local_port) + 1.times do |i| + client.puts "item#{i}" + end + client.close + sleep(0.1) + ensure + client_done << true + end + end + session.loop(0.1) { client_done.empty? } + end + end + + def start_server + server = TCPServer.open(0) + Thread.start do + loop do + Thread.start(server.accept) do |client| + yield(client) + end + end + end + return server + end + + def test_client_close_should_be_handled_remote + setup_ssh_env do + message = "This is a small message!"*1000 + session = Net::SSH.start(*ssh_start_params) + server_done = Queue.new + server = start_server do |client| + begin + data = client.read message.size + server_done << data + client.close + rescue + server_done << $! + end + end + client_done = Queue.new + got_remote_port = Queue.new + local_port = server.addr[1] + session.forward.remote(0, localhost, local_port) do |actual_remote_port| + got_remote_port << actual_remote_port + end + session.loop(0.1) { got_remote_port.empty? } + remote_port = got_remote_port.pop + Thread.start do + begin + client = TCPSocket.new(localhost, remote_port) + client.write(message) + client.close + client_done << true + rescue + client_done << $! + end + end + timeout(5) do + session.loop(0.1) { server_done.empty? } + assert_equal message, server_done.pop + end + end + end + + def test_client_close_should_be_handled + setup_ssh_env do + message = "This is a small message!"*1000 + session = Net::SSH.start(*ssh_start_params) + server_done = Queue.new + server = start_server do |client| + begin + data = client.read message.size + server_done << data + client.close + rescue + server_done << $! + end + end + client_done = Queue.new + remote_port = server.addr[1] + local_port = session.forward.local(0, localhost, remote_port) + Thread.start do + begin + client = TCPSocket.new(localhost, local_port) + client.write(message) + client.close + client_done << true + rescue + client_done << $! + end + end + timeout(5) do + session.loop(0.1) { server_done.empty? } + assert_equal message, server_done.pop + end + end + end + + def test_server_eof_should_be_handled_remote + setup_ssh_env do + message = "This is a small message!" + session = Net::SSH.start(*ssh_start_params) + server = start_server do |client| + client.write message + client.close + end + client_done = Queue.new + got_remote_port = Queue.new + local_port = server.addr[1] + session.forward.remote(0, localhost, local_port) do |actual_remote_port| + got_remote_port << actual_remote_port + end + session.loop(0.1) { got_remote_port.empty? } + remote_port = got_remote_port.pop + Thread.start do + begin + client = TCPSocket.new(localhost, remote_port) + data = client.read(4096) + client.close + client_done << data + rescue + client_done << $! + end + end + timeout(5) do + session.loop(0.1) { client_done.empty? } + assert_equal message, client_done.pop + end + end + end + + def test_server_eof_should_be_handled + setup_ssh_env do + message = "This is a small message!" + session = Net::SSH.start(*ssh_start_params) + server = start_server do |client| + client.write message + client.close + end + client_done = Queue.new + remote_port = server.addr[1] + local_port = session.forward.local(0, localhost, remote_port) + Thread.start do + begin + client = TCPSocket.new(localhost, local_port) + data = client.read(4096) + client.close + client_done << data + rescue + client_done << $! + end + end + timeout(5) do + session.loop(0.1) { client_done.empty? } + assert_equal message, client_done.pop + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/test_id_rsa_keys.rb new/test/integration/test_id_rsa_keys.rb --- old/test/integration/test_id_rsa_keys.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/integration/test_id_rsa_keys.rb 2015-12-30 10:07:47.000000000 +0100 @@ -10,12 +10,6 @@ class TestIDRSAPKeys < Test::Unit::TestCase include IntegrationTestHelpers - def tmpdir(&block) - Dir.mktmpdir do |dir| - yield(dir) - end - end - def test_in_file_no_password tmpdir do |dir| sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub" @@ -81,4 +75,22 @@ assert_equal "hello from:net_ssh_1\n", ret end end + + def test_asks_for_passwords_when_read_from_memory + tmpdir do |dir| + sh "rm -rf #{dir}/id_rsa #{dir}/id_rsa.pub" + sh "ssh-keygen -f #{dir}/id_rsa -t rsa -N 'pwd12'" + set_authorized_key('net_ssh_1',"#{dir}/id_rsa.pub") + private_key = File.read("#{dir}/id_rsa") + + options = {keys: [], key_data: [private_key]} + + key_manager = Net::SSH::Authentication::KeyManager.new(nil, options) + + Net::SSH::KeyFactory.expects(:prompt).with('Enter passphrase for :', false).returns('pwd12') + Net::SSH.start("localhost", "net_ssh_1", options) do |ssh| + ssh.exec! 'whoami' + end + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/integration/test_proxy.rb new/test/integration/test_proxy.rb --- old/test/integration/test_proxy.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/integration/test_proxy.rb 2015-12-30 10:07:47.000000000 +0100 @@ -0,0 +1,93 @@ +require_relative './common' +require 'net/ssh/buffer' +require 'net/ssh' +require 'timeout' +require 'tempfile' +require 'net/ssh/proxy/command' + +class TestProxy < Test::Unit::TestCase + include IntegrationTestHelpers + + def localhost + 'localhost' + end + + def user + 'net_ssh_1' + end + + def ssh_start_params(options) + [localhost ,user , {:keys => @key_id_rsa, :verbose => :debug}.merge(options)] + end + + def setup_ssh_env(&block) + tmpdir do |dir| + @key_id_rsa = "#{dir}/id_rsa" + sh "rm -rf #{@key_id_rsa} #{@key_id_rsa}.pub" + sh "ssh-keygen -f #{@key_id_rsa} -t rsa -N ''" + set_authorized_key(user,"#{@key_id_rsa}.pub") + yield + end + end + + def test_smoke + setup_ssh_env do + proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost 22") + msg = 'echo123' + ret = Net::SSH.start(*ssh_start_params(:proxy => proxy)) do |ssh| + ssh.exec! "echo \"$USER:#{msg}\"" + end + assert_equal "net_ssh_1:#{msg}\n", ret + end + end + + def with_spurious_write_wakeup_emulate(rate=99,&block) + orig_io_select = Net::SSH::Compat.method(:io_select) + count = 0 + Net::SSH::Compat.singleton_class.send(:define_method,:io_select) do |*params| + count += 1 + if (count % rate != 0) + if params && params[1] && !params[1].empty? + return [[],params[1],[]] + end + #if params && params[0] && !params[0].empty? + #return [params[0],[],[]] + #end + end + IO.select(*params) + end + begin + yield + ensure + Net::SSH::Compat.singleton_class.send(:define_method,:io_select,&orig_io_select) + end + end + + def test_with_rate_limit_and_spurious_wakeup + system("sudo sh -c 'echo 4096 > /proc/sys/fs/pipe-max-size'") + begin + setup_ssh_env do + proxy = Net::SSH::Proxy::Command.new("/usr/bin/pv --rate-limit 100k | /bin/nc localhost 22") + #proxy = Net::SSH::Proxy::Command.new("/bin/nc localhost 22") + begin + large_msg = 'echo123'*30000 + ok = Net::SSH.start(*ssh_start_params(:proxy => proxy)) do |ssh| + with_spurious_write_wakeup_emulate do + ret = ssh.exec! "echo \"$USER:#{large_msg}\"" + #assert_equal "net_ssh_1:#{large_msg}\n", ret + assert_equal "/bin/sh: Argument list too long\n", ret + hello_count = 1000 + ret = ssh.exec! "ruby -e 'puts \"Hello\"*#{hello_count}'" + assert_equal "Hello"*hello_count+"\n", ret + end + :ok + end + end + assert_equal :ok, ok + end + ensure + system("sudo sh -c 'echo 1048576 > /proc/sys/fs/pipe-max-size'") + end + end + +end \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/manual/test_forward.rb new/test/manual/test_forward.rb --- old/test/manual/test_forward.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/manual/test_forward.rb 1970-01-01 01:00:00.000000000 +0100 @@ -1,285 +0,0 @@ -# $ ruby -Ilib -Itest -rrubygems test/manual/test_forward.rb - -# Tests for the following patch: -# -# http://github.com/net-ssh/net-ssh/tree/portfwfix -# -# It fixes 3 issues, regarding closing forwarded ports: -# -# 1.) if client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed. -# 2.) if client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with -# 3.) if server closes the sending side, the on_eof is not handled. -# -# More info: -# -# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7 - -require 'common' -require 'net/ssh/buffer' -require 'net/ssh' -require 'timeout' -require 'tempfile' - -class TestForward < Test::Unit::TestCase - - def localhost - 'localhost' - end - - def ssh_start_params - [localhost ,ENV['USER'], {:keys => "~/.ssh/id_rsa", :verbose => :debug}] - end - - def start_server_sending_lot_of_data(exceptions) - server = TCPServer.open(0) - Thread.start do - loop do - Thread.start(server.accept) do |client| - begin - 10000.times do |i| - client.puts "item#{i}" - end - client.close - rescue - exceptions << $! - raise - end - end - end - end - return server - end - - def start_server_closing_soon(exceptions=nil) - server = TCPServer.open(0) - Thread.start do - loop do - Thread.start(server.accept) do |client| - begin - client.recv(1024) - client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) - client.close - rescue - exceptions << $! - raise - end - end - end - end - return server - end - - def test_local_ephemeral_port_should_work_correctly - session = Net::SSH.start(*ssh_start_params) - - assert_nothing_raised do - assigned_port = session.forward.local(0, localhost, 22) - assert_not_nil assigned_port - assert_operator assigned_port, :>, 0 - end - end - - def test_remote_ephemeral_port_should_work_correctly - session = Net::SSH.start(*ssh_start_params) - - assert_nothing_raised do - session.forward.remote(22, localhost, 0, localhost) - session.loop { !(session.forward.active_remotes.length > 0) } - assigned_port = session.forward.active_remotes.first[0] - assert_not_nil assigned_port - assert_operator assigned_port, :>, 0 - end - end - - def test_remote_callback_should_fire - session = Net::SSH.start(*ssh_start_params) - - assert_nothing_raised do - got_port = nil - session.forward.remote(22, localhost, 0, localhost) do |port| - got_port = port - end - session.loop { !(session.forward.active_remotes.length > 0) } - assert_operator session.forward.active_remote_destinations.length, :==, 1 - assert_operator session.forward.active_remote_destinations.keys.first, :==, [ 22, localhost ] - assert_operator session.forward.active_remote_destinations.values.first, :==, [ got_port, localhost ] - assert_operator session.forward.active_remotes.first, :==, [ got_port, localhost ] - assigned_port = session.forward.active_remotes.first[0] - assert_operator got_port, :==, assigned_port - assert_not_nil assigned_port - assert_operator assigned_port, :>, 0 - end - end - - def test_remote_callback_should_fire_on_error_and_still_throw_exception - session = Net::SSH.start(*ssh_start_params) - - assert_nothing_raised do - session.forward.remote(22, localhost, 22, localhost) do |port| - assert_operator port, :==, :error - end - end - assert_raises(Net::SSH::Exception) do - session.loop { true } - end - end - - def test_remote_callback_should_fire_on_error_but_not_throw_exception_if_asked_not_to - session = Net::SSH.start(*ssh_start_params) - - assert_nothing_raised do - got_port = nil - session.forward.remote(22, localhost, 22, localhost) do |port| - assert_operator port, :==, :error - got_port = port - :no_exception - end - session.loop { !got_port } - assert_operator port, :==, :error - assert_operator session.forward.active_remotes.length, :==, 0 - end - end - - def test_loop_should_not_abort_when_local_side_of_forward_is_closed - session = Net::SSH.start(*ssh_start_params) - server_exc = Queue.new - server = start_server_sending_lot_of_data(server_exc) - remote_port = server.addr[1] - local_port = 0 # request ephemeral port - session.forward.local(local_port, localhost, remote_port) - client_done = Queue.new - Thread.start do - begin - client = TCPSocket.new(localhost, local_port) - client.recv(1024) - client.close - sleep(0.2) - ensure - client_done << true - end - end - session.loop(0.1) { client_done.empty? } - assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty? - end - - def test_loop_should_not_abort_when_local_side_of_forward_is_reset - session = Net::SSH.start(*ssh_start_params) - server_exc = Queue.new - server = start_server_sending_lot_of_data(server_exc) - remote_port = server.addr[1] - local_port = 0 # request ephemeral port - session.forward.local(local_port, localhost, remote_port) - client_done = Queue.new - Thread.start do - begin - client = TCPSocket.new(localhost, local_port) - client.recv(1024) - client.setsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER, [1, 0].pack("ii")) - client.close - sleep(0.1) - ensure - client_done << true - end - end - session.loop(0.1) { client_done.empty? } - assert_equal "Broken pipe", "#{server_exc.pop}" unless server_exc.empty? - end - - def create_local_socket(&blk) - tempfile = Tempfile.new("net_ssh_forward_test") - path = tempfile.path - tempfile.delete - yield UNIXServer.open(path) - File.delete(path) - end if defined?(UNIXServer) - - def test_forward_local_unix_socket_to_remote_port - session = Net::SSH.start(*ssh_start_params) - server_exc = Queue.new - server = start_server_sending_lot_of_data(server_exc) - remote_port = server.addr[1] - client_data = nil - - create_local_socket do |local_socket| - session.forward.local(local_socket, localhost, remote_port) - client_done = Queue.new - - Thread.start do - begin - client = UNIXSocket.new(local_socket.path) - client_data = client.recv(1024) - client.close - sleep(0.2) - ensure - client_done << true - end - end - - session.loop(0.1) { client_done.empty? } - end - - assert_not_nil(client_data, "client should have received data") - assert(client_data.match(/item\d/), 'client should have received the string item') - end if defined?(UNIXSocket) - - def test_loop_should_not_abort_when_server_side_of_forward_is_closed - session = Net::SSH.start(*ssh_start_params) - server = start_server_closing_soon - remote_port = server.addr[1] - local_port = 0 # request ephemeral port - session.forward.local(local_port, localhost, remote_port) - client_done = Queue.new - Thread.start do - begin - client = TCPSocket.new(localhost, local_port) - 1.times do |i| - client.puts "item#{i}" - end - client.close - sleep(0.1) - ensure - client_done << true - end - end - session.loop(0.1) { client_done.empty? } - end - - def start_server - server = TCPServer.open(0) - Thread.start do - loop do - Thread.start(server.accept) do |client| - yield(client) - end - end - end - return server - end - - def test_server_eof_should_be_handled - session = Net::SSH.start(*ssh_start_params) - server = start_server do |client| - client.write "This is a small message!" - client.close - end - client_done = Queue.new - client_exception = Queue.new - client_data = Queue.new - remote_port = server.addr[1] - local_port = session.forward.local(0, localhost, remote_port) - Thread.start do - begin - client = TCPSocket.new(localhost, local_port) - data = client.read(4096) - client.close - client_done << data - rescue - client_done << $! - end - end - timeout(5) do - session.loop(0.1) { client_done.empty? } - assert_equal "This is a small message!", client_done.pop - end - end -end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/start/test_user_nil.rb new/test/start/test_user_nil.rb --- old/test/start/test_user_nil.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/test/start/test_user_nil.rb 2015-12-30 10:07:47.000000000 +0100 @@ -0,0 +1,27 @@ +require 'common' +require 'net/ssh' + +module NetSSH + class TestStartUserNil < Test::Unit::TestCase + def setup + @authentication_session = mock('authentication_session') + Net::SSH::Authentication::Session.stubs(:new).returns(@authentication_session) + Net::SSH::Transport::Session.stubs(:new).returns(mock('transport_session')) + Net::SSH::Connection::Session.stubs(:new).returns(mock('connection_session')) + end + + def test_start_should_accept_nil_user + @authentication_session.stubs(:authenticate).returns(true) + assert_nothing_raised do + Net::SSH.start('localhost') + end + end + + def test_start_should_use_default_user_when_nil + @authentication_session.stubs(:authenticate).with() {|_next_service, user, _password| user == Etc.getlogin }.returns(true) + assert_nothing_raised do + Net::SSH.start('localhost') + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/test_all.rb new/test/test_all.rb --- old/test/test_all.rb 2015-09-25 21:35:53.000000000 +0200 +++ new/test/test_all.rb 2015-12-30 10:07:47.000000000 +0100 @@ -4,7 +4,7 @@ # $ ruby -Ilib -Itest -rrubygems test/transport/test_server_version.rb Dir.chdir(File.dirname(__FILE__)) do test_files = Dir['**/test_*.rb']-['test_all.rb'] # prevent circular require - test_files -= Dir['integration/test_*.rb'] + test_files -= Dir['integration/test_*.rb'] unless ENV['NET_SSH_RUN_INTEGRATION_TESTS'] test_files = test_files.reject { |f| f =~ /^manual/ } test_files = test_files.select { |f| f =~ Regexp.new(ENV['ONLY']) } if ENV['ONLY'] test_files = test_files.reject { |f| f =~ Regexp.new(ENV['EXCEPT']) } if ENV['EXCEPT']