#!/usr/bin/ruby $:.unshift "#{File.dirname(__FILE__)}/../../lib" require 'test/unit' require 'xmpp4r' # Jabber::debug = true # Jabber::warnings = true class ClientDisconnectCleanupTest < Test::Unit::TestCase class ControledClient < Jabber::Client attr_accessor :tcpserver, :socket_override def connect begin @port = 1024 + rand(32768 - 1024) @tcpserver = TCPServer.new("127.0.0.1", @port) rescue Errno::EADDRINUSE, Errno::EACCES @tcpserver.close rescue nil retry end super("127.0.0.1", @port) end def start @socket = socket_override super end end def test_regular_stream_end rd, wr = IO.pipe rd.instance_eval do def write(*args) end def flush end end client = ControledClient.new("test@localhost") @exceptions_caught = 0 client.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do client.socket_override = rd client.instance_eval{ @keepalive_interval = 0.1 } client.connect client.auth_nonsasl("password", false) end sleep(0.1) assert client.is_connected? wr.write('') wr.write("") sleep(0.2) assert !client.is_connected? assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? } assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? } assert @exceptions_caught > 0 end def test_error_on_send rd, wr = IO.pipe rd.instance_eval do def write(*args) end def flush end end client = ControledClient.new("test@localhost") @exceptions_caught = 0 client.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do client.socket_override = rd client.connect client.auth_nonsasl("password", false) end sleep(0.1) assert client.is_connected? rd.instance_eval do def write(*args) raise "No writting for you, you disconnect now" end end wr.write(%Q{ }) sleep(0.1) assert !client.is_connected? assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? } assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? } assert @exceptions_caught > 0 end def test_client_disconnect rd, wr = IO.pipe rd.instance_eval do def write(*args) end def flush end end client = ControledClient.new("test@localhost") @exceptions_caught = 0 client.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do client.socket_override = rd client.connect client.auth_nonsasl("password", false) end wr.write(%Q{ }) sleep(0.1) assert client.is_connected? assert client.instance_eval{ @parser_thread.alive? } assert client.instance_eval{ @keepaliveThread.alive? } wr.close sleep(0.1) assert !client.is_connected? assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? } assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? } assert @exceptions_caught > 0 end end class ConnectionDisconnectCleanupTest < Test::Unit::TestCase class PipeConnection < Jabber::Connection attr_accessor :socket_override def connect begin @port = 1024 + rand(32768 - 1024) tcpsocket = TCPServer.new("127.0.0.1", @port) rescue Errno::EADDRINUSE, Errno::EACCES tcpsocket.close rescue nil retry end super("127.0.0.1", @port) end def accept_features #do nothing end def start @socket = self.socket_override super end end def test_cleanup_when_disconnected_during_keepalive rd, wr = IO.pipe conn = PipeConnection.new @exceptions_caught = 0 conn.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do conn.socket_override = rd #this will raise exception in keepalive thread, when attempts to send blank space shortly after connect conn.instance_eval{ @keepalive_interval = 0.1 } conn.connect end sleep(0.2) assert rd.closed? assert !conn.is_connected? assert !conn.instance_eval{ @parser_thread }.alive? assert !conn.instance_eval{ @keepaliveThread }.alive? assert @exceptions_caught > 0 end def test_cleanup_after_stream_close rd, wr = IO.pipe conn = PipeConnection.new @exceptions_caught = 0 conn.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do conn.socket_override = rd conn.connect end wr.write("") wr.close sleep(0.1) assert rd.closed? assert !conn.is_connected? assert !conn.instance_eval{ @parser_thread }.alive? assert !conn.instance_eval{ @keepaliveThread }.alive? assert @exceptions_caught > 0 end def test_cleanup_after_stream_end rd, wr = IO.pipe conn = PipeConnection.new @exceptions_caught = 0 conn.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end Thread.new do conn.socket_override = rd conn.connect end wr.write('') wr.write("") # wr.close sleep(0.1) assert rd.closed? assert !conn.is_connected? assert !conn.instance_eval{ @parser_thread }.alive? assert !conn.instance_eval{ @keepaliveThread }.alive? assert @exceptions_caught > 0 end end class StreamDisconnectCleanupTest < Test::Unit::TestCase def test_cleanup_when_errors_on_send rd, wr = IO.pipe stream = Jabber::Stream.new @exceptions_caught = 0 stream.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end assert !stream.is_connected? stream.start(rd) wr.write("") assert stream.is_connected? #should raise error trying to write to stream that can't be written to, and catch should close it. begin stream.send("") rescue end sleep(0.1) assert rd.closed? assert !stream.is_connected? assert !stream.instance_eval{ @parser_thread }.alive? assert @exceptions_caught > 0 end def test_cleanup_after_stream_close rd, wr = IO.pipe stream = Jabber::Stream.new @exceptions_caught = 0 stream.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end assert !stream.is_connected? stream.start(rd) wr.write("") assert stream.is_connected? wr.close sleep(0.1) assert rd.closed? assert !stream.is_connected? assert !stream.instance_eval{ @parser_thread }.alive? assert @exceptions_caught > 0 end def test_cleanup_after_stream_end rd, wr = IO.pipe stream = Jabber::Stream.new @exceptions_caught = 0 stream.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end assert !stream.is_connected? stream.start(rd) wr.write('') wr.write("") assert stream.is_connected? # wr.close sleep(0.1) assert rd.closed? assert !stream.is_connected? assert !stream.instance_eval{ @parser_thread }.alive? assert @exceptions_caught > 0 end def test_cleanup_after_parse_failure rd, wr = IO.pipe stream = Jabber::Stream.new @exceptions_caught = 0 stream.on_exception do |e, connection, where_failed| @exceptions_caught += 1 end assert !stream.is_connected? stream.start(rd) wr.write('>') wr.close assert stream.is_connected? sleep(0.1) assert rd.closed? assert !stream.is_connected? assert !stream.instance_eval{ @parser_thread }.alive? assert @exceptions_caught > 0 end end