import logging import time from unittest import mock import pytest from engineio import exceptions as engineio_exceptions, json, packet as engineio_packet from fastsio import ( async_namespace, client, exceptions, msgpack_packet, namespace, packet, ) class TestClient: def test_is_asyncio_based(self): c = client.Client() assert not c.is_asyncio_based() @mock.patch("socketio.client.Client._engineio_client_class") def test_create(self, engineio_client_class): c = client.Client( reconnection=False, reconnection_attempts=123, reconnection_delay=5, reconnection_delay_max=10, randomization_factor=0.2, handle_sigint=False, foo="bar", ) assert not c.reconnection assert c.reconnection_attempts == 123 assert c.reconnection_delay == 5 assert c.reconnection_delay_max == 10 assert c.randomization_factor == 0.2 assert not c.handle_sigint engineio_client_class().assert_called_once_with(foo="bar", handle_sigint=False) assert c.connection_url is None assert c.connection_headers is None assert c.connection_transports is None assert c.connection_namespaces == [] assert c.socketio_path is None assert c.sid is None assert c.namespaces == {} assert c.handlers == {} assert c.namespace_handlers == {} assert c.callbacks == {} assert c._binary_packet is None assert c._reconnect_task is None assert c.packet_class == packet.Packet def test_msgpack(self): c = client.Client(serializer="msgpack") assert c.packet_class == msgpack_packet.MsgPackPacket def test_custom_serializer(self): class CustomPacket(packet.Packet): pass c = client.Client(serializer=CustomPacket) assert c.packet_class == CustomPacket def test_custom_json(self): client.Client() assert packet.Packet.json == json assert engineio_packet.Packet.json == json client.Client(json="foo") assert packet.Packet.json == "foo" assert engineio_packet.Packet.json == "foo" packet.Packet.json = json def test_logger(self): c = client.Client(logger=False) assert c.logger.getEffectiveLevel() == logging.ERROR c.logger.setLevel(logging.NOTSET) c = client.Client(logger=True) assert c.logger.getEffectiveLevel() == logging.INFO c.logger.setLevel(logging.WARNING) c = client.Client(logger=True) assert c.logger.getEffectiveLevel() == logging.WARNING c.logger.setLevel(logging.NOTSET) my_logger = logging.Logger("foo") c = client.Client(logger=my_logger) assert c.logger == my_logger @mock.patch("socketio.client.Client._engineio_client_class") def test_engineio_logger(self, engineio_client_class): client.Client(engineio_logger="foo") engineio_client_class().assert_called_once_with( handle_sigint=True, logger="foo" ) def test_on_event(self): c = client.Client() @c.on("connect") def foo(): pass def bar(): pass c.on("disconnect", bar) c.on("disconnect", bar, namespace="/foo") assert c.handlers["/"]["connect"] == foo assert c.handlers["/"]["disconnect"] == bar assert c.handlers["/foo"]["disconnect"] == bar def test_event(self): c = client.Client() @c.event def connect(): pass @c.event def foo(): pass @c.event def bar(): pass @c.event(namespace="/foo") def disconnect(): pass assert c.handlers["/"]["connect"] == connect assert c.handlers["/"]["foo"] == foo assert c.handlers["/"]["bar"] == bar assert c.handlers["/foo"]["disconnect"] == disconnect def test_namespace_handler(self): class MyNamespace(namespace.ClientNamespace): pass c = client.Client() n = MyNamespace("/foo") c.register_namespace(n) assert c.namespace_handlers["/foo"] == n def test_namespace_handler_wrong_class(self): class MyNamespace: def __init__(self, n): pass c = client.Client() n = MyNamespace("/foo") with pytest.raises(ValueError): c.register_namespace(n) def test_namespace_handler_wrong_async(self): class MyNamespace(async_namespace.AsyncClientNamespace): pass c = client.Client() n = MyNamespace("/foo") with pytest.raises(ValueError): c.register_namespace(n) def test_connect(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( "url", headers="headers", auth="auth", transports="transports", namespaces=["/foo", "/", "/bar"], socketio_path="path", wait=False, ) assert c.connection_url == "url" assert c.connection_headers == "headers" assert c.connection_auth == "auth" assert c.connection_transports == "transports" assert c.connection_namespaces == ["/foo", "/", "/bar"] assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( "url", headers="headers", transports="transports", engineio_path="path", ) def test_connect_functions(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( lambda: "url", headers=lambda: "headers", auth="auth", transports="transports", namespaces=["/foo", "/", "/bar"], socketio_path="path", wait=False, ) c.eio.connect.assert_called_once_with( "url", headers="headers", transports="transports", engineio_path="path", ) def test_connect_one_namespace(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( "url", headers="headers", transports="transports", namespaces="/foo", socketio_path="path", wait=False, ) assert c.connection_url == "url" assert c.connection_headers == "headers" assert c.connection_transports == "transports" assert c.connection_namespaces == ["/foo"] assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( "url", headers="headers", transports="transports", engineio_path="path", ) def test_connect_default_namespaces(self): c = client.Client() c.eio.connect = mock.MagicMock() c.on("foo", mock.MagicMock(), namespace="/foo") c.on("bar", mock.MagicMock(), namespace="/") c.on("baz", mock.MagicMock(), namespace="*") c.connect( "url", headers="headers", transports="transports", socketio_path="path", wait=False, ) assert c.connection_url == "url" assert c.connection_headers == "headers" assert c.connection_transports == "transports" assert c.connection_namespaces == ["/foo", "/"] or c.connection_namespaces == [ "/", "/foo", ] assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( "url", headers="headers", transports="transports", engineio_path="path", ) def test_connect_no_namespaces(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( "url", headers="headers", transports="transports", socketio_path="path", wait=False, ) assert c.connection_url == "url" assert c.connection_headers == "headers" assert c.connection_transports == "transports" assert c.connection_namespaces == ["/"] assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( "url", headers="headers", transports="transports", engineio_path="path", ) def test_connect_error(self): c = client.Client() c.eio.connect = mock.MagicMock( side_effect=engineio_exceptions.ConnectionError("foo") ) c.on("foo", mock.MagicMock(), namespace="/foo") c.on("bar", mock.MagicMock(), namespace="/") with pytest.raises(exceptions.ConnectionError): c.connect( "url", headers="headers", transports="transports", socketio_path="path", wait=False, ) def test_connect_twice(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( "url", wait=False, ) with pytest.raises(exceptions.ConnectionError): c.connect( "url", wait=False, ) def test_connect_wait_single_namespace(self): c = client.Client() c.eio.connect = mock.MagicMock() c._connect_event = mock.MagicMock() def mock_connect(timeout): assert timeout == 0.01 c.namespaces = {"/": "123"} return True c._connect_event.wait = mock_connect c.connect( "url", wait=True, wait_timeout=0.01, ) assert c.connected is True def test_connect_wait_two_namespaces(self): c = client.Client() c.eio.connect = mock.MagicMock() c._connect_event = mock.MagicMock() def mock_connect(timeout): assert timeout == 0.01 if c.namespaces == {}: c.namespaces = {"/bar": "123"} return True if c.namespaces == {"/bar": "123"}: c.namespaces = {"/bar": "123", "/foo": "456"} return True return False c._connect_event.wait = mock_connect c.connect( "url", namespaces=["/foo", "/bar"], wait=True, wait_timeout=0.01, ) assert c.connected is True assert c.namespaces == {"/bar": "123", "/foo": "456"} def test_connect_timeout(self): c = client.Client() c.eio.connect = mock.MagicMock() c.disconnect = mock.MagicMock() with pytest.raises(exceptions.ConnectionError): c.connect( "url", wait=True, wait_timeout=0.01, ) c.disconnect.assert_called_once_with() def test_wait_no_reconnect(self): c = client.Client() c.eio.wait = mock.MagicMock() c.sleep = mock.MagicMock() c._reconnect_task = None c.wait() c.eio.wait.assert_called_once_with() c.sleep.assert_called_once_with(1) def test_wait_reconnect_failed(self): c = client.Client() c.eio.wait = mock.MagicMock() c.sleep = mock.MagicMock() c._reconnect_task = mock.MagicMock() states = ["disconnected"] def fake_join(): c.eio.state = states.pop(0) c._reconnect_task.join = fake_join c.wait() c.eio.wait.assert_called_once_with() c.sleep.assert_called_once_with(1) def test_wait_reconnect_successful(self): c = client.Client() c.eio.wait = mock.MagicMock() c.sleep = mock.MagicMock() c._reconnect_task = mock.MagicMock() states = ["connected", "disconnected"] def fake_join(): c.eio.state = states.pop(0) c._reconnect_task.join = fake_join c.wait() assert c.eio.wait.call_count == 2 assert c.sleep.call_count == 2 def test_get_sid(self): c = client.Client() c.namespaces = {"/": "1", "/foo": "2"} assert c.get_sid() == "1" assert c.get_sid("/") == "1" assert c.get_sid("/foo") == "2" assert c.get_sid("/bar") is None def test_emit_no_arguments(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo") expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo"], id=None ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_one_argument(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo", "bar") expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo", "bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_one_argument_list(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo", ["bar", "baz"]) expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo", ["bar", "baz"]], id=None, ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_two_arguments(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo", ("bar", "baz")) expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo", "bar", "baz"], id=None, ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_namespace(self): c = client.Client() c.namespaces = ["/foo"] c._send_packet = mock.MagicMock() c.emit("foo", namespace="/foo") expected_packet = packet.Packet( packet.EVENT, namespace="/foo", data=["foo"], id=None ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_unknown_namespace(self): c = client.Client() c.namespaces = ["/foo"] with pytest.raises(exceptions.BadNamespaceError): c.emit("foo", namespace="/bar") def test_emit_with_callback(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.emit("foo", callback="cb") expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo"], id=123 ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) c._generate_ack_id.assert_called_once_with("/", "cb") def test_emit_namespace_with_callback(self): c = client.Client() c.namespaces = {"/foo": "1"} c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.emit("foo", namespace="/foo", callback="cb") expected_packet = packet.Packet( packet.EVENT, namespace="/foo", data=["foo"], id=123 ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) c._generate_ack_id.assert_called_once_with("/foo", "cb") def test_emit_binary(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo", b"bar") expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo", b"bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_not_binary(self): c = client.Client() c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c.emit("foo", "bar") expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo", "bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_send(self): c = client.Client() c.emit = mock.MagicMock() c.send("data", "namespace", "callback") c.emit.assert_called_once_with( "message", data="data", namespace="namespace", callback="callback" ) def test_send_with_defaults(self): c = client.Client() c.emit = mock.MagicMock() c.send("data") c.emit.assert_called_once_with( "message", data="data", namespace=None, callback=None ) def test_call(self): c = client.Client() c.namespaces = {"/": "1"} def fake_event_wait(timeout=None): assert timeout == 60 c._generate_ack_id.call_args_list[0][0][1]("foo", 321) return True c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait assert c.call("foo") == ("foo", 321) expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo"], id=123 ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_call_with_timeout(self): c = client.Client() c.namespaces = {"/": "1"} def fake_event_wait(timeout=None): assert timeout == 12 return False c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait with pytest.raises(exceptions.TimeoutError): c.call("foo", timeout=12) expected_packet = packet.Packet( packet.EVENT, namespace="/", data=["foo"], id=123 ) assert c._send_packet.call_count == 1 assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_disconnect(self): c = client.Client() c.connected = True c.namespaces = {"/": "1"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() c.eio.state = "connected" c.disconnect() assert c.connected assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 1 expected_packet = packet.Packet(packet.DISCONNECT, namespace="/") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) c.eio.disconnect.assert_called_once_with() def test_disconnect_namespaces(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() c.eio.state = "connected" c.disconnect() assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 2 expected_packet = packet.Packet(packet.DISCONNECT, namespace="/foo") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) expected_packet = packet.Packet(packet.DISCONNECT, namespace="/bar") assert ( c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_transport(self): c = client.Client() c.eio.transport = mock.MagicMock(return_value="foo") assert c.transport() == "foo" c.eio.transport.assert_called_once_with() def test_start_background_task(self): c = client.Client() c.eio.start_background_task = mock.MagicMock(return_value="foo") assert c.start_background_task("foo", "bar", baz="baz") == "foo" c.eio.start_background_task.assert_called_once_with("foo", "bar", baz="baz") def test_sleep(self): c = client.Client() c.eio.sleep = mock.MagicMock() c.sleep(1.23) c.eio.sleep.assert_called_once_with(1.23) def test_send_packet(self): c = client.Client() c.eio.send = mock.MagicMock() c._send_packet(packet.Packet(packet.EVENT, "foo")) c.eio.send.assert_called_once_with('2"foo"') def test_send_packet_binary(self): c = client.Client() c.eio.send = mock.MagicMock() c._send_packet(packet.Packet(packet.EVENT, b"foo")) assert c.eio.send.call_args_list == [ mock.call('51-{"_placeholder":true,"num":0}'), mock.call(b"foo"), ] or c.eio.send.call_args_list == [ mock.call('51-{"num":0,"_placeholder":true}'), mock.call(b"foo"), ] def test_send_packet_default_binary(self): c = client.Client() c.eio.send = mock.MagicMock() c._send_packet(packet.Packet(packet.EVENT, "foo")) c.eio.send.assert_called_once_with('2"foo"') def test_generate_ack_id(self): c = client.Client() assert c._generate_ack_id("/", "cb") == 1 assert c._generate_ack_id("/", "cb") == 2 assert c._generate_ack_id("/", "cb") == 3 assert c._generate_ack_id("/foo", "cb") == 1 assert c._generate_ack_id("/bar", "cb") == 1 assert c._generate_ack_id("/", "cb") == 4 assert c._generate_ack_id("/bar", "cb") == 2 def test_handle_connect(self): c = client.Client() c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c._handle_connect("/", {"sid": "123"}) assert c.namespaces == {"/": "123"} c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect", namespace="/") c._send_packet.assert_not_called() def test_handle_connect_with_namespaces(self): c = client.Client() c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c._handle_connect("/", {"sid": "3"}) c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect", namespace="/") assert c.namespaces == {"/": "3", "/foo": "1", "/bar": "2"} def test_handle_connect_namespace(self): c = client.Client() c.namespaces = {"/foo": "1"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c._handle_connect("/foo", {"sid": "123"}) c._handle_connect("/bar", {"sid": "2"}) assert c._trigger_event.call_count == 1 c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect", namespace="/bar") assert c.namespaces == {"/foo": "1", "/bar": "2"} def test_handle_disconnect(self): c = client.Client() c.namespace = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() c._handle_disconnect("/") c._trigger_event.assert_any_call("disconnect", "/", c.reason.SERVER_DISCONNECT) c._trigger_event.assert_any_call("__disconnect_final", "/") assert not c.connected c._handle_disconnect("/") assert c._trigger_event.call_count == 2 def test_handle_disconnect_namespace(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._handle_disconnect("/foo") c._trigger_event.assert_any_call( "disconnect", "/foo", c.reason.SERVER_DISCONNECT ) c._trigger_event.assert_any_call("__disconnect_final", "/foo") assert c.namespaces == {"/bar": "2"} assert c.connected c._handle_disconnect("/bar") c._trigger_event.assert_any_call( "disconnect", "/bar", c.reason.SERVER_DISCONNECT ) c._trigger_event.assert_any_call("__disconnect_final", "/bar") assert c.namespaces == {} assert not c.connected def test_handle_disconnect_unknown_namespace(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._handle_disconnect("/baz") c._trigger_event.assert_any_call( "disconnect", "/baz", c.reason.SERVER_DISCONNECT ) c._trigger_event.assert_any_call("__disconnect_final", "/baz") assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_disconnect_default_namespace(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._handle_disconnect("/") c._trigger_event.assert_any_call("disconnect", "/", c.reason.SERVER_DISCONNECT) c._trigger_event.assert_any_call("__disconnect_final", "/") assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_event(self): c = client.Client() c._trigger_event = mock.MagicMock() c._handle_event("/", None, ["foo", ("bar", "baz")]) c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) def test_handle_event_with_id_no_arguments(self): c = client.Client() c._trigger_event = mock.MagicMock(return_value=None) c._send_packet = mock.MagicMock() c._handle_event("/", 123, ["foo", ("bar", "baz")]) c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=[]) assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_one_argument(self): c = client.Client() c._trigger_event = mock.MagicMock(return_value="ret") c._send_packet = mock.MagicMock() c._handle_event("/", 123, ["foo", ("bar", "baz")]) c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=["ret"]) assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_one_list_argument(self): c = client.Client() c._trigger_event = mock.MagicMock(return_value=["a", "b"]) c._send_packet = mock.MagicMock() c._handle_event("/", 123, ["foo", ("bar", "baz")]) c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet( packet.ACK, namespace="/", id=123, data=[["a", "b"]] ) assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_two_arguments(self): c = client.Client() c._trigger_event = mock.MagicMock(return_value=("a", "b")) c._send_packet = mock.MagicMock() c._handle_event("/", 123, ["foo", ("bar", "baz")]) c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet( packet.ACK, namespace="/", id=123, data=["a", "b"] ) assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_ack(self): c = client.Client() mock_cb = mock.MagicMock() c.callbacks["/foo"] = {123: mock_cb} c._handle_ack("/foo", 123, ["bar", "baz"]) mock_cb.assert_called_once_with("bar", "baz") assert 123 not in c.callbacks["/foo"] def test_handle_ack_not_found(self): c = client.Client() mock_cb = mock.MagicMock() c.callbacks["/foo"] = {123: mock_cb} c._handle_ack("/foo", 124, ["bar", "baz"]) mock_cb.assert_not_called() assert 123 in c.callbacks["/foo"] def test_handle_error(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._handle_error("/", "error") assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect_error", "/", "error") def test_handle_error_with_no_arguments(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._handle_error("/", None) assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect_error", "/") def test_handle_error_namespace(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._handle_error("/bar", ["error", "message"]) assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with( "connect_error", "/bar", "error", "message" ) def test_handle_error_namespace_with_no_arguments(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._handle_error("/bar", None) assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with("connect_error", "/bar") def test_handle_error_unknown_namespace(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._handle_error("/baz", "error") assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected c._connect_event.set.assert_called_once_with() def test_trigger_event(self): c = client.Client() handler = mock.MagicMock() catchall_handler = mock.MagicMock() c.on("foo", handler) c.on("*", catchall_handler) c._trigger_event("foo", "/", 1, "2") c._trigger_event("bar", "/", 1, "2", 3) c._trigger_event("connect", "/") # should not trigger handler.assert_called_once_with(1, "2") catchall_handler.assert_called_once_with("bar", 1, "2", 3) def test_trigger_event_namespace(self): c = client.Client() handler = mock.MagicMock() catchall_handler = mock.MagicMock() c.on("foo", handler, namespace="/bar") c.on("*", catchall_handler, namespace="/bar") c._trigger_event("foo", "/bar", 1, "2") c._trigger_event("bar", "/bar", 1, "2", 3) handler.assert_called_once_with(1, "2") catchall_handler.assert_called_once_with("bar", 1, "2", 3) def test_trigger_event_with_catchall_namespace(self): c = client.Client() connect_star_handler = mock.MagicMock() msg_foo_handler = mock.MagicMock() msg_star_handler = mock.MagicMock() star_foo_handler = mock.MagicMock() star_star_handler = mock.MagicMock() c.on("connect", connect_star_handler, namespace="*") c.on("msg", msg_foo_handler, namespace="/foo") c.on("msg", msg_star_handler, namespace="*") c.on("*", star_foo_handler, namespace="/foo") c.on("*", star_star_handler, namespace="*") c._trigger_event("connect", "/bar") c._trigger_event("msg", "/foo", "a", "b") c._trigger_event("msg", "/bar", "a", "b") c._trigger_event("my message", "/foo", "a", "b", "c") c._trigger_event("my message", "/bar", "a", "b", "c") c._trigger_event("disconnect", "/bar") connect_star_handler.assert_called_once_with("/bar") msg_foo_handler.assert_called_once_with("a", "b") msg_star_handler.assert_called_once_with("/bar", "a", "b") star_foo_handler.assert_called_once_with("my message", "a", "b", "c") star_star_handler.assert_called_once_with("my message", "/bar", "a", "b", "c") def test_trigger_event_with_catchall_namespace_handler(self): result = {} class MyNamespace(namespace.ClientNamespace): def on_connect(self, ns): result["result"] = (ns,) def on_disconnect(self, ns, reason): result["result"] = ("disconnect", ns, reason) def on_foo(self, ns, data): result["result"] = (ns, data) def on_bar(self, ns): result["result"] = "bar" + ns def on_baz(self, ns, data1, data2): result["result"] = (ns, data1, data2) c = client.Client() c.register_namespace(MyNamespace("*")) c._trigger_event("connect", "/foo") assert result["result"] == ("/foo",) c._trigger_event("foo", "/foo", "a") assert result["result"] == ("/foo", "a") c._trigger_event("bar", "/foo") assert result["result"] == "bar/foo" c._trigger_event("baz", "/foo", "a", "b") assert result["result"] == ("/foo", "a", "b") c._trigger_event("disconnect", "/foo", "bar") assert result["result"] == ("disconnect", "/foo", "bar") def test_trigger_event_class_namespace(self): c = client.Client() result = [] class MyNamespace(namespace.ClientNamespace): def on_foo(self, a, b): result.append(a) result.append(b) c.register_namespace(MyNamespace("/")) c._trigger_event("foo", "/", 1, "2") assert result == [1, "2"] def test_trigger_event_unknown_namespace(self): c = client.Client() result = [] class MyNamespace(namespace.ClientNamespace): def on_foo(self, a, b): result.append(a) result.append(b) c.register_namespace(MyNamespace("/")) c._trigger_event("foo", "/bar", 1, "2") assert result == [] @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect(self, random): c = client.Client() c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c.connect = mock.MagicMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) c._handle_reconnect() assert c._reconnect_abort.wait.call_count == 3 assert c._reconnect_abort.wait.call_args_list == [ mock.call(1.5), mock.call(1.5), mock.call(4.0), ] assert c._reconnect_task is None @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_delay(self, random): c = client.Client(reconnection_delay_max=3) c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c.connect = mock.MagicMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) c._handle_reconnect() assert c._reconnect_abort.wait.call_count == 3 assert c._reconnect_abort.wait.call_args_list == [ mock.call(1.5), mock.call(1.5), mock.call(3.0), ] assert c._reconnect_task is None @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_attempts(self, random): c = client.Client(reconnection_attempts=2) c.connection_namespaces = ["/"] c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c._trigger_event = mock.MagicMock() c.connect = mock.MagicMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) c._handle_reconnect() assert c._reconnect_abort.wait.call_count == 2 assert c._reconnect_abort.wait.call_args_list == [ mock.call(1.5), mock.call(1.5), ] assert c._reconnect_task == "foo" c._trigger_event.assert_called_once_with("__disconnect_final", namespace="/") @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_aborted(self, random): c = client.Client() c.connection_namespaces = ["/"] c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(side_effect=[False, True]) c._trigger_event = mock.MagicMock() c.connect = mock.MagicMock(side_effect=exceptions.ConnectionError) c._handle_reconnect() assert c._reconnect_abort.wait.call_count == 2 assert c._reconnect_abort.wait.call_args_list == [ mock.call(1.5), mock.call(1.5), ] assert c._reconnect_task == "foo" c._trigger_event.assert_called_once_with("__disconnect_final", namespace="/") def test_shutdown_disconnect(self): c = client.Client() c.connected = True c.namespaces = {"/": "1"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() c.eio.state = "connected" c.shutdown() assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 1 expected_packet = packet.Packet(packet.DISCONNECT, namespace="/") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) c.eio.disconnect.assert_called_once_with() def test_shutdown_disconnect_namespaces(self): c = client.Client() c.connected = True c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() c.eio.state = "connected" c.shutdown() assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 2 expected_packet = packet.Packet(packet.DISCONNECT, namespace="/foo") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) expected_packet = packet.Packet(packet.DISCONNECT, namespace="/bar") assert ( c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_shutdown_reconnect(self, random): c = client.Client() c.connection_namespaces = ["/"] c._reconnect_task = mock.MagicMock() c._trigger_event = mock.MagicMock() c.connect = mock.MagicMock(side_effect=exceptions.ConnectionError) task = c.start_background_task(c._handle_reconnect) time.sleep(0.1) c.shutdown() task.join() c._trigger_event.assert_called_once_with("__disconnect_final", namespace="/") c._reconnect_task.join.assert_called_once_with() def test_handle_eio_connect(self): c = client.Client() c.connection_namespaces = ["/", "/foo"] c.connection_auth = "auth" c._send_packet = mock.MagicMock() c.eio.sid = "foo" assert c.sid is None c._handle_eio_connect() assert c.sid == "foo" assert c._send_packet.call_count == 2 expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_handle_eio_connect_function(self): c = client.Client() c.connection_namespaces = ["/", "/foo"] c.connection_auth = lambda: "auth" c._send_packet = mock.MagicMock() c.eio.sid = "foo" assert c.sid is None c._handle_eio_connect() assert c.sid == "foo" assert c._send_packet.call_count == 2 expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_handle_eio_message(self): c = client.Client() c._handle_connect = mock.MagicMock() c._handle_disconnect = mock.MagicMock() c._handle_event = mock.MagicMock() c._handle_ack = mock.MagicMock() c._handle_error = mock.MagicMock() c._handle_eio_message('0{"sid":"123"}') c._handle_connect.assert_called_with(None, {"sid": "123"}) c._handle_eio_message('0/foo,{"sid":"123"}') c._handle_connect.assert_called_with("/foo", {"sid": "123"}) c._handle_eio_message("1") c._handle_disconnect.assert_called_with(None) c._handle_eio_message("1/foo") c._handle_disconnect.assert_called_with("/foo") c._handle_eio_message('2["foo"]') c._handle_event.assert_called_with(None, None, ["foo"]) c._handle_eio_message('3/foo,["bar"]') c._handle_ack.assert_called_with("/foo", None, ["bar"]) c._handle_eio_message("4") c._handle_error.assert_called_with(None, None) c._handle_eio_message('4"foo"') c._handle_error.assert_called_with(None, "foo") c._handle_eio_message('4["foo"]') c._handle_error.assert_called_with(None, ["foo"]) c._handle_eio_message("4/foo") c._handle_error.assert_called_with("/foo", None) c._handle_eio_message('4/foo,["foo","bar"]') c._handle_error.assert_called_with("/foo", ["foo", "bar"]) c._handle_eio_message('51-{"_placeholder":true,"num":0}') assert c._binary_packet.packet_type == packet.BINARY_EVENT c._handle_eio_message(b"foo") c._handle_event.assert_called_with(None, None, b"foo") c._handle_eio_message( '62-/foo,{"1":{"_placeholder":true,"num":1},' '"2":{"_placeholder":true,"num":0}}' ) assert c._binary_packet.packet_type == packet.BINARY_ACK c._handle_eio_message(b"bar") c._handle_eio_message(b"foo") c._handle_ack.assert_called_with("/foo", None, {"1": b"foo", "2": b"bar"}) with pytest.raises(ValueError): c._handle_eio_message("9") def test_eio_disconnect(self): c = client.Client() c.namespaces = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() c.sid = "foo" c.eio.state = "connected" c._handle_eio_disconnect("foo") c._trigger_event.assert_called_once_with("disconnect", "/", "foo") assert c.sid is None assert not c.connected def test_eio_disconnect_namespaces(self): c = client.Client() c.connected = True c.namespaces = {"/": "1", "/foo": "2", "/bar": "3"} c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() c.sid = "foo" c.eio.state = "connected" c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT) c._trigger_event.assert_any_call( "disconnect", "/foo", c.reason.CLIENT_DISCONNECT ) c._trigger_event.assert_any_call( "disconnect", "/bar", c.reason.CLIENT_DISCONNECT ) c._trigger_event.assert_any_call("disconnect", "/", c.reason.CLIENT_DISCONNECT) assert c.sid is None assert not c.connected def test_eio_disconnect_reconnect(self): c = client.Client(reconnection=True) c.start_background_task = mock.MagicMock() c.eio.state = "connected" c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT) c.start_background_task.assert_called_once_with(c._handle_reconnect) def test_eio_disconnect_self_disconnect(self): c = client.Client(reconnection=True) c.start_background_task = mock.MagicMock() c.eio.state = "disconnected" c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT) c.start_background_task.assert_not_called() def test_eio_disconnect_no_reconnect(self): c = client.Client(reconnection=False) c.namespaces = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() c.sid = "foo" c.eio.state = "connected" c._handle_eio_disconnect(c.reason.TRANSPORT_ERROR) c._trigger_event.assert_any_call("disconnect", "/", c.reason.TRANSPORT_ERROR) c._trigger_event.assert_any_call("__disconnect_final", "/") assert c.sid is None assert not c.connected c.start_background_task.assert_not_called()