import sys import time import unittest import six if six.PY3: from unittest import mock else: import mock try: import websockets except ImportError: # weirdness to avoid errors in PY2 test run class _dummy(): pass websockets = _dummy() websockets.exceptions = _dummy() websockets.exceptions.InvalidURI = _dummy() from engineio import client from engineio import exceptions from engineio import packet from engineio import payload if sys.version_info >= (3, 5): import asyncio from asyncio import coroutine from engineio import asyncio_client else: # mock coroutine so that Python 2 doesn't complain def coroutine(f): return f def AsyncMock(*args, **kwargs): """Return a mock asynchronous function.""" m = mock.MagicMock(*args, **kwargs) @coroutine def mock_coro(*args, **kwargs): return m(*args, **kwargs) mock_coro.mock = m return mock_coro def _run(coro): """Run the given coroutine.""" return asyncio.get_event_loop().run_until_complete(coro) @unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') class TestAsyncClient(unittest.TestCase): def test_is_asyncio_based(self): c = asyncio_client.AsyncClient() self.assertEqual(c.is_asyncio_based(), True) def test_already_connected(self): c = asyncio_client.AsyncClient() c.state = 'connected' self.assertRaises(ValueError, _run, c.connect('http://foo')) def test_invalid_transports(self): c = asyncio_client.AsyncClient() self.assertRaises(ValueError, _run, c.connect( 'http://foo', transports=['foo', 'bar'])) def test_some_invalid_transports(self): c = asyncio_client.AsyncClient() c._connect_websocket = AsyncMock() _run(c.connect('http://foo', transports=['foo', 'websocket', 'bar'])) self.assertEqual(c.transports, ['websocket']) def test_connect_polling(self): c = asyncio_client.AsyncClient() c._connect_polling = AsyncMock(return_value='foo') self.assertEqual(_run(c.connect('http://foo')), 'foo') c._connect_polling.mock.assert_called_once_with( 'http://foo', {}, 'engine.io') c = asyncio_client.AsyncClient() c._connect_polling = AsyncMock(return_value='foo') self.assertEqual( _run(c.connect('http://foo', transports=['polling'])), 'foo') c._connect_polling.mock.assert_called_once_with( 'http://foo', {}, 'engine.io') c = asyncio_client.AsyncClient() c._connect_polling = AsyncMock(return_value='foo') self.assertEqual( _run(c.connect('http://foo', transports=['polling', 'websocket'])), 'foo') c._connect_polling.mock.assert_called_once_with( 'http://foo', {}, 'engine.io') def test_connect_websocket(self): c = asyncio_client.AsyncClient() c._connect_websocket = AsyncMock(return_value='foo') self.assertEqual( _run(c.connect('http://foo', transports=['websocket'])), 'foo') c._connect_websocket.mock.assert_called_once_with( 'http://foo', {}, 'engine.io') c = asyncio_client.AsyncClient() c._connect_websocket = AsyncMock(return_value='foo') self.assertEqual( _run(c.connect('http://foo', transports='websocket')), 'foo') c._connect_websocket.mock.assert_called_once_with( 'http://foo', {}, 'engine.io') def test_connect_query_string(self): c = asyncio_client.AsyncClient() c._connect_polling = AsyncMock(return_value='foo') self.assertEqual(_run(c.connect('http://foo?bar=baz')), 'foo') c._connect_polling.mock.assert_called_once_with( 'http://foo?bar=baz', {}, 'engine.io') def test_connect_custom_headers(self): c = asyncio_client.AsyncClient() c._connect_polling = AsyncMock(return_value='foo') self.assertEqual( _run(c.connect('http://foo', headers={'Foo': 'Bar'})), 'foo') c._connect_polling.mock.assert_called_once_with( 'http://foo', {'Foo': 'Bar'}, 'engine.io') def test_wait(self): c = asyncio_client.AsyncClient() done = [] @coroutine def fake_read_look_task(): done.append(True) c.read_loop_task = fake_read_look_task() _run(c.wait()) self.assertEqual(done, [True]) def test_wait_no_task(self): c = asyncio_client.AsyncClient() c.read_loop_task = None _run(c.wait()) def test_send(self): c = asyncio_client.AsyncClient() saved_packets = [] @coroutine def fake_send_packet(pkt): saved_packets.append(pkt) c._send_packet = fake_send_packet _run(c.send('foo')) _run(c.send('foo', binary=False)) _run(c.send(b'foo', binary=True)) self.assertEqual(saved_packets[0].packet_type, packet.MESSAGE) self.assertEqual(saved_packets[0].data, 'foo') self.assertEqual(saved_packets[0].binary, False if six.PY3 else True) self.assertEqual(saved_packets[1].packet_type, packet.MESSAGE) self.assertEqual(saved_packets[1].data, 'foo') self.assertEqual(saved_packets[1].binary, False) self.assertEqual(saved_packets[2].packet_type, packet.MESSAGE) self.assertEqual(saved_packets[2].data, b'foo') self.assertEqual(saved_packets[2].binary, True) def test_disconnect_not_connected(self): c = asyncio_client.AsyncClient() c.state = 'foo' _run(c.disconnect()) self.assertEqual(c.state, 'disconnected') def test_disconnect_polling(self): c = asyncio_client.AsyncClient() client.connected_clients.append(c) c.state = 'connected' c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.queue.join = AsyncMock() c.read_loop_task = AsyncMock()() c.ws = mock.MagicMock() c.ws.close = AsyncMock() c._trigger_event = AsyncMock() _run(c.disconnect()) c.ws.close.mock.assert_not_called() self.assertNotIn(c, client.connected_clients) c._trigger_event.mock.assert_called_once_with('disconnect') def test_disconnect_websocket(self): c = asyncio_client.AsyncClient() client.connected_clients.append(c) c.state = 'connected' c.current_transport = 'websocket' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.queue.join = AsyncMock() c.read_loop_task = AsyncMock()() c.ws = mock.MagicMock() c.ws.close = AsyncMock() c._trigger_event = AsyncMock() _run(c.disconnect()) c.ws.close.mock.assert_called_once_with() self.assertNotIn(c, client.connected_clients) c._trigger_event.mock.assert_called_once_with('disconnect') def test_disconnect_polling_abort(self): c = asyncio_client.AsyncClient() client.connected_clients.append(c) c.state = 'connected' c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.queue.join = AsyncMock() c.read_loop_task = AsyncMock()() c.ws = mock.MagicMock() c.ws.close = AsyncMock() _run(c.disconnect(abort=True)) c.queue.join.mock.assert_not_called() c.ws.close.mock.assert_not_called() self.assertNotIn(c, client.connected_clients) def test_disconnect_websocket_abort(self): c = asyncio_client.AsyncClient() client.connected_clients.append(c) c.state = 'connected' c.current_transport = 'websocket' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.queue.join = AsyncMock() c.read_loop_task = AsyncMock()() c.ws = mock.MagicMock() c.ws.close = AsyncMock() _run(c.disconnect(abort=True)) c.queue.join.mock.assert_not_called() c.ws.mock.assert_not_called() self.assertNotIn(c, client.connected_clients) def test_background_tasks(self): r = [] @coroutine def foo(arg): r.append(arg) c = asyncio_client.AsyncClient() c.start_background_task(foo, 'bar') pending = asyncio.Task.all_tasks() asyncio.get_event_loop().run_until_complete(asyncio.wait(pending)) self.assertEqual(r, ['bar']) def test_sleep(self): c = asyncio_client.AsyncClient() _run(c.sleep(0)) @mock.patch('engineio.client.time.time', return_value=123.456) def test_polling_connection_failed(self, _time): c = asyncio_client.AsyncClient() c._send_request = AsyncMock(return_value=None) self.assertRaises( exceptions.ConnectionError, _run, c.connect( 'http://foo', headers={'Foo': 'Bar'})) c._send_request.mock.assert_called_once_with( 'GET', 'http://foo/engine.io/?transport=polling&EIO=3&t=123.456', headers={'Foo': 'Bar'}) def test_polling_connection_404(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 404 self.assertRaises( exceptions.ConnectionError, _run, c.connect('http://foo')) def test_polling_connection_invalid_packet(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=b'foo') self.assertRaises( exceptions.ConnectionError, _run, c.connect('http://foo')) def test_polling_connection_no_open_packet(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.CLOSE, { 'sid': '123', 'upgrades': [], 'pingInterval': 10, 'pingTimeout': 20 }) ]).encode()) self.assertRaises( exceptions.ConnectionError, _run, c.connect('http://foo')) def test_polling_connection_successful(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.OPEN, { 'sid': '123', 'upgrades': [], 'pingInterval': 1000, 'pingTimeout': 2000 }) ]).encode()) c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() on_connect = AsyncMock() c.on('connect', on_connect) _run(c.connect('http://foo')) time.sleep(0.1) c._ping_loop.mock.assert_called_once_with() c._read_loop_polling.mock.assert_called_once_with() c._read_loop_websocket.mock.assert_not_called() c._write_loop.mock.assert_called_once_with() on_connect.mock.assert_called_once_with() self.assertIn(c, client.connected_clients) self.assertEqual( c.base_url, 'http://foo/engine.io/?transport=polling&EIO=3&sid=123') self.assertEqual(c.sid, '123') self.assertEqual(c.ping_interval, 1) self.assertEqual(c.ping_timeout, 2) self.assertEqual(c.upgrades, []) self.assertEqual(c.transport(), 'polling') def test_polling_connection_with_more_packets(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.OPEN, { 'sid': '123', 'upgrades': [], 'pingInterval': 1000, 'pingTimeout': 2000 }), packet.Packet(packet.NOOP) ]).encode()) c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() c._receive_packet = AsyncMock() on_connect = AsyncMock() c.on('connect', on_connect) _run(c.connect('http://foo')) time.sleep(0.1) self.assertEqual(c._receive_packet.mock.call_count, 1) self.assertEqual( c._receive_packet.mock.call_args_list[0][0][0].packet_type, packet.NOOP) def test_polling_connection_upgraded(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.OPEN, { 'sid': '123', 'upgrades': ['websocket'], 'pingInterval': 1000, 'pingTimeout': 2000 }) ]).encode()) c._connect_websocket = AsyncMock(return_value=True) on_connect = mock.MagicMock() c.on('connect', on_connect) _run(c.connect('http://foo')) c._connect_websocket.mock.assert_called_once_with('http://foo', {}, 'engine.io') on_connect.assert_called_once_with() self.assertIn(c, client.connected_clients) self.assertEqual( c.base_url, 'http://foo/engine.io/?transport=polling&EIO=3&sid=123') self.assertEqual(c.sid, '123') self.assertEqual(c.ping_interval, 1) self.assertEqual(c.ping_timeout, 2) self.assertEqual(c.upgrades, ['websocket']) def test_polling_connection_not_upgraded(self): c = asyncio_client.AsyncClient() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.OPEN, { 'sid': '123', 'upgrades': ['websocket'], 'pingInterval': 1000, 'pingTimeout': 2000 }) ]).encode()) c._connect_websocket = AsyncMock(return_value=False) c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() on_connect = mock.MagicMock() c.on('connect', on_connect) _run(c.connect('http://foo')) time.sleep(0.1) c._connect_websocket.mock.assert_called_once_with('http://foo', {}, 'engine.io') c._ping_loop.mock.assert_called_once_with() c._read_loop_polling.mock.assert_called_once_with() c._read_loop_websocket.mock.assert_not_called() c._write_loop.mock.assert_called_once_with() on_connect.assert_called_once_with() self.assertIn(c, client.connected_clients) @mock.patch('engineio.client.time.time', return_value=123.456) @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock( side_effect=[websockets.exceptions.InvalidURI])) def test_websocket_connection_failed(self, _time): c = asyncio_client.AsyncClient() self.assertRaises( exceptions.ConnectionError, _run, c.connect('http://foo', transports=['websocket'], headers={'Foo': 'Bar'})) asyncio_client.websockets.connect.mock.assert_called_once_with( 'ws://foo/engine.io/?transport=websocket&EIO=3&t=123.456', extra_headers={'Foo': 'Bar'}) @mock.patch('engineio.client.time.time', return_value=123.456) @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock( side_effect=[websockets.exceptions.InvalidURI])) def test_websocket_upgrade_failed(self, _time): c = asyncio_client.AsyncClient() c.sid = '123' self.assertFalse(_run(c.connect( 'http://foo', transports=['websocket']))) asyncio_client.websockets.connect.mock.assert_called_once_with( 'ws://foo/engine.io/?transport=websocket&EIO=3&sid=123&t=123.456', extra_headers={}) @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock()) def test_websocket_connection_no_open_packet(self): asyncio_client.websockets.connect.mock.return_value.recv = AsyncMock( return_value=packet.Packet(packet.CLOSE).encode()) c = asyncio_client.AsyncClient() self.assertRaises( exceptions.ConnectionError, _run, c.connect('http://foo', transports=['websocket'])) @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock()) def test_websocket_connection_successful(self): ws = asyncio_client.websockets.connect.mock.return_value ws.recv = AsyncMock(return_value=packet.Packet( packet.OPEN, { 'sid': '123', 'upgrades': [], 'pingInterval': 1000, 'pingTimeout': 2000 }).encode()) c = asyncio_client.AsyncClient() c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() on_connect = mock.MagicMock() c.on('connect', on_connect) _run(c.connect('ws://foo', transports=['websocket'])) time.sleep(0.1) c._ping_loop.mock.assert_called_once_with() c._read_loop_polling.mock.assert_not_called() c._read_loop_websocket.mock.assert_called_once_with() c._write_loop.mock.assert_called_once_with() on_connect.assert_called_once_with() self.assertIn(c, client.connected_clients) self.assertEqual( c.base_url, 'ws://foo/engine.io/?transport=websocket&EIO=3') self.assertEqual(c.sid, '123') self.assertEqual(c.ping_interval, 1) self.assertEqual(c.ping_timeout, 2) self.assertEqual(c.upgrades, []) self.assertEqual(c.transport(), 'websocket') self.assertEqual(c.ws, ws) @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock()) def test_websocket_upgrade_no_pong(self): ws = asyncio_client.websockets.connect.mock.return_value ws.recv = AsyncMock(return_value=packet.Packet( packet.OPEN, { 'sid': '123', 'upgrades': [], 'pingInterval': 1000, 'pingTimeout': 2000 }).encode()) ws.send = AsyncMock() c = asyncio_client.AsyncClient() c.sid = '123' c.current_transport = 'polling' c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() on_connect = mock.MagicMock() c.on('connect', on_connect) self.assertFalse(_run(c.connect('ws://foo', transports=['websocket']))) c._ping_loop.mock.assert_not_called() c._read_loop_polling.mock.assert_not_called() c._read_loop_websocket.mock.assert_not_called() c._write_loop.mock.assert_not_called() on_connect.assert_not_called() self.assertEqual(c.transport(), 'polling') ws.send.mock.assert_called_once_with('2probe') @mock.patch('engineio.asyncio_client.websockets.connect', new=AsyncMock()) def test_websocket_upgrade_successful(self): ws = asyncio_client.websockets.connect.mock.return_value ws.recv = AsyncMock(return_value=packet.Packet( packet.PONG, 'probe').encode()) ws.send = AsyncMock() c = asyncio_client.AsyncClient() c.sid = '123' c.base_url = 'http://foo' c.current_transport = 'polling' c._ping_loop = AsyncMock() c._read_loop_polling = AsyncMock() c._read_loop_websocket = AsyncMock() c._write_loop = AsyncMock() on_connect = mock.MagicMock() c.on('connect', on_connect) self.assertTrue(_run(c.connect('ws://foo', transports=['websocket']))) time.sleep(0.1) c._ping_loop.mock.assert_called_once_with() c._read_loop_polling.mock.assert_not_called() c._read_loop_websocket.mock.assert_called_once_with() c._write_loop.mock.assert_called_once_with() on_connect.assert_not_called() # was called by polling self.assertNotIn(c, client.connected_clients) # was added by polling self.assertEqual(c.base_url, 'http://foo') # not changed self.assertEqual(c.sid, '123') # not changed self.assertEqual(c.transport(), 'websocket') self.assertEqual(c.ws, ws) self.assertEqual( ws.send.mock.call_args_list[0], (('2probe',),)) # ping self.assertEqual( ws.send.mock.call_args_list[1], (('5',),)) # upgrade def test_receive_unknown_packet(self): c = asyncio_client.AsyncClient() _run(c._receive_packet(packet.Packet(encoded_packet=b'9'))) # should be ignored def test_receive_noop_packet(self): c = asyncio_client.AsyncClient() _run(c._receive_packet(packet.Packet(packet.NOOP))) # should be ignored def test_receive_pong_packet(self): c = asyncio_client.AsyncClient() c.pong_received = False _run(c._receive_packet(packet.Packet(packet.PONG))) self.assertTrue(c.pong_received) def test_receive_message_packet(self): c = asyncio_client.AsyncClient() on_message = AsyncMock() c.on('message', on_message) _run(c._receive_packet(packet.Packet(packet.MESSAGE, {'foo': 'bar'}))) on_message.mock.assert_called_once_with({'foo': 'bar'}) def test_send_packet_disconnected(self): c = asyncio_client.AsyncClient() c.queue, c.queue_empty = c._create_queue() c.state = 'disconnected' _run(c._send_packet(packet.Packet(packet.NOOP))) self.assertTrue(c.queue.empty()) def test_send_packet(self): c = asyncio_client.AsyncClient() c.queue, c.queue_empty = c._create_queue() c.state = 'connected' _run(c._send_packet(packet.Packet(packet.NOOP))) self.assertFalse(c.queue.empty()) pkt = _run(c.queue.get()) self.assertEqual(pkt.packet_type, packet.NOOP) def test_trigger_event_function(self): result = [] def foo_handler(arg): result.append('ok') result.append(arg) c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) _run(c._trigger_event('message', 'bar')) self.assertEqual(result, ['ok', 'bar']) def test_trigger_event_coroutine(self): result = [] @coroutine def foo_handler(arg): result.append('ok') result.append(arg) c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) _run(c._trigger_event('message', 'bar')) self.assertEqual(result, ['ok', 'bar']) def test_trigger_event_function_error(self): def connect_handler(arg): return 1 / 0 def foo_handler(arg): return 1 / 0 c = asyncio_client.AsyncClient() c.on('connect', handler=connect_handler) c.on('message', handler=foo_handler) self.assertFalse(_run(c._trigger_event('connect', '123'))) self.assertIsNone(_run(c._trigger_event('message', 'bar'))) def test_trigger_event_coroutine_error(self): @coroutine def connect_handler(arg): return 1 / 0 @coroutine def foo_handler(arg): return 1 / 0 c = asyncio_client.AsyncClient() c.on('connect', handler=connect_handler) c.on('message', handler=foo_handler) self.assertFalse(_run(c._trigger_event('connect', '123'))) self.assertIsNone(_run(c._trigger_event('message', 'bar'))) def test_trigger_event_function_async(self): result = [] def foo_handler(arg): result.append('ok') result.append(arg) c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) fut = _run(c._trigger_event('message', 'bar', run_async=True)) asyncio.get_event_loop().run_until_complete(fut) self.assertEqual(result, ['ok', 'bar']) def test_trigger_event_coroutine_async(self): result = [] @coroutine def foo_handler(arg): result.append('ok') result.append(arg) c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) fut = _run(c._trigger_event('message', 'bar', run_async=True)) asyncio.get_event_loop().run_until_complete(fut) self.assertEqual(result, ['ok', 'bar']) def test_trigger_event_function_async_error(self): result = [] def foo_handler(arg): result.append(arg) return 1 / 0 c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) fut = _run(c._trigger_event('message', 'bar', run_async=True)) self.assertRaises( ZeroDivisionError, asyncio.get_event_loop().run_until_complete, fut) self.assertEqual(result, ['bar']) def test_trigger_event_coroutine_async_error(self): result = [] @coroutine def foo_handler(arg): result.append(arg) return 1 / 0 c = asyncio_client.AsyncClient() c.on('message', handler=foo_handler) fut = _run(c._trigger_event('message', 'bar', run_async=True)) self.assertRaises( ZeroDivisionError, asyncio.get_event_loop().run_until_complete, fut) self.assertEqual(result, ['bar']) def test_trigger_unknown_event(self): c = asyncio_client.AsyncClient() _run(c._trigger_event('connect', run_async=False)) _run(c._trigger_event('message', 123, run_async=True)) # should do nothing def test_ping_loop_disconnected(self): c = asyncio_client.AsyncClient() c.state = 'disconnected' _run(c._ping_loop()) # should not block def test_ping_loop_disconnect(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 10 c._send_packet = AsyncMock() states = [ ('disconnecting', True) ] @coroutine def fake_wait(): c.state, c.pong_received = states.pop(0) c.ping_loop_event.wait = fake_wait _run(c._ping_loop()) self.assertEqual( c._send_packet.mock.call_args_list[0][0][0].encode(), b'2') def test_ping_loop_missing_pong(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 10 c._send_packet = AsyncMock() c.queue = mock.MagicMock() c.queue.put = AsyncMock() states = [ ('connected', False) ] @coroutine def fake_wait(): c.state, c.pong_received = states.pop(0) c.ping_loop_event.wait = fake_wait _run(c._ping_loop()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) def test_ping_loop_missing_pong_websocket(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 10 c._send_packet = AsyncMock() c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.ws = mock.MagicMock() c.ws.close = AsyncMock() states = [ ('connected', False) ] @coroutine def fake_wait(): c.state, c.pong_received = states.pop(0) c.ping_loop_event.wait = fake_wait _run(c._ping_loop()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) c.ws.close.mock.assert_called_once_with() def test_read_loop_polling_disconnected(self): c = asyncio_client.AsyncClient() c.state = 'disconnected' c._trigger_event = AsyncMock() c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_polling()) c._trigger_event.mock.assert_not_called() # should not block @mock.patch('engineio.client.time.time', return_value=123.456) def test_read_loop_polling_no_response(self, _time): c = asyncio_client.AsyncClient() c.state = 'connected' c.base_url = 'http://foo' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c._send_request = AsyncMock(return_value=None) c._trigger_event = AsyncMock() c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_polling()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) c._send_request.mock.assert_called_once_with( 'GET', 'http://foo&t=123.456') c._trigger_event.mock.assert_called_once_with('disconnect') @mock.patch('engineio.client.time.time', return_value=123.456) def test_read_loop_polling_bad_status(self, _time): c = asyncio_client.AsyncClient() c.state = 'connected' c.base_url = 'http://foo' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 400 c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_polling()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) c._send_request.mock.assert_called_once_with( 'GET', 'http://foo&t=123.456') @mock.patch('engineio.client.time.time', return_value=123.456) def test_read_loop_polling_bad_packet(self, _time): c = asyncio_client.AsyncClient() c.state = 'connected' c.base_url = 'http://foo' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 c._send_request.mock.return_value.read = AsyncMock( return_value=b'foo') c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_polling()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) c._send_request.mock.assert_called_once_with( 'GET', 'http://foo&t=123.456') def test_read_loop_polling(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.base_url = 'http://foo' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c._send_request = AsyncMock() c._send_request.mock.side_effect = [ mock.MagicMock(status=200, read=AsyncMock( return_value=payload.Payload(packets=[ packet.Packet(packet.PING), packet.Packet(packet.NOOP)]).encode())), None ] c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() c._receive_packet = AsyncMock() _run(c._read_loop_polling()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) self.assertEqual(c._send_request.mock.call_count, 2) self.assertEqual(c._receive_packet.mock.call_count, 2) self.assertEqual( c._receive_packet.mock.call_args_list[0][0][0].encode(), b'2') self.assertEqual( c._receive_packet.mock.call_args_list[1][0][0].encode(), b'6') def test_read_loop_websocket_disconnected(self): c = asyncio_client.AsyncClient() c.state = 'disconnected' c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_websocket()) # should not block def test_read_loop_websocket_no_response(self): c = asyncio_client.AsyncClient() c.base_url = 'ws://foo' c.state = 'connected' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.ws = mock.MagicMock() c.ws.recv = AsyncMock( side_effect=websockets.exceptions.ConnectionClosed(1, 'foo')) c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_websocket()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) def test_read_loop_websocket_unexpected_error(self): c = asyncio_client.AsyncClient() c.base_url = 'ws://foo' c.state = 'connected' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.ws = mock.MagicMock() c.ws.recv = AsyncMock(side_effect=ValueError) c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() _run(c._read_loop_websocket()) self.assertEqual(c.state, 'disconnected') c.queue.put.mock.assert_called_once_with(None) def test_read_loop_websocket(self): c = asyncio_client.AsyncClient() c.base_url = 'ws://foo' c.state = 'connected' c.queue = mock.MagicMock() c.queue.put = AsyncMock() c.ws = mock.MagicMock() c.ws.recv = AsyncMock(side_effect=[ packet.Packet(packet.PING).encode(), ValueError]) c.write_loop_task = AsyncMock()() c.ping_loop_task = AsyncMock()() c._receive_packet = AsyncMock() _run(c._read_loop_websocket()) self.assertEqual(c.state, 'disconnected') self.assertEqual( c._receive_packet.mock.call_args_list[0][0][0].encode(), b'2') c.queue.put.mock.assert_called_once_with(None) def test_write_loop_disconnected(self): c = asyncio_client.AsyncClient() c.state = 'disconnected' _run(c._write_loop()) # should not block def test_write_loop_no_packets(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.queue = mock.MagicMock() c.queue.get = AsyncMock(return_value=None) _run(c._write_loop()) c.queue.task_done.assert_called_once_with() c.queue.get.mock.assert_called_once_with() def test_write_loop_empty_queue(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=RuntimeError) _run(c._write_loop()) c.queue.get.mock.assert_called_once_with() def test_write_loop_polling_one_packet(self): c = asyncio_client.AsyncClient() c.base_url = 'http://foo' c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=RuntimeError) c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 1) p = payload.Payload( packets=[packet.Packet(packet.MESSAGE, {'foo': 'bar'})]) c._send_request.mock.assert_called_once_with( 'POST', 'http://foo', body=p.encode(), headers={'Content-Type': 'application/octet-stream'}) def test_write_loop_polling_three_packets(self): c = asyncio_client.AsyncClient() c.base_url = 'http://foo' c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ packet.Packet(packet.PING), packet.Packet(packet.NOOP), RuntimeError ]) c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 3) p = payload.Payload(packets=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), packet.Packet(packet.PING), packet.Packet(packet.NOOP), ]) c._send_request.mock.assert_called_once_with( 'POST', 'http://foo', body=p.encode(), headers={'Content-Type': 'application/octet-stream'}) def test_write_loop_polling_two_packets_done(self): c = asyncio_client.AsyncClient() c.base_url = 'http://foo' c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ packet.Packet(packet.PING), None ]) c._send_request = AsyncMock() c._send_request.mock.return_value.status = 200 _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 3) p = payload.Payload(packets=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), packet.Packet(packet.PING), ]) c._send_request.mock.assert_called_once_with( 'POST', 'http://foo', body=p.encode(), headers={'Content-Type': 'application/octet-stream'}) self.assertEqual(c.state, 'disconnected') def test_write_loop_polling_bad_connection(self): c = asyncio_client.AsyncClient() c.base_url = 'http://foo' c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ RuntimeError ]) c._send_request = AsyncMock(return_value=None) _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 1) p = payload.Payload( packets=[packet.Packet(packet.MESSAGE, {'foo': 'bar'})]) c._send_request.mock.assert_called_once_with( 'POST', 'http://foo', body=p.encode(), headers={'Content-Type': 'application/octet-stream'}) self.assertEqual(c.state, 'disconnected') def test_write_loop_polling_bad_status(self): c = asyncio_client.AsyncClient() c.base_url = 'http://foo' c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'polling' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ RuntimeError ]) c._send_request = AsyncMock() c._send_request.mock.return_value.status = 500 _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 1) p = payload.Payload( packets=[packet.Packet(packet.MESSAGE, {'foo': 'bar'})]) c._send_request.mock.assert_called_once_with( 'POST', 'http://foo', body=p.encode(), headers={'Content-Type': 'application/octet-stream'}) self.assertEqual(c.state, 'disconnected') def test_write_loop_websocket_one_packet(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'websocket' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ RuntimeError ]) c.ws = mock.MagicMock() c.ws.send = AsyncMock() _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 1) self.assertEqual(c.ws.send.mock.call_count, 1) c.ws.send.mock.assert_called_once_with('4{"foo":"bar"}') def test_write_loop_websocket_three_packets(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'websocket' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ packet.Packet(packet.PING), packet.Packet(packet.NOOP), RuntimeError ]) c.ws = mock.MagicMock() c.ws.send = AsyncMock() _run(c._write_loop()) self.assertEqual(c.queue.task_done.call_count, 3) self.assertEqual(c.ws.send.mock.call_count, 3) self.assertEqual(c.ws.send.mock.call_args_list[0][0][0], '4{"foo":"bar"}') self.assertEqual(c.ws.send.mock.call_args_list[1][0][0], '2') self.assertEqual(c.ws.send.mock.call_args_list[2][0][0], '6') def test_write_loop_websocket_bad_connection(self): c = asyncio_client.AsyncClient() c.state = 'connected' c.ping_interval = 1 c.ping_timeout = 2 c.current_transport = 'websocket' c.queue = mock.MagicMock() c.queue_empty = RuntimeError c.queue.get = AsyncMock(side_effect=[ packet.Packet(packet.MESSAGE, {'foo': 'bar'}), RuntimeError ]) c.queue.get_nowait = mock.MagicMock(side_effect=[ RuntimeError ]) c.ws = mock.MagicMock() c.ws.send = AsyncMock( side_effect=websockets.exceptions.ConnectionClosed(1, 'foo')) _run(c._write_loop()) self.assertEqual(c.state, 'disconnected')