Browse Source

disconnect reasons for client

pull/1422/head
Miguel Grinberg 4 months ago
parent
commit
a6e6ca6265
Failed to extract signature
  1. 28
      src/socketio/async_client.py
  2. 24
      src/socketio/async_namespace.py
  3. 2
      src/socketio/base_client.py
  4. 18
      src/socketio/client.py
  5. 7
      src/socketio/namespace.py
  6. 89
      tests/async/test_client.py
  7. 62
      tests/async/test_namespace.py
  8. 71
      tests/common/test_client.py
  9. 39
      tests/common/test_namespace.py

28
src/socketio/async_client.py

@ -398,8 +398,9 @@ class AsyncClient(base_client.BaseClient):
if not self.connected: if not self.connected:
return return
namespace = namespace or '/' namespace = namespace or '/'
await self._trigger_event('disconnect', namespace=namespace) await self._trigger_event('disconnect', namespace,
await self._trigger_event('__disconnect_final', namespace=namespace) self.reason.SERVER_DISCONNECT)
await self._trigger_event('__disconnect_final', namespace)
if namespace in self.namespaces: if namespace in self.namespaces:
del self.namespaces[namespace] del self.namespaces[namespace]
if not self.namespaces: if not self.namespaces:
@ -461,12 +462,28 @@ class AsyncClient(base_client.BaseClient):
handler, args = self._get_event_handler(event, namespace, args) handler, args = self._get_event_handler(event, namespace, args)
if handler: if handler:
if asyncio.iscoroutinefunction(handler): if asyncio.iscoroutinefunction(handler):
try:
try: try:
ret = await handler(*args) ret = await handler(*args)
except TypeError:
# the legacy disconnect event does not take a reason
# argument
if event == 'disconnect':
ret = await handler(*args[:-1])
else: # pragma: no cover
raise
except asyncio.CancelledError: # pragma: no cover except asyncio.CancelledError: # pragma: no cover
ret = None ret = None
else: else:
try:
ret = handler(*args) ret = handler(*args)
except TypeError:
# the legacy disconnect event does not take a reason
# argument
if event == 'disconnect':
ret = handler(*args[:-1])
else: # pragma: no cover
raise
return ret return ret
# or else, forward the event to a namepsace handler if one exists # or else, forward the event to a namepsace handler if one exists
@ -566,16 +583,15 @@ class AsyncClient(base_client.BaseClient):
else: else:
raise ValueError('Unknown packet type.') raise ValueError('Unknown packet type.')
async def _handle_eio_disconnect(self): async def _handle_eio_disconnect(self, reason):
"""Handle the Engine.IO disconnection event.""" """Handle the Engine.IO disconnection event."""
self.logger.info('Engine.IO connection dropped') self.logger.info('Engine.IO connection dropped')
will_reconnect = self.reconnection and self.eio.state == 'connected' will_reconnect = self.reconnection and self.eio.state == 'connected'
if self.connected: if self.connected:
for n in self.namespaces: for n in self.namespaces:
await self._trigger_event('disconnect', namespace=n) await self._trigger_event('disconnect', n, reason)
if not will_reconnect: if not will_reconnect:
await self._trigger_event('__disconnect_final', await self._trigger_event('__disconnect_final', n)
namespace=n)
self.namespaces = {} self.namespaces = {}
self.connected = False self.connected = False
self.callbacks = {} self.callbacks = {}

24
src/socketio/async_namespace.py

@ -46,7 +46,15 @@ class AsyncNamespace(base_namespace.BaseServerNamespace):
except asyncio.CancelledError: # pragma: no cover except asyncio.CancelledError: # pragma: no cover
ret = None ret = None
else: else:
try:
ret = handler(*args) ret = handler(*args)
except TypeError:
# legacy disconnect events do not have a reason
# argument
if event == 'disconnect':
ret = handler(*args[:-1])
else: # pragma: no cover
raise
return ret return ret
async def emit(self, event, data=None, to=None, room=None, skip_sid=None, async def emit(self, event, data=None, to=None, room=None, skip_sid=None,
@ -206,12 +214,28 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace):
if hasattr(self, handler_name): if hasattr(self, handler_name):
handler = getattr(self, handler_name) handler = getattr(self, handler_name)
if asyncio.iscoroutinefunction(handler) is True: if asyncio.iscoroutinefunction(handler) is True:
try:
try: try:
ret = await handler(*args) ret = await handler(*args)
except TypeError:
# legacy disconnect events do not have a reason
# argument
if event == 'disconnect':
ret = await handler(*args[:-1])
else: # pragma: no cover
raise
except asyncio.CancelledError: # pragma: no cover except asyncio.CancelledError: # pragma: no cover
ret = None ret = None
else: else:
try:
ret = handler(*args) ret = handler(*args)
except TypeError:
# legacy disconnect events do not have a reason
# argument
if event == 'disconnect':
ret = handler(*args[:-1])
else: # pragma: no cover
raise
return ret return ret
async def emit(self, event, data=None, namespace=None, callback=None): async def emit(self, event, data=None, namespace=None, callback=None):

2
src/socketio/base_client.py

@ -289,7 +289,7 @@ class BaseClient:
def _handle_eio_message(self, data): # pragma: no cover def _handle_eio_message(self, data): # pragma: no cover
raise NotImplementedError() raise NotImplementedError()
def _handle_eio_disconnect(self): # pragma: no cover def _handle_eio_disconnect(self, reason): # pragma: no cover
raise NotImplementedError() raise NotImplementedError()
def _engineio_client_class(self): # pragma: no cover def _engineio_client_class(self): # pragma: no cover

18
src/socketio/client.py

@ -377,8 +377,9 @@ class Client(base_client.BaseClient):
if not self.connected: if not self.connected:
return return
namespace = namespace or '/' namespace = namespace or '/'
self._trigger_event('disconnect', namespace=namespace) self._trigger_event('disconnect', namespace,
self._trigger_event('__disconnect_final', namespace=namespace) self.reason.SERVER_DISCONNECT)
self._trigger_event('__disconnect_final', namespace)
if namespace in self.namespaces: if namespace in self.namespaces:
del self.namespaces[namespace] del self.namespaces[namespace]
if not self.namespaces: if not self.namespaces:
@ -436,7 +437,14 @@ class Client(base_client.BaseClient):
# first see if we have an explicit handler for the event # first see if we have an explicit handler for the event
handler, args = self._get_event_handler(event, namespace, args) handler, args = self._get_event_handler(event, namespace, args)
if handler: if handler:
try:
return handler(*args) return handler(*args)
except TypeError:
# the legacy disconnect event does not take a reason argument
if event == 'disconnect':
return handler(*args[:-1])
else: # pragma: no cover
raise
# or else, forward the event to a namespace handler if one exists # or else, forward the event to a namespace handler if one exists
handler, args = self._get_namespace_handler(namespace, args) handler, args = self._get_namespace_handler(namespace, args)
@ -525,15 +533,15 @@ class Client(base_client.BaseClient):
else: else:
raise ValueError('Unknown packet type.') raise ValueError('Unknown packet type.')
def _handle_eio_disconnect(self): def _handle_eio_disconnect(self, reason):
"""Handle the Engine.IO disconnection event.""" """Handle the Engine.IO disconnection event."""
self.logger.info('Engine.IO connection dropped') self.logger.info('Engine.IO connection dropped')
will_reconnect = self.reconnection and self.eio.state == 'connected' will_reconnect = self.reconnection and self.eio.state == 'connected'
if self.connected: if self.connected:
for n in self.namespaces: for n in self.namespaces:
self._trigger_event('disconnect', namespace=n) self._trigger_event('disconnect', n, reason)
if not will_reconnect: if not will_reconnect:
self._trigger_event('__disconnect_final', namespace=n) self._trigger_event('__disconnect_final', n)
self.namespaces = {} self.namespaces = {}
self.connected = False self.connected = False
self.callbacks = {} self.callbacks = {}

7
src/socketio/namespace.py

@ -161,7 +161,14 @@ class ClientNamespace(base_namespace.BaseClientNamespace):
""" """
handler_name = 'on_' + (event or '') handler_name = 'on_' + (event or '')
if hasattr(self, handler_name): if hasattr(self, handler_name):
try:
return getattr(self, handler_name)(*args) return getattr(self, handler_name)(*args)
except TypeError:
# legacy disconnect events do not have a reason argument
if event == 'disconnect':
return getattr(self, handler_name)(*args[:-1])
else: # pragma: no cover
raise
def emit(self, event, data=None, namespace=None, callback=None): def emit(self, event, data=None, namespace=None, callback=None):
"""Emit a custom event to the server. """Emit a custom event to the server.

89
tests/async/test_client.py

@ -578,11 +578,9 @@ class TestAsyncClient:
c._trigger_event = mock.AsyncMock() c._trigger_event = mock.AsyncMock()
await c._handle_disconnect('/') await c._handle_disconnect('/')
c._trigger_event.assert_any_await( c._trigger_event.assert_any_await(
'disconnect', namespace='/' 'disconnect', '/', c.reason.SERVER_DISCONNECT
)
c._trigger_event.assert_any_await(
'__disconnect_final', namespace='/'
) )
c._trigger_event.assert_any_await('__disconnect_final', '/')
assert not c.connected assert not c.connected
await c._handle_disconnect('/') await c._handle_disconnect('/')
assert c._trigger_event.await_count == 2 assert c._trigger_event.await_count == 2
@ -593,21 +591,15 @@ class TestAsyncClient:
c.namespaces = {'/foo': '1', '/bar': '2'} c.namespaces = {'/foo': '1', '/bar': '2'}
c._trigger_event = mock.AsyncMock() c._trigger_event = mock.AsyncMock()
await c._handle_disconnect('/foo') await c._handle_disconnect('/foo')
c._trigger_event.assert_any_await( c._trigger_event.assert_any_await('disconnect', '/foo',
'disconnect', namespace='/foo' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_await('__disconnect_final', '/foo')
c._trigger_event.assert_any_await(
'__disconnect_final', namespace='/foo'
)
assert c.namespaces == {'/bar': '2'} assert c.namespaces == {'/bar': '2'}
assert c.connected assert c.connected
await c._handle_disconnect('/bar') await c._handle_disconnect('/bar')
c._trigger_event.assert_any_await( c._trigger_event.assert_any_await('disconnect', '/bar',
'disconnect', namespace='/bar' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_await('__disconnect_final', '/bar')
c._trigger_event.assert_any_await(
'__disconnect_final', namespace='/bar'
)
assert c.namespaces == {} assert c.namespaces == {}
assert not c.connected assert not c.connected
@ -617,12 +609,9 @@ class TestAsyncClient:
c.namespaces = {'/foo': '1', '/bar': '2'} c.namespaces = {'/foo': '1', '/bar': '2'}
c._trigger_event = mock.AsyncMock() c._trigger_event = mock.AsyncMock()
await c._handle_disconnect('/baz') await c._handle_disconnect('/baz')
c._trigger_event.assert_any_await( c._trigger_event.assert_any_await('disconnect', '/baz',
'disconnect', namespace='/baz' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_await('__disconnect_final', '/baz')
c._trigger_event.assert_any_await(
'__disconnect_final', namespace='/baz'
)
assert c.namespaces == {'/foo': '1', '/bar': '2'} assert c.namespaces == {'/foo': '1', '/bar': '2'}
assert c.connected assert c.connected
@ -632,8 +621,9 @@ class TestAsyncClient:
c.namespaces = {'/foo': '1', '/bar': '2'} c.namespaces = {'/foo': '1', '/bar': '2'}
c._trigger_event = mock.AsyncMock() c._trigger_event = mock.AsyncMock()
await c._handle_disconnect('/') await c._handle_disconnect('/')
c._trigger_event.assert_any_await('disconnect', namespace='/') c._trigger_event.assert_any_await('disconnect', '/',
c._trigger_event.assert_any_await('__disconnect_final', namespace='/') c.reason.SERVER_DISCONNECT)
c._trigger_event.assert_any_await('__disconnect_final', '/')
assert c.namespaces == {'/foo': '1', '/bar': '2'} assert c.namespaces == {'/foo': '1', '/bar': '2'}
assert c.connected assert c.connected
@ -818,6 +808,26 @@ class TestAsyncClient:
handler.assert_awaited_once_with(1, '2') handler.assert_awaited_once_with(1, '2')
catchall_handler.assert_awaited_once_with('bar', 1, '2', 3) catchall_handler.assert_awaited_once_with('bar', 1, '2', 3)
async def test_trigger_legacy_disconnect_event(self):
c = async_client.AsyncClient()
@c.on('disconnect')
def baz():
return 'baz'
r = await c._trigger_event('disconnect', '/', 'foo')
assert r == 'baz'
async def test_trigger_legacy_disconnect_event_async(self):
c = async_client.AsyncClient()
@c.on('disconnect')
async def baz():
return 'baz'
r = await c._trigger_event('disconnect', '/', 'foo')
assert r == 'baz'
async def test_trigger_event_class_namespace(self): async def test_trigger_event_class_namespace(self):
c = async_client.AsyncClient() c = async_client.AsyncClient()
result = [] result = []
@ -1127,10 +1137,8 @@ class TestAsyncClient:
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
await c._handle_eio_disconnect() await c._handle_eio_disconnect('foo')
c._trigger_event.assert_awaited_once_with( c._trigger_event.assert_awaited_once_with('disconnect', '/', 'foo')
'disconnect', namespace='/'
)
assert c.sid is None assert c.sid is None
assert not c.connected assert not c.connected
@ -1141,9 +1149,13 @@ class TestAsyncClient:
c._trigger_event = mock.AsyncMock() c._trigger_event = mock.AsyncMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
await c._handle_eio_disconnect() await c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c._trigger_event.assert_any_await('disconnect', namespace='/foo') c._trigger_event.assert_any_await('disconnect', '/foo',
c._trigger_event.assert_any_await('disconnect', namespace='/bar') c.reason.CLIENT_DISCONNECT)
c._trigger_event.assert_any_await('disconnect', '/bar',
c.reason.CLIENT_DISCONNECT)
c._trigger_event.asserT_any_await('disconnect', '/',
c.reason.CLIENT_DISCONNECT)
assert c.sid is None assert c.sid is None
assert not c.connected assert not c.connected
@ -1151,14 +1163,14 @@ class TestAsyncClient:
c = async_client.AsyncClient(reconnection=True) c = async_client.AsyncClient(reconnection=True)
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.eio.state = 'connected' c.eio.state = 'connected'
await c._handle_eio_disconnect() await c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c.start_background_task.assert_called_once_with(c._handle_reconnect) c.start_background_task.assert_called_once_with(c._handle_reconnect)
async def test_eio_disconnect_self_disconnect(self): async def test_eio_disconnect_self_disconnect(self):
c = async_client.AsyncClient(reconnection=True) c = async_client.AsyncClient(reconnection=True)
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.eio.state = 'disconnected' c.eio.state = 'disconnected'
await c._handle_eio_disconnect() await c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c.start_background_task.assert_not_called() c.start_background_task.assert_not_called()
async def test_eio_disconnect_no_reconnect(self): async def test_eio_disconnect_no_reconnect(self):
@ -1169,13 +1181,10 @@ class TestAsyncClient:
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
await c._handle_eio_disconnect() await c._handle_eio_disconnect(c.reason.TRANSPORT_ERROR)
c._trigger_event.assert_any_await( c._trigger_event.assert_any_await('disconnect', '/',
'disconnect', namespace='/' c.reason.TRANSPORT_ERROR)
) c._trigger_event.assert_any_await('__disconnect_final', '/')
c._trigger_event.assert_any_await(
'__disconnect_final', namespace='/'
)
assert c.sid is None assert c.sid is None
assert not c.connected assert not c.connected
c.start_background_task.assert_not_called() c.start_background_task.assert_not_called()

62
tests/async/test_namespace.py

@ -19,13 +19,37 @@ class TestAsyncNamespace:
async def test_disconnect_event(self): async def test_disconnect_event(self):
result = {} result = {}
class MyNamespace(async_namespace.AsyncNamespace):
async def on_disconnect(self, sid, reason):
result['result'] = (sid, reason)
ns = MyNamespace('/foo')
ns._set_server(mock.MagicMock())
_run(ns.trigger_event('disconnect', 'sid', 'foo'))
assert result['result'] == ('sid', 'foo')
def test_legacy_disconnect_event(self):
result = {}
class MyNamespace(async_namespace.AsyncNamespace):
def on_disconnect(self, sid):
result['result'] = sid
ns = MyNamespace('/foo')
ns._set_server(mock.MagicMock())
_run(ns.trigger_event('disconnect', 'sid', 'foo'))
assert result['result'] == 'sid'
def test_legacy_disconnect_event_async(self):
result = {}
class MyNamespace(async_namespace.AsyncNamespace): class MyNamespace(async_namespace.AsyncNamespace):
async def on_disconnect(self, sid): async def on_disconnect(self, sid):
result['result'] = sid result['result'] = sid
ns = MyNamespace('/foo') ns = MyNamespace('/foo')
ns._set_server(mock.MagicMock()) ns._set_server(mock.MagicMock())
await ns.trigger_event('disconnect', 'sid') await ns.trigger_event('disconnect', 'sid', 'foo')
assert result['result'] == 'sid' assert result['result'] == 'sid'
async def test_sync_event(self): async def test_sync_event(self):
@ -242,6 +266,42 @@ class TestAsyncNamespace:
await ns.disconnect('sid', namespace='/bar') await ns.disconnect('sid', namespace='/bar')
ns.server.disconnect.assert_awaited_with('sid', namespace='/bar') ns.server.disconnect.assert_awaited_with('sid', namespace='/bar')
async def test_disconnect_event(self):
result = {}
class MyNamespace(async_namespace.AsyncClientNamespace):
async def on_disconnect(self, reason):
result['result'] = reason
ns = MyNamespace('/foo')
ns._set_client(mock.MagicMock())
await ns.trigger_event('disconnect', 'foo')
assert result['result'] == 'foo'
async def test_legacy_disconnect_event_client(self):
result = {}
class MyNamespace(async_namespace.AsyncClientNamespace):
def on_disconnect(self):
result['result'] = 'ok'
ns = MyNamespace('/foo')
ns._set_client(mock.MagicMock())
await ns.trigger_event('disconnect', 'foo')
assert result['result'] == 'ok'
async def test_legacy_disconnect_event_client_async(self):
result = {}
class MyNamespace(async_namespace.AsyncClientNamespace):
async def on_disconnect(self):
result['result'] = 'ok'
ns = MyNamespace('/foo')
ns._set_client(mock.MagicMock())
await ns.trigger_event('disconnect', 'foo')
assert result['result'] == 'ok'
async def test_sync_event_client(self): async def test_sync_event_client(self):
result = {} result = {}

71
tests/common/test_client.py

@ -752,8 +752,9 @@ class TestClient:
c.connected = True c.connected = True
c._trigger_event = mock.MagicMock() c._trigger_event = mock.MagicMock()
c._handle_disconnect('/') c._handle_disconnect('/')
c._trigger_event.assert_any_call('disconnect', namespace='/') c._trigger_event.assert_any_call('disconnect', '/',
c._trigger_event.assert_any_call('__disconnect_final', namespace='/') c.reason.SERVER_DISCONNECT)
c._trigger_event.assert_any_call('__disconnect_final', '/')
assert not c.connected assert not c.connected
c._handle_disconnect('/') c._handle_disconnect('/')
assert c._trigger_event.call_count == 2 assert c._trigger_event.call_count == 2
@ -764,21 +765,15 @@ class TestClient:
c.namespaces = {'/foo': '1', '/bar': '2'} c.namespaces = {'/foo': '1', '/bar': '2'}
c._trigger_event = mock.MagicMock() c._trigger_event = mock.MagicMock()
c._handle_disconnect('/foo') c._handle_disconnect('/foo')
c._trigger_event.assert_any_call( c._trigger_event.assert_any_call('disconnect', '/foo',
'disconnect', namespace='/foo' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_call('__disconnect_final', '/foo')
c._trigger_event.assert_any_call(
'__disconnect_final', namespace='/foo'
)
assert c.namespaces == {'/bar': '2'} assert c.namespaces == {'/bar': '2'}
assert c.connected assert c.connected
c._handle_disconnect('/bar') c._handle_disconnect('/bar')
c._trigger_event.assert_any_call( c._trigger_event.assert_any_call('disconnect', '/bar',
'disconnect', namespace='/bar' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_call('__disconnect_final', '/bar')
c._trigger_event.assert_any_call(
'__disconnect_final', namespace='/bar'
)
assert c.namespaces == {} assert c.namespaces == {}
assert not c.connected assert not c.connected
@ -788,12 +783,9 @@ class TestClient:
c.namespaces = {'/foo': '1', '/bar': '2'} c.namespaces = {'/foo': '1', '/bar': '2'}
c._trigger_event = mock.MagicMock() c._trigger_event = mock.MagicMock()
c._handle_disconnect('/baz') c._handle_disconnect('/baz')
c._trigger_event.assert_any_call( c._trigger_event.assert_any_call('disconnect', '/baz',
'disconnect', namespace='/baz' c.reason.SERVER_DISCONNECT)
) c._trigger_event.assert_any_call('__disconnect_final', '/baz')
c._trigger_event.assert_any_call(
'__disconnect_final', namespace='/baz'
)
assert c.namespaces == {'/foo': '1', '/bar': '2'} assert c.namespaces == {'/foo': '1', '/bar': '2'}
assert c.connected assert c.connected
@ -804,8 +796,9 @@ class TestClient:
c._trigger_event = mock.MagicMock() c._trigger_event = mock.MagicMock()
c._handle_disconnect('/') c._handle_disconnect('/')
print(c._trigger_event.call_args_list) print(c._trigger_event.call_args_list)
c._trigger_event.assert_any_call('disconnect', namespace='/') c._trigger_event.assert_any_call('disconnect', '/',
c._trigger_event.assert_any_call('__disconnect_final', namespace='/') c.reason.SERVER_DISCONNECT)
c._trigger_event.assert_any_call('__disconnect_final', '/')
assert c.namespaces == {'/foo': '1', '/bar': '2'} assert c.namespaces == {'/foo': '1', '/bar': '2'}
assert c.connected assert c.connected
@ -1003,8 +996,8 @@ class TestClient:
def on_connect(self, ns): def on_connect(self, ns):
result['result'] = (ns,) result['result'] = (ns,)
def on_disconnect(self, ns): def on_disconnect(self, ns, reason):
result['result'] = ('disconnect', ns) result['result'] = ('disconnect', ns, reason)
def on_foo(self, ns, data): def on_foo(self, ns, data):
result['result'] = (ns, data) result['result'] = (ns, data)
@ -1025,8 +1018,8 @@ class TestClient:
assert result['result'] == 'bar/foo' assert result['result'] == 'bar/foo'
c._trigger_event('baz', '/foo', 'a', 'b') c._trigger_event('baz', '/foo', 'a', 'b')
assert result['result'] == ('/foo', 'a', 'b') assert result['result'] == ('/foo', 'a', 'b')
c._trigger_event('disconnect', '/foo') c._trigger_event('disconnect', '/foo', 'bar')
assert result['result'] == ('disconnect', '/foo') assert result['result'] == ('disconnect', '/foo', 'bar')
def test_trigger_event_class_namespace(self): def test_trigger_event_class_namespace(self):
c = client.Client() c = client.Client()
@ -1286,8 +1279,8 @@ class TestClient:
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
c._handle_eio_disconnect() c._handle_eio_disconnect('foo')
c._trigger_event.assert_called_once_with('disconnect', namespace='/') c._trigger_event.assert_called_once_with('disconnect', '/', 'foo')
assert c.sid is None assert c.sid is None
assert not c.connected assert not c.connected
@ -1299,10 +1292,13 @@ class TestClient:
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
c._handle_eio_disconnect() c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c._trigger_event.assert_any_call('disconnect', namespace='/foo') c._trigger_event.assert_any_call('disconnect', '/foo',
c._trigger_event.assert_any_call('disconnect', namespace='/bar') c.reason.CLIENT_DISCONNECT)
c._trigger_event.assert_any_call('disconnect', namespace='/') 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 c.sid is None
assert not c.connected assert not c.connected
@ -1310,14 +1306,14 @@ class TestClient:
c = client.Client(reconnection=True) c = client.Client(reconnection=True)
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.eio.state = 'connected' c.eio.state = 'connected'
c._handle_eio_disconnect() c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c.start_background_task.assert_called_once_with(c._handle_reconnect) c.start_background_task.assert_called_once_with(c._handle_reconnect)
def test_eio_disconnect_self_disconnect(self): def test_eio_disconnect_self_disconnect(self):
c = client.Client(reconnection=True) c = client.Client(reconnection=True)
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.eio.state = 'disconnected' c.eio.state = 'disconnected'
c._handle_eio_disconnect() c._handle_eio_disconnect(c.reason.CLIENT_DISCONNECT)
c.start_background_task.assert_not_called() c.start_background_task.assert_not_called()
def test_eio_disconnect_no_reconnect(self): def test_eio_disconnect_no_reconnect(self):
@ -1328,9 +1324,10 @@ class TestClient:
c.start_background_task = mock.MagicMock() c.start_background_task = mock.MagicMock()
c.sid = 'foo' c.sid = 'foo'
c.eio.state = 'connected' c.eio.state = 'connected'
c._handle_eio_disconnect() c._handle_eio_disconnect(c.reason.TRANSPORT_ERROR)
c._trigger_event.assert_any_call('disconnect', namespace='/') c._trigger_event.assert_any_call('disconnect', '/',
c._trigger_event.assert_any_call('__disconnect_final', namespace='/') c.reason.TRANSPORT_ERROR)
c._trigger_event.assert_any_call('__disconnect_final', '/')
assert c.sid is None assert c.sid is None
assert not c.connected assert not c.connected
c.start_background_task.assert_not_called() c.start_background_task.assert_not_called()

39
tests/common/test_namespace.py

@ -19,13 +19,25 @@ class TestNamespace:
def test_disconnect_event(self): def test_disconnect_event(self):
result = {} result = {}
class MyNamespace(namespace.Namespace):
def on_disconnect(self, sid, reason):
result['result'] = (sid, reason)
ns = MyNamespace('/foo')
ns._set_server(mock.MagicMock())
ns.trigger_event('disconnect', 'sid', 'foo')
assert result['result'] == ('sid', 'foo')
def test_legacy_disconnect_event(self):
result = {}
class MyNamespace(namespace.Namespace): class MyNamespace(namespace.Namespace):
def on_disconnect(self, sid): def on_disconnect(self, sid):
result['result'] = sid result['result'] = sid
ns = MyNamespace('/foo') ns = MyNamespace('/foo')
ns._set_server(mock.MagicMock()) ns._set_server(mock.MagicMock())
ns.trigger_event('disconnect', 'sid') ns.trigger_event('disconnect', 'sid', 'foo')
assert result['result'] == 'sid' assert result['result'] == 'sid'
def test_event(self): def test_event(self):
@ -216,6 +228,31 @@ class TestNamespace:
ns.disconnect('sid', namespace='/bar') ns.disconnect('sid', namespace='/bar')
ns.server.disconnect.assert_called_with('sid', namespace='/bar') ns.server.disconnect.assert_called_with('sid', namespace='/bar')
def test_disconnect_event_client(self):
result = {}
class MyNamespace(namespace.ClientNamespace):
def on_disconnect(self, reason):
result['result'] = reason
ns = MyNamespace('/foo')
ns._set_client(mock.MagicMock())
ns.trigger_event('disconnect', 'foo')
assert result['result'] == 'foo'
def test_legacy_disconnect_event_client(self):
result = {}
class MyNamespace(namespace.ClientNamespace):
def on_disconnect(self):
result['result'] = 'ok'
ns = MyNamespace('/foo')
ns._set_client(mock.MagicMock())
ns.trigger_event('disconnect', 'foo')
assert result['result'] == 'ok'
def test_event_not_found_client(self): def test_event_not_found_client(self):
result = {} result = {}

Loading…
Cancel
Save