From 8c9fc735503ca383768f8b1eaaf0fe4175b1bd01 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 12 Jul 2011 03:15:30 +0200 Subject: [PATCH] Implement rest of connection tests --- mopidy/utils/network.py | 16 +-- tests/utils/network_test.py | 201 +++++++++++++++++++++++++++++++----- 2 files changed, 183 insertions(+), 34 deletions(-) diff --git a/mopidy/utils/network.py b/mopidy/utils/network.py index 7767377b..27eb3ed8 100644 --- a/mopidy/utils/network.py +++ b/mopidy/utils/network.py @@ -143,7 +143,6 @@ class Connection(object): self.sock.close() except socket.error: pass - return False def send(self, data): """Send data to client exactly as is.""" @@ -189,17 +188,20 @@ class Connection(object): def recv_callback(self, fd, flags): if flags & (gobject.IO_ERR | gobject.IO_HUP): - return self.stop() + self.stop() + return False try: data = self.sock.recv(4096) except socket.error as e: - if e.errno in (errno.EWOULDBLOCK, errno.EAGAIN): + if e.errno in (errno.EWOULDBLOCK, errno.EINTR): return True - return self.stop() + self.stop() + return False if not data: - return self.stop() + self.stop() + return False self.actor_ref.send_one_way({'received': data}) return True @@ -216,9 +218,9 @@ class Connection(object): if not self.send_buffer: self.disable_send() except socket.error as e: - if e.errno not in (errno.EAGAIN, errno.EWOULDBLOCK): + if e.errno not in (errno.EWOULDBLOCK, errno.EINTR): #self.log_error(e) # FIXME log error - return self.stop() + self.stop() finally: self.send_lock.release() diff --git a/tests/utils/network_test.py b/tests/utils/network_test.py index 23ed0247..8fd345c6 100644 --- a/tests/utils/network_test.py +++ b/tests/utils/network_test.py @@ -18,7 +18,7 @@ class FormatHostnameTest(unittest.TestCase): @patch('mopidy.utils.network.has_ipv6', False) def test_format_hostname_does_nothing_when_only_ipv4_available(self): network.has_ipv6 = False - self.assertEquals(network.format_hostname('0.0.0.0'), '0.0.0.0') + self.assertEqual(network.format_hostname('0.0.0.0'), '0.0.0.0') class TryIPv6SocketTest(unittest.TestCase): @@ -119,7 +119,7 @@ class ServerTest(unittest.TestCase): self.mock.accept_connection.assert_called_once_with() self.mock.maximum_connections_exceeded.assert_called_once_with() self.mock.init_connection.assert_called_once_with(sentinel.sock, sentinel.addr) - self.assertEquals(0, self.mock.reject_connection.call_count) + self.assertEqual(0, self.mock.reject_connection.call_count) def test_handle_connection_exceeded_connections(self): self.mock.accept_connection.return_value = (sentinel.sock, sentinel.addr) @@ -129,7 +129,7 @@ class ServerTest(unittest.TestCase): self.mock.accept_connection.assert_called_once_with() self.mock.maximum_connections_exceeded.assert_called_once_with() self.mock.reject_connection.assert_called_once_with(sentinel.sock, sentinel.addr) - self.assertEquals(0, self.mock.init_connection.call_count) + self.assertEqual(0, self.mock.init_connection.call_count) def test_accept_connection(self): sock = Mock(spec=socket.SocketType) @@ -137,20 +137,17 @@ class ServerTest(unittest.TestCase): self.mock.server_socket = sock sock, addr = network.Server.accept_connection(self.mock) - self.assertEquals(sentinel.sock, sock) - self.assertEquals(sentinel.addr, addr) + self.assertEqual(sentinel.sock, sock) + self.assertEqual(sentinel.addr, addr) def test_accept_connection_recoverable_error(self): sock = Mock(spec=socket.SocketType) self.mock.server_socket = sock - sock.accept.side_effect = socket.error(errno.EAGAIN, '') - self.assertRaises(network.ShouldRetrySocketCall, - network.Server.accept_connection, self.mock) - - sock.accept.side_effect = socket.error(errno.EINTR, '') - self.assertRaises(network.ShouldRetrySocketCall, - network.Server.accept_connection, self.mock) + for error in (errno.EAGAIN, errno.EINTR): + sock.accept.side_effect = socket.error(error, '') + self.assertRaises(network.ShouldRetrySocketCall, + network.Server.accept_connection, self.mock) def test_accept_connection_unrecoverable_error(self): sock = Mock(spec=socket.SocketType) @@ -244,32 +241,40 @@ class ConnectionTest(unittest.TestCase): self.assertEqual(sentinel.port, self.mock.port) def test_stop_disables_recv_send_and_timeout(self): + self.mock.actor_ref = Mock() + self.mock.sock = Mock(spec=socket.SocketType) + network.Connection.stop(self.mock) self.mock.disable_timeout.assert_called_once_with() self.mock.disable_recv.assert_called_once_with() self.mock.disable_timeout.assert_called_once_with() def test_stop_closes_socket(self): - sock = Mock(spec=socket.SocketType) - self.mock.sock = sock + self.mock.actor_ref = Mock() + self.mock.sock = Mock(spec=socket.SocketType) network.Connection.stop(self.mock) - sock.close.assert_called_once_with() + self.mock.sock.close.assert_called_once_with() def test_stop_closes_socket_error(self): - sock = Mock(spec=socket.SocketType) - sock.close.side_effect = socket.error() - self.mock.sock = sock + self.mock.actor_ref = Mock() + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.close.side_effect = socket.error() network.Connection.stop(self.mock) - sock.close.assert_called_once_with() + self.mock.sock.close.assert_called_once_with() - def test_stop_return_false(self): - self.assertFalse(network.Connection.stop(self.mock)) + def test_stop_stops_actor(self): + self.mock.actor_ref = Mock() + self.mock.sock = Mock(spec=socket.SocketType) + + network.Connection.stop(self.mock) + self.mock.actor_ref.stop.assert_called_once_with() @patch.object(gobject, 'io_add_watch', new=Mock()) def test_enable_recv_registers_with_gobject(self): self.mock.recv_id = None + self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock.fileno.return_value = sentinel.fileno gobject.io_add_watch.return_value = sentinel.tag @@ -305,6 +310,7 @@ class ConnectionTest(unittest.TestCase): @patch.object(gobject, 'io_add_watch', new=Mock()) def test_enable_send_registers_with_gobject(self): self.mock.send_id = None + self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock.fileno.return_value = sentinel.fileno gobject.io_add_watch.return_value = sentinel.tag @@ -384,14 +390,155 @@ class ConnectionTest(unittest.TestCase): self.assertEqual(0, gobject.source_remove.call_count) self.assertEqual(None, self.mock.timeout_id) - @SkipTest - def test_recv_callback(self): - pass + def test_send_acquires_and_releases_lock(self): + self.mock.send_lock = Mock() + self.mock.send_buffer = '' + + network.Connection.send(self.mock, 'data') + self.mock.send_lock.acquire.assert_called_once_with(True) + self.mock.send_lock.release.assert_called_once_with() + + def test_send_appends_to_send_buffer(self): + self.mock.send_lock = Mock() + self.mock.send_buffer = '' + + network.Connection.send(self.mock, 'abc') + self.assertEqual('abc', self.mock.send_buffer) + + network.Connection.send(self.mock, 'def') + self.assertEqual('abcdef', self.mock.send_buffer) + + network.Connection.send(self.mock, '') + self.assertEqual('abcdef', self.mock.send_buffer) + + def test_send_calls_enable_send(self): + self.mock.send_lock = Mock() + self.mock.send_buffer = '' + + network.Connection.send(self.mock, 'data') + self.mock.enable_send.assert_called_once_with() + + def test_recv_callback_respects_io_err(self): + self.assertFalse(network.Connection.recv_callback(self.mock, + sentinel.fd, gobject.IO_IN | gobject.IO_ERR)) + self.mock.stop.assert_called_once_with() + + def test_recv_callback_respects_io_hup(self): + self.assertFalse(network.Connection.recv_callback(self.mock, + sentinel.fd, gobject.IO_IN | gobject.IO_HUP)) + self.mock.stop.assert_called_once_with() + + def test_recv_callback_respects_io_hup_and_io_err(self): + self.assertFalse(network.Connection.recv_callback(self.mock, + sentinel.fd, gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR)) + self.mock.stop.assert_called_once_with() + + def test_recv_callback_gets_data(self): + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.recv.return_value = 'data' + self.mock.actor_ref = Mock() + + self.assertTrue(network.Connection.recv_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.actor_ref.send_one_way.assert_called_once_with( + {'received': 'data'}) + + def test_recv_callback_gets_no_data(self): + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.recv.return_value = '' + + self.assertFalse(network.Connection.recv_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.stop.assert_called_once_with() + + def test_recv_callback_recoverable_error(self): + self.mock.sock = Mock(spec=socket.SocketType) + + for error in (errno.EWOULDBLOCK, errno.EINTR): + self.mock.sock.recv.side_effect = socket.error(error, '') + self.assertTrue(network.Connection.recv_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + + def test_recv_callback_unrecoverable_error(self): + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.recv.side_effect = socket.error() + + self.assertFalse(network.Connection.recv_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.stop.assert_called_once_with() @SkipTest - def test_send_callback(self): + def test_send_callback_respects_flags(self): + # stop self pass - @SkipTest + def test_send_callback_acquires_and_releases_lock(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = True + self.mock.send_buffer = '' + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.send.return_value = 0 + + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.send_lock.acquire.assert_called_once_with(False) + self.mock.send_lock.release.assert_called_once_with() + + def test_send_callback_fails_to_acquire_lock(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = False + + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.send_lock.acquire.assert_called_once_with(False) + + def test_send_callback_sends_all_data(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = True + self.mock.send_buffer = 'data' + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.send.return_value = 4 + + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.disable_send.assert_called_once_with() + self.mock.sock.send.assert_called_once_with('data') + self.assertEqual('', self.mock.send_buffer) + + def test_send_callback_sends_partial_data(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = True + self.mock.send_buffer = 'data' + self.mock.sock = Mock(spec=socket.SocketType) + self.mock.sock.send.return_value = 2 + + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.sock.send.assert_called_once_with('data') + self.assertEqual('ta', self.mock.send_buffer) + + def test_send_callback_recoverable_error(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = True + self.mock.send_buffer = 'data' + self.mock.sock = Mock(spec=socket.SocketType) + + for error in (errno.EWOULDBLOCK, errno.EINTR): + self.mock.sock.send.side_effect = socket.error(error, '') + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + + def test_send_callback_unrecoverable_error(self): + self.mock.send_lock = Mock() + self.mock.send_lock.acquire.return_value = True + self.mock.send_buffer = 'data' + self.mock.sock = Mock(spec=socket.SocketType) + + self.mock.sock.send.side_effect = socket.error() + self.assertTrue(network.Connection.send_callback( + self.mock, sentinel.fd, gobject.IO_IN)) + self.mock.stop.assert_called_once_with() + def test_timeout_callback(self): - pass + network.Connection.timeout_callback(self.mock) + self.mock.stop.assert_called_once_with()