You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1303 lines
46 KiB

import logging
import time
from unittest import mock
import pytest
from engineio import exceptions as engineio_exceptions, json, packet as engineio_packet
from socketio 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()