summaryrefslogtreecommitdiff
path: root/test/connection
diff options
context:
space:
mode:
authorJamis Buck <jamis@37signals.com>2007-08-15 16:02:43 +0000
committerJamis Buck <jamis@37signals.com>2007-08-15 16:02:43 +0000
commit317cd10369f21ef067916c0cec749b94c7e737d7 (patch)
tree70b8b392121f80937d6f360ac73fed18f88e69e8 /test/connection
parent98d535cf0e47190350973c42bc3301c79ca7a657 (diff)
downloadnet-ssh-317cd10369f21ef067916c0cec749b94c7e737d7.tar.gz
connection session tests
git-svn-id: http://svn.jamisbuck.org/net-ssh/branches/v2@182 1d2a57f2-1ded-0310-ad52-83097a15a5de
Diffstat (limited to 'test/connection')
-rw-r--r--test/connection/test_session.rb416
1 files changed, 416 insertions, 0 deletions
diff --git a/test/connection/test_session.rb b/test/connection/test_session.rb
new file mode 100644
index 0000000..b6921a0
--- /dev/null
+++ b/test/connection/test_session.rb
@@ -0,0 +1,416 @@
+$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/..").uniq!
+require 'common'
+require 'net/ssh/connection/session'
+
+module Connection
+
+ class TestSession < Test::Unit::TestCase
+ include Net::SSH::Connection::Constants
+
+ def test_constructor_should_set_defaults
+ assert session.channels.empty?
+ assert session.listeners.empty?
+ assert session.pending_requests.empty?
+ assert_equal [socket], session.readers
+ assert_equal [socket], session.writers
+ end
+
+ def test_on_open_channel_should_register_block_with_given_channel_type
+ flag = false
+ session.on_open_channel("testing") { flag = true }
+ assert_not_nil session.channel_open_handlers["testing"]
+ session.channel_open_handlers["testing"].call
+ assert flag, "callback should have been invoked"
+ end
+
+ def test_forward_should_create_and_cache_instance_of_forward_service
+ assert_instance_of Net::SSH::Service::Forward, session.forward
+ assert_equal session.forward.object_id, session.forward.object_id
+ end
+
+ def test_listen_to_should_add_argument_to_readers_list
+ io = stub("io")
+ session.listen_to(io)
+ assert session.readers.include?(io)
+ assert !session.writers.include?(io)
+ assert !session.listeners.key?(io)
+ end
+
+ def test_listen_to_should_add_argument_to_writers_list_if_it_responds_to_pending_write
+ io = stub("io", :pending_write? => true)
+ session.listen_to(io)
+ assert session.readers.include?(io)
+ assert session.writers.include?(io)
+ assert !session.listeners.key?(io)
+ end
+
+ def test_listen_to_should_add_argument_to_listeners_list_if_block_is_given
+ io = stub("io", :pending_write? => true)
+ flag = false
+ session.listen_to(io) { flag = true }
+ assert !flag, "callback should not be invoked immediately"
+ assert session.readers.include?(io)
+ assert session.writers.include?(io)
+ assert session.listeners.key?(io)
+ session.listeners[io].call
+ assert flag, "callback should have been invoked"
+ end
+
+ def test_stop_listening_to_should_remove_argument_from_lists
+ io = stub("io", :pending_write? => true)
+
+ session.listen_to(io) { }
+ assert session.readers.include?(io)
+ assert session.writers.include?(io)
+ assert session.listeners.key?(io)
+
+ session.stop_listening_to(io)
+ assert !session.readers.include?(io)
+ assert !session.writers.include?(io)
+ assert !session.listeners.key?(io)
+ end
+
+ def test_send_message_should_enqueue_message_at_transport_layer
+ packet = P(:byte, REQUEST_SUCCESS)
+ session.send_message(packet)
+ assert_equal packet.to_s, socket.write_buffer
+ end
+
+ def test_open_channel_defaults_should_use_session_channel
+ flag = false
+ channel = session.open_channel { flag = true }
+ assert !flag, "callback should not be invoked immediately"
+ channel.do_open_confirmation(1,2,3)
+ assert flag, "callback should have been invoked"
+ assert_equal "session", channel.type
+ assert_equal 0, channel.local_id
+ assert_equal channel, session.channels[channel.local_id]
+
+ packet = P(:byte, CHANNEL_OPEN, :string, "session", :long, channel.local_id,
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
+ assert_equal packet.to_s, socket.write_buffer
+ end
+
+ def test_open_channel_with_type_should_use_type
+ channel = session.open_channel("direct-tcpip")
+ assert_equal "direct-tcpip", channel.type
+ packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
+ assert_equal packet.to_s, socket.write_buffer
+ end
+
+ def test_open_channel_with_extras_should_append_extras_to_packet
+ channel = session.open_channel("direct-tcpip", :string, "other.host", :long, 1234)
+ packet = P(:byte, CHANNEL_OPEN, :string, "direct-tcpip", :long, channel.local_id,
+ :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size,
+ :string, "other.host", :long, 1234)
+ assert_equal packet.to_s, socket.write_buffer
+ end
+
+ def test_send_global_request_without_callback_should_not_expect_reply
+ packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, false)
+ session.send_global_request("testing")
+ assert_equal packet.to_s, socket.write_buffer
+ assert session.pending_requests.empty?
+ end
+
+ def test_send_global_request_with_callback_should_expect_reply
+ packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, true)
+ proc = Proc.new {}
+ session.send_global_request("testing", &proc)
+ assert_equal packet.to_s, socket.write_buffer
+ assert_equal [proc], session.pending_requests
+ end
+
+ def test_send_global_request_with_extras_should_append_extras_to_packet
+ packet = P(:byte, GLOBAL_REQUEST, :string, "testing", :bool, false, :string, "other.host", :long, 1234)
+ session.send_global_request("testing", :string, "other.host", :long, 1234)
+ assert_equal packet.to_s, socket.write_buffer
+ end
+
+ def test_process_should_exit_immediately_if_block_is_false
+ session.channels[0] = stub("channel", :closing? => false)
+ session.channels[0].expects(:process).never
+ process_times(0)
+ end
+
+ def test_process_should_exit_after_processing_if_block_is_true_then_false
+ session.channels[0] = stub("channel", :closing? => 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].expects(:process).never
+ IO.expects(:select).never
+ process_times(2)
+ end
+
+ def test_global_request_packets_should_be_silently_handled_if_no_handler_exists_for_them
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, false)
+ process_times(2)
+ assert transport.queue.empty?
+ assert !socket.pending_write?
+ end
+
+ def test_global_request_packets_should_be_auto_replied_to_even_if_no_handler_exists
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
+ process_times(2)
+ assert_equal P(:byte, REQUEST_FAILURE).to_s, socket.write_buffer
+ end
+
+ def test_global_request_handler_should_not_trigger_auto_reply_if_no_reply_is_wanted
+ flag = false
+ session.on_global_request("testing") { flag = true }
+ assert !flag, "callback should not be invoked yet"
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, false)
+ process_times(2)
+ assert transport.queue.empty?
+ assert !socket.pending_write?
+ assert flag, "callback should have been invoked"
+ end
+
+ def test_global_request_handler_returning_true_should_trigger_success_auto_reply
+ flag = false
+ session.on_global_request("testing") { flag = true }
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
+ process_times(2)
+ assert_equal P(:byte, REQUEST_SUCCESS).to_s, socket.write_buffer
+ assert flag
+ end
+
+ def test_global_request_handler_returning_false_should_trigger_failure_auto_reply
+ flag = false
+ session.on_global_request("testing") { flag = true; false }
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
+ process_times(2)
+ assert_equal P(:byte, REQUEST_FAILURE).to_s, socket.write_buffer
+ assert flag
+ end
+
+ def test_global_request_handler_returning_sent_should_not_trigger_auto_reply
+ flag = false
+ session.on_global_request("testing") { flag = true; :sent }
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
+ process_times(2)
+ assert !socket.pending_write?
+ assert flag
+ end
+
+ def test_global_request_handler_returning_other_value_should_raise_error
+ session.on_global_request("testing") { "bug" }
+ transport.return(GLOBAL_REQUEST, :string, "testing", :bool, true)
+ assert_raises(RuntimeError) { process_times(2) }
+ end
+
+ def test_request_success_packets_should_invoke_next_pending_request_with_true
+ result = nil
+ session.pending_requests << Proc.new { |*args| result = args }
+ transport.return(REQUEST_SUCCESS)
+ process_times(2)
+ assert_equal [true, P(:byte, REQUEST_SUCCESS)], result
+ assert session.pending_requests.empty?
+ end
+
+ def test_request_failure_packets_should_invoke_next_pending_request_with_false
+ result = nil
+ session.pending_requests << Proc.new { |*args| result = args }
+ transport.return(REQUEST_FAILURE)
+ process_times(2)
+ assert_equal [false, P(:byte, REQUEST_FAILURE)], result
+ assert session.pending_requests.empty?
+ end
+
+ def test_channel_open_packet_without_corresponding_channel_open_handler_should_result_in_channel_open_failure
+ transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20000, :long, 0x10000)
+ process_times(2)
+ assert_equal P(:byte, CHANNEL_OPEN_FAILURE, :long, 14, :long, 3, :string, "unknown channel type auth-agent", :string, "").to_s, socket.write_buffer
+ end
+
+ def test_channel_open_packet_with_corresponding_handler_should_result_in_channel_open_failure_when_handler_returns_an_error
+ transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20000, :long, 0x10000)
+ session.on_open_channel "auth-agent" do |s, ch, p|
+ raise Net::SSH::ChannelOpenFailed.new(1234, "we iz in ur channelz!")
+ end
+ process_times(2)
+ assert_equal P(:byte, CHANNEL_OPEN_FAILURE, :long, 14, :long, 1234, :string, "we iz in ur channelz!", :string, "").to_s, socket.write_buffer
+ end
+
+ def test_channel_open_packet_with_corresponding_handler_should_result_in_channel_open_confirmation_when_handler_succeeds
+ transport.return(CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20001, :long, 0x10001)
+ result = nil
+ session.on_open_channel("auth-agent") { |*args| result = args }
+ process_times(2)
+ assert_equal P(:byte, CHANNEL_OPEN_CONFIRMATION, :long, 14, :long, 0, :long, 0x20000, :long, 0x10000).to_s, socket.write_buffer
+ assert_not_nil(ch = session.channels[0])
+ assert_equal [session, ch, P(:byte, CHANNEL_OPEN, :string, "auth-agent", :long, 14, :long, 0x20001, :long, 0x10001)], result
+ assert_equal 0, ch.local_id
+ assert_equal 14, ch.remote_id
+ assert_equal 0x20001, ch.remote_maximum_window_size
+ assert_equal 0x10001, ch.remote_maximum_packet_size
+ assert_equal 0x20000, ch.local_maximum_window_size
+ assert_equal 0x10000, ch.local_maximum_packet_size
+ assert_equal "auth-agent", ch.type
+ end
+
+ def test_channel_open_confirmation_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_open_confirmation).with(1234, 0x20001, 0x10001)
+ transport.return(CHANNEL_OPEN_CONFIRMATION, :long, 14, :long, 1234, :long, 0x20001, :long, 0x10001)
+ process_times(2)
+ end
+
+ def test_channel_window_adjust_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_window_adjust).with(5000)
+ transport.return(CHANNEL_WINDOW_ADJUST, :long, 14, :long, 5000)
+ process_times(2)
+ end
+
+ def test_channel_request_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_request).with("testing", false, Net::SSH::Buffer.new)
+ transport.return(CHANNEL_REQUEST, :long, 14, :string, "testing", :bool, false)
+ process_times(2)
+ end
+
+ def test_channel_data_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_data).with("bring it on down")
+ transport.return(CHANNEL_DATA, :long, 14, :string, "bring it on down")
+ process_times(2)
+ end
+
+ def test_channel_extended_data_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_extended_data).with(1, "bring it on down")
+ transport.return(CHANNEL_EXTENDED_DATA, :long, 14, :long, 1, :string, "bring it on down")
+ process_times(2)
+ end
+
+ def test_channel_eof_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_eof).with()
+ transport.return(CHANNEL_EOF, :long, 14)
+ process_times(2)
+ end
+
+ def test_channel_success_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_success).with()
+ transport.return(CHANNEL_SUCCESS, :long, 14)
+ process_times(2)
+ end
+
+ def test_channel_failure_packet_should_be_routed_to_corresponding_channel
+ channel_at(14).expects(:do_failure).with()
+ transport.return(CHANNEL_FAILURE, :long, 14)
+ process_times(2)
+ 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()
+ transport.return(CHANNEL_CLOSE, :long, 14)
+ process_times(2)
+ assert session.channels.empty?
+ end
+
+ def test_multiple_pending_dispatches_should_be_dispatched_together
+ channel_at(14).expects(:do_eof).with()
+ session.channels[14].expects(:do_success).with()
+ transport.return(CHANNEL_SUCCESS, :long, 14)
+ transport.return(CHANNEL_EOF, :long, 14)
+ process_times(2)
+ end
+
+ def test_writers_without_pending_writes_should_not_be_considered_for_select
+ IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ session.process
+ end
+
+ def test_writers_with_pending_writes_should_be_considered_for_select
+ socket.enqueue("laksdjflasdkf")
+ IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[],[]])
+ session.process
+ end
+
+ def test_ready_readers_should_be_filled
+ socket.expects(:recv).returns("this is some data")
+ IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
+ session.process
+ assert_equal [socket], session.readers
+ end
+
+ def test_ready_readers_that_cant_be_filled_should_be_removed
+ socket.expects(:recv).returns("")
+ socket.expects(:close)
+ IO.expects(:select).with([socket],[],nil,nil).returns([[socket],[],[]])
+ session.process
+ assert_equal [], session.readers
+ assert_equal [], session.writers
+ end
+
+ def test_ready_readers_that_are_registered_with_a_block_should_call_block_instead_of_fill
+ io = stub("io")
+ flag = false
+ session.listen_to(io) { flag = true }
+ IO.expects(:select).with([socket,io],[],nil,nil).returns([[io],[],[]])
+ session.process
+ assert flag, "callback should have been invoked"
+ end
+
+ def test_ready_writers_should_call_send_pending
+ socket.enqueue("laksdjflasdkf")
+ socket.expects(:send).with("laksdjflasdkf", 0).returns(13)
+ IO.expects(:select).with([socket],[socket],nil,nil).returns([[],[socket],[]])
+ session.process
+ end
+
+ def test_process_should_call_rekey_as_needed
+ transport.expects(:rekey_as_needed)
+ IO.expects(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ session.process
+ end
+
+ def test_loop_should_call_process_until_process_returns_false
+ IO.stubs(:select).with([socket],[],nil,nil).returns([[],[],[]])
+ session.expects(:process).with(nil).times(4).returns(true,true,true,false).yields
+ n = 0
+ session.loop { n += 1 }
+ assert_equal 4, n
+ end
+
+ private
+
+ module MockSocket
+ # so that we can easily test the contents that were enqueued, without
+ # worrying about all the packet stream overhead
+ def enqueue_packet(message)
+ enqueue(message.to_s)
+ end
+ end
+
+ def socket
+ @socket ||= begin
+ socket ||= Object.new
+ socket.extend(Net::SSH::Transport::PacketStream)
+ socket.extend(MockSocket)
+ socket
+ end
+ end
+
+ def channel_at(local_id)
+ session.channels[local_id] = stub("channel", :process => true, :closing? => false)
+ end
+
+ def transport(options={})
+ @transport ||= MockTransport.new(options.merge(:socket => socket))
+ end
+
+ def session(options={})
+ @session ||= Net::SSH::Connection::Session.new(transport, options)
+ end
+
+ def process_times(n)
+ i = 0
+ session.process { (i += 1) < n }
+ end
+ end
+
+end \ No newline at end of file