9 changed files with 1154 additions and 2 deletions
@ -0,0 +1,83 @@ |
|||||
|
import asyncio |
||||
|
|
||||
|
from socketio import namespace |
||||
|
|
||||
|
|
||||
|
class AsyncNamespace(namespace.Namespace): |
||||
|
"""Base class for asyncio class-based namespaces. |
||||
|
|
||||
|
A class-based namespace is a class that contains all the event handlers |
||||
|
for a Socket.IO namespace. The event handlers are methods of the class |
||||
|
with the prefix ``on_``, such as ``on_connect``, ``on_disconnect``, |
||||
|
``on_message``, ``on_json``, and so on. These can be regular functions or |
||||
|
coroutines. |
||||
|
|
||||
|
:param namespace: The Socket.IO namespace to be used with all the event |
||||
|
handlers defined in this class. If this argument is |
||||
|
omitted, the default namespace is used. |
||||
|
""" |
||||
|
def is_asyncio_based(self): |
||||
|
return True |
||||
|
|
||||
|
async def trigger_event(self, event, *args): |
||||
|
"""Dispatch an event to the proper handler method. |
||||
|
|
||||
|
In the most common usage, this method is not overloaded by subclasses, |
||||
|
as it performs the routing of events to methods. However, this |
||||
|
method can be overriden if special dispatching rules are needed, or if |
||||
|
having a single method that catches all events is desired. |
||||
|
|
||||
|
Note: this method is a coroutine. |
||||
|
""" |
||||
|
handler_name = 'on_' + event |
||||
|
if hasattr(self, handler_name): |
||||
|
handler = getattr(self, handler_name) |
||||
|
if asyncio.iscoroutinefunction(handler) is True: |
||||
|
try: |
||||
|
ret = await handler(*args) |
||||
|
except asyncio.CancelledError: # pragma: no cover |
||||
|
pass |
||||
|
else: |
||||
|
ret = handler(*args) |
||||
|
return ret |
||||
|
|
||||
|
async def emit(self, event, data=None, room=None, skip_sid=None, |
||||
|
namespace=None, callback=None): |
||||
|
"""Emit a custom event to one or more connected clients. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.emit` method is |
||||
|
that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
|
||||
|
Note: this method is a coroutine. |
||||
|
""" |
||||
|
return await self.server.emit(event, data=data, room=room, |
||||
|
skip_sid=skip_sid, |
||||
|
namespace=namespace or self.namespace, |
||||
|
callback=callback) |
||||
|
|
||||
|
async def send(self, data, room=None, skip_sid=None, namespace=None, |
||||
|
callback=None): |
||||
|
"""Send a message to one or more connected clients. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.send` method is |
||||
|
that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
|
||||
|
Note: this method is a coroutine. |
||||
|
""" |
||||
|
return await self.server.send(data, room=room, skip_sid=skip_sid, |
||||
|
namespace=namespace or self.namespace, |
||||
|
callback=callback) |
||||
|
|
||||
|
async def disconnect(self, sid, namespace=None): |
||||
|
"""Disconnect a client. |
||||
|
|
||||
|
The only difference with the :func:`socketio.Server.disconnect` method |
||||
|
is that when the ``namespace`` argument is not given the namespace |
||||
|
associated with the class is used. |
||||
|
|
||||
|
Note: this method is a coroutine. |
||||
|
""" |
||||
|
return await self.server.disconnect( |
||||
|
sid, namespace=namespace or self.namespace) |
@ -0,0 +1,280 @@ |
|||||
|
import sys |
||||
|
import unittest |
||||
|
|
||||
|
import six |
||||
|
if six.PY3: |
||||
|
from unittest import mock |
||||
|
else: |
||||
|
import mock |
||||
|
|
||||
|
if sys.version_info >= (3, 5): |
||||
|
import asyncio |
||||
|
from asyncio import coroutine |
||||
|
from socketio import asyncio_manager |
||||
|
else: |
||||
|
# mock coroutine so that Python 2 doesn't complain |
||||
|
def coroutine(f): |
||||
|
return f |
||||
|
|
||||
|
|
||||
|
def AsyncMock(*args, **kwargs): |
||||
|
"""Return a mock asynchronous function.""" |
||||
|
m = mock.MagicMock(*args, **kwargs) |
||||
|
|
||||
|
@coroutine |
||||
|
def mock_coro(*args, **kwargs): |
||||
|
return m(*args, **kwargs) |
||||
|
|
||||
|
mock_coro.mock = m |
||||
|
return mock_coro |
||||
|
|
||||
|
|
||||
|
def _run(coro): |
||||
|
"""Run the given coroutine.""" |
||||
|
return asyncio.get_event_loop().run_until_complete(coro) |
||||
|
|
||||
|
|
||||
|
@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') |
||||
|
class TestAsyncioManager(unittest.TestCase): |
||||
|
def setUp(self): |
||||
|
mock_server = mock.MagicMock() |
||||
|
mock_server._emit_internal = AsyncMock() |
||||
|
self.bm = asyncio_manager.AsyncioManager() |
||||
|
self.bm.set_server(mock_server) |
||||
|
self.bm.initialize() |
||||
|
|
||||
|
def test_connect(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.assertIn(None, self.bm.rooms['/foo']) |
||||
|
self.assertIn('123', self.bm.rooms['/foo']) |
||||
|
self.assertIn('123', self.bm.rooms['/foo'][None]) |
||||
|
self.assertIn('123', self.bm.rooms['/foo']['123']) |
||||
|
self.assertEqual(self.bm.rooms['/foo'], {None: {'123': True}, |
||||
|
'123': {'123': True}}) |
||||
|
|
||||
|
def test_pre_disconnect(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.pre_disconnect('123', '/foo') |
||||
|
self.assertEqual(self.bm.pending_disconnect, {'/foo': ['123']}) |
||||
|
self.assertFalse(self.bm.is_connected('123', '/foo')) |
||||
|
self.bm.pre_disconnect('456', '/foo') |
||||
|
self.assertEqual(self.bm.pending_disconnect, {'/foo': ['123', '456']}) |
||||
|
self.assertFalse(self.bm.is_connected('456', '/foo')) |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.assertEqual(self.bm.pending_disconnect, {'/foo': ['456']}) |
||||
|
self.bm.disconnect('456', '/foo') |
||||
|
self.assertEqual(self.bm.pending_disconnect, {}) |
||||
|
|
||||
|
def test_disconnect(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.enter_room('456', '/foo', 'baz') |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.assertEqual(self.bm.rooms['/foo'], {None: {'456': True}, |
||||
|
'456': {'456': True}, |
||||
|
'baz': {'456': True}}) |
||||
|
|
||||
|
def test_disconnect_default_namespace(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.assertTrue(self.bm.is_connected('123', '/')) |
||||
|
self.assertTrue(self.bm.is_connected('123', '/foo')) |
||||
|
self.bm.disconnect('123', '/') |
||||
|
self.assertFalse(self.bm.is_connected('123', '/')) |
||||
|
self.assertTrue(self.bm.is_connected('123', '/foo')) |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.assertFalse(self.bm.is_connected('123', '/foo')) |
||||
|
self.assertEqual(self.bm.rooms['/'], {None: {'456': True}, |
||||
|
'456': {'456': True}}) |
||||
|
self.assertEqual(self.bm.rooms['/foo'], {None: {'456': True}, |
||||
|
'456': {'456': True}}) |
||||
|
|
||||
|
def test_disconnect_twice(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.disconnect('123', '/') |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.bm.disconnect('123', '/') |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.assertEqual(self.bm.rooms['/'], {None: {'456': True}, |
||||
|
'456': {'456': True}}) |
||||
|
self.assertEqual(self.bm.rooms['/foo'], {None: {'456': True}, |
||||
|
'456': {'456': True}}) |
||||
|
|
||||
|
def test_disconnect_all(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.enter_room('456', '/foo', 'baz') |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.bm.disconnect('456', '/foo') |
||||
|
self.assertEqual(self.bm.rooms, {}) |
||||
|
|
||||
|
def test_disconnect_with_callbacks(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm._generate_ack_id('123', '/', 'f') |
||||
|
self.bm._generate_ack_id('123', '/foo', 'g') |
||||
|
self.bm.disconnect('123', '/foo') |
||||
|
self.assertNotIn('/foo', self.bm.callbacks['123']) |
||||
|
self.bm.disconnect('123', '/') |
||||
|
self.assertNotIn('123', self.bm.callbacks) |
||||
|
|
||||
|
def test_trigger_sync_callback(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
cb = mock.MagicMock() |
||||
|
id1 = self.bm._generate_ack_id('123', '/', cb) |
||||
|
id2 = self.bm._generate_ack_id('123', '/foo', cb) |
||||
|
_run(self.bm.trigger_callback('123', '/', id1, ['foo'])) |
||||
|
_run(self.bm.trigger_callback('123', '/foo', id2, ['bar', 'baz'])) |
||||
|
self.assertEqual(cb.call_count, 2) |
||||
|
cb.assert_any_call('foo') |
||||
|
cb.assert_any_call('bar', 'baz') |
||||
|
|
||||
|
def test_trigger_async_callback(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
cb = AsyncMock() |
||||
|
id1 = self.bm._generate_ack_id('123', '/', cb) |
||||
|
id2 = self.bm._generate_ack_id('123', '/foo', cb) |
||||
|
_run(self.bm.trigger_callback('123', '/', id1, ['foo'])) |
||||
|
_run(self.bm.trigger_callback('123', '/foo', id2, ['bar', 'baz'])) |
||||
|
self.assertEqual(cb.mock.call_count, 2) |
||||
|
cb.mock.assert_any_call('foo') |
||||
|
cb.mock.assert_any_call('bar', 'baz') |
||||
|
|
||||
|
def test_invalid_callback(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
cb = mock.MagicMock() |
||||
|
id = self.bm._generate_ack_id('123', '/', cb) |
||||
|
|
||||
|
# these should not raise an exception |
||||
|
_run(self.bm.trigger_callback('124', '/', id, ['foo'])) |
||||
|
_run(self.bm.trigger_callback('123', '/foo', id, ['foo'])) |
||||
|
_run(self.bm.trigger_callback('123', '/', id + 1, ['foo'])) |
||||
|
self.assertEqual(cb.mock.call_count, 0) |
||||
|
|
||||
|
def test_get_namespaces(self): |
||||
|
self.assertEqual(list(self.bm.get_namespaces()), []) |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('123', '/foo') |
||||
|
namespaces = list(self.bm.get_namespaces()) |
||||
|
self.assertEqual(len(namespaces), 2) |
||||
|
self.assertIn('/', namespaces) |
||||
|
self.assertIn('/foo', namespaces) |
||||
|
|
||||
|
def test_get_participants(self): |
||||
|
self.bm.connect('123', '/') |
||||
|
self.bm.connect('456', '/') |
||||
|
self.bm.connect('789', '/') |
||||
|
self.bm.disconnect('789', '/') |
||||
|
self.assertNotIn('789', self.bm.rooms['/'][None]) |
||||
|
participants = list(self.bm.get_participants('/', None)) |
||||
|
self.assertEqual(len(participants), 2) |
||||
|
self.assertNotIn('789', participants) |
||||
|
|
||||
|
def test_leave_invalid_room(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.leave_room('123', '/foo', 'baz') |
||||
|
self.bm.leave_room('123', '/bar', 'baz') |
||||
|
|
||||
|
def test_no_room(self): |
||||
|
rooms = self.bm.get_rooms('123', '/foo') |
||||
|
self.assertEqual([], rooms) |
||||
|
|
||||
|
def test_close_room(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.connect('789', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.close_room('bar', '/foo') |
||||
|
self.assertNotIn('bar', self.bm.rooms['/foo']) |
||||
|
|
||||
|
def test_close_invalid_room(self): |
||||
|
self.bm.close_room('bar', '/foo') |
||||
|
|
||||
|
def test_rooms(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
r = self.bm.get_rooms('123', '/foo') |
||||
|
self.assertEqual(len(r), 2) |
||||
|
self.assertIn('123', r) |
||||
|
self.assertIn('bar', r) |
||||
|
|
||||
|
def test_emit_to_sid(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', |
||||
|
room='123')) |
||||
|
self.bm.server._emit_internal.mock.assert_called_once_with( |
||||
|
'123', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
|
||||
|
def test_emit_to_room(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.enter_room('456', '/foo', 'bar') |
||||
|
self.bm.connect('789', '/foo') |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', |
||||
|
room='bar')) |
||||
|
self.assertEqual(self.bm.server._emit_internal.mock.call_count, 2) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'123', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'456', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
|
||||
|
def test_emit_to_all(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.enter_room('456', '/foo', 'bar') |
||||
|
self.bm.connect('789', '/foo') |
||||
|
self.bm.connect('abc', '/bar') |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo')) |
||||
|
self.assertEqual(self.bm.server._emit_internal.mock.call_count, 3) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'123', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'456', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'789', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
|
||||
|
def test_emit_to_all_skip_one(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm.enter_room('123', '/foo', 'bar') |
||||
|
self.bm.connect('456', '/foo') |
||||
|
self.bm.enter_room('456', '/foo', 'bar') |
||||
|
self.bm.connect('789', '/foo') |
||||
|
self.bm.connect('abc', '/bar') |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', |
||||
|
skip_sid='456')) |
||||
|
self.assertEqual(self.bm.server._emit_internal.mock.call_count, 2) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'123', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
self.bm.server._emit_internal.mock.assert_any_call( |
||||
|
'789', 'my event', {'foo': 'bar'}, '/foo', None) |
||||
|
|
||||
|
def test_emit_with_callback(self): |
||||
|
self.bm.connect('123', '/foo') |
||||
|
self.bm._generate_ack_id = mock.MagicMock() |
||||
|
self.bm._generate_ack_id.return_value = 11 |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', |
||||
|
callback='cb')) |
||||
|
self.bm._generate_ack_id.assert_called_once_with('123', '/foo', 'cb') |
||||
|
self.bm.server._emit_internal.mock.assert_called_once_with( |
||||
|
'123', 'my event', {'foo': 'bar'}, '/foo', 11) |
||||
|
|
||||
|
def test_emit_to_invalid_room(self): |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/', |
||||
|
room='123')) |
||||
|
|
||||
|
def test_emit_to_invalid_namespace(self): |
||||
|
_run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo')) |
@ -0,0 +1,179 @@ |
|||||
|
import sys |
||||
|
import unittest |
||||
|
|
||||
|
import six |
||||
|
if six.PY3: |
||||
|
from unittest import mock |
||||
|
else: |
||||
|
import mock |
||||
|
|
||||
|
if sys.version_info >= (3, 5): |
||||
|
import asyncio |
||||
|
from asyncio import coroutine |
||||
|
from socketio import asyncio_namespace |
||||
|
else: |
||||
|
# mock coroutine so that Python 2 doesn't complain |
||||
|
def coroutine(f): |
||||
|
return f |
||||
|
|
||||
|
|
||||
|
def AsyncMock(*args, **kwargs): |
||||
|
"""Return a mock asynchronous function.""" |
||||
|
m = mock.MagicMock(*args, **kwargs) |
||||
|
|
||||
|
@coroutine |
||||
|
def mock_coro(*args, **kwargs): |
||||
|
return m(*args, **kwargs) |
||||
|
|
||||
|
mock_coro.mock = m |
||||
|
return mock_coro |
||||
|
|
||||
|
|
||||
|
def _run(coro): |
||||
|
"""Run the given coroutine.""" |
||||
|
return asyncio.get_event_loop().run_until_complete(coro) |
||||
|
|
||||
|
|
||||
|
@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') |
||||
|
class TestAsyncNamespace(unittest.TestCase): |
||||
|
def test_connect_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
@coroutine |
||||
|
def on_connect(self, sid, environ): |
||||
|
result['result'] = (sid, environ) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
_run(ns.trigger_event('connect', 'sid', {'foo': 'bar'})) |
||||
|
self.assertEqual(result['result'], ('sid', {'foo': 'bar'})) |
||||
|
|
||||
|
def test_disconnect_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
@coroutine |
||||
|
def on_disconnect(self, sid): |
||||
|
result['result'] = sid |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
_run(ns.trigger_event('disconnect', 'sid')) |
||||
|
self.assertEqual(result['result'], 'sid') |
||||
|
|
||||
|
def test_sync_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
def on_custom_message(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
_run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) |
||||
|
self.assertEqual(result['result'], ('sid', {'data': 'data'})) |
||||
|
|
||||
|
def test_async_event(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
@coroutine |
||||
|
def on_custom_message(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
_run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) |
||||
|
self.assertEqual(result['result'], ('sid', {'data': 'data'})) |
||||
|
|
||||
|
def test_event_not_found(self): |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
@coroutine |
||||
|
def on_custom_message(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
ns = MyNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
_run(ns.trigger_event('another_custom_message', 'sid', |
||||
|
{'data': 'data'})) |
||||
|
self.assertEqual(result, {}) |
||||
|
|
||||
|
def test_emit(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
mock_server = mock.MagicMock() |
||||
|
mock_server.emit = AsyncMock() |
||||
|
ns._set_server(mock_server) |
||||
|
_run(ns.emit('ev', data='data', room='room', skip_sid='skip', |
||||
|
callback='cb')) |
||||
|
ns.server.emit.mock.assert_called_with( |
||||
|
'ev', data='data', room='room', skip_sid='skip', namespace='/foo', |
||||
|
callback='cb') |
||||
|
_run(ns.emit('ev', data='data', room='room', skip_sid='skip', |
||||
|
namespace='/bar', callback='cb')) |
||||
|
ns.server.emit.mock.assert_called_with( |
||||
|
'ev', data='data', room='room', skip_sid='skip', namespace='/bar', |
||||
|
callback='cb') |
||||
|
|
||||
|
def test_send(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
mock_server = mock.MagicMock() |
||||
|
mock_server.send = AsyncMock() |
||||
|
ns._set_server(mock_server) |
||||
|
_run(ns.send(data='data', room='room', skip_sid='skip', callback='cb')) |
||||
|
ns.server.send.mock.assert_called_with( |
||||
|
'data', room='room', skip_sid='skip', namespace='/foo', |
||||
|
callback='cb') |
||||
|
_run(ns.send(data='data', room='room', skip_sid='skip', |
||||
|
namespace='/bar', callback='cb')) |
||||
|
ns.server.send.mock.assert_called_with( |
||||
|
'data', room='room', skip_sid='skip', namespace='/bar', |
||||
|
callback='cb') |
||||
|
|
||||
|
def test_enter_room(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
ns.enter_room('sid', 'room') |
||||
|
ns.server.enter_room.assert_called_with('sid', 'room', |
||||
|
namespace='/foo') |
||||
|
ns.enter_room('sid', 'room', namespace='/bar') |
||||
|
ns.server.enter_room.assert_called_with('sid', 'room', |
||||
|
namespace='/bar') |
||||
|
|
||||
|
def test_leave_room(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
ns.leave_room('sid', 'room') |
||||
|
ns.server.leave_room.assert_called_with('sid', 'room', |
||||
|
namespace='/foo') |
||||
|
ns.leave_room('sid', 'room', namespace='/bar') |
||||
|
ns.server.leave_room.assert_called_with('sid', 'room', |
||||
|
namespace='/bar') |
||||
|
|
||||
|
def test_close_room(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
ns.close_room('room') |
||||
|
ns.server.close_room.assert_called_with('room', namespace='/foo') |
||||
|
ns.close_room('room', namespace='/bar') |
||||
|
ns.server.close_room.assert_called_with('room', namespace='/bar') |
||||
|
|
||||
|
def test_rooms(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
ns._set_server(mock.MagicMock()) |
||||
|
ns.rooms('sid') |
||||
|
ns.server.rooms.assert_called_with('sid', namespace='/foo') |
||||
|
ns.rooms('sid', namespace='/bar') |
||||
|
ns.server.rooms.assert_called_with('sid', namespace='/bar') |
||||
|
|
||||
|
def test_disconnect(self): |
||||
|
ns = asyncio_namespace.AsyncNamespace('/foo') |
||||
|
mock_server = mock.MagicMock() |
||||
|
mock_server.disconnect = AsyncMock() |
||||
|
ns._set_server(mock_server) |
||||
|
_run(ns.disconnect('sid')) |
||||
|
ns.server.disconnect.mock.assert_called_with('sid', namespace='/foo') |
||||
|
_run(ns.disconnect('sid', namespace='/bar')) |
||||
|
ns.server.disconnect.mock.assert_called_with('sid', namespace='/bar') |
@ -0,0 +1,594 @@ |
|||||
|
import json |
||||
|
import logging |
||||
|
import sys |
||||
|
import unittest |
||||
|
|
||||
|
import six |
||||
|
if six.PY3: |
||||
|
from unittest import mock |
||||
|
else: |
||||
|
import mock |
||||
|
|
||||
|
from socketio import packet |
||||
|
from socketio import namespace |
||||
|
if sys.version_info >= (3, 5): |
||||
|
import asyncio |
||||
|
from asyncio import coroutine |
||||
|
from socketio import asyncio_server |
||||
|
from socketio import asyncio_namespace |
||||
|
else: |
||||
|
# mock coroutine so that Python 2 doesn't complain |
||||
|
def coroutine(f): |
||||
|
return f |
||||
|
|
||||
|
|
||||
|
def AsyncMock(*args, **kwargs): |
||||
|
"""Return a mock asynchronous function.""" |
||||
|
m = mock.MagicMock(*args, **kwargs) |
||||
|
|
||||
|
@coroutine |
||||
|
def mock_coro(*args, **kwargs): |
||||
|
return m(*args, **kwargs) |
||||
|
|
||||
|
mock_coro.mock = m |
||||
|
return mock_coro |
||||
|
|
||||
|
|
||||
|
def _run(coro): |
||||
|
"""Run the given coroutine.""" |
||||
|
return asyncio.get_event_loop().run_until_complete(coro) |
||||
|
|
||||
|
|
||||
|
@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') |
||||
|
@mock.patch('socketio.server.engineio.AsyncServer') |
||||
|
class TestAsyncServer(unittest.TestCase): |
||||
|
def tearDown(self): |
||||
|
# restore JSON encoder, in case a test changed it |
||||
|
packet.Packet.json = json |
||||
|
|
||||
|
def _get_mock_manager(self): |
||||
|
mgr = mock.MagicMock() |
||||
|
mgr.emit = AsyncMock() |
||||
|
mgr.trigger_callback = AsyncMock() |
||||
|
return mgr |
||||
|
|
||||
|
def test_create(self, eio): |
||||
|
eio.return_value.handle_request = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr, foo='bar') |
||||
|
_run(s.handle_request({})) |
||||
|
_run(s.handle_request({})) |
||||
|
eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False}) |
||||
|
self.assertEqual(s.manager, mgr) |
||||
|
self.assertEqual(s.eio.on.call_count, 3) |
||||
|
self.assertEqual(s.binary, False) |
||||
|
self.assertEqual(s.async_handlers, False) |
||||
|
|
||||
|
def test_attach(self, eio): |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
s.attach('app', 'path') |
||||
|
eio.return_value.attach.assert_called_once_with('app', 'path') |
||||
|
|
||||
|
def test_on_event(self, eio): |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
|
||||
|
@s.on('connect') |
||||
|
def foo(): |
||||
|
pass |
||||
|
|
||||
|
def bar(): |
||||
|
pass |
||||
|
s.on('disconnect', bar) |
||||
|
s.on('disconnect', bar, namespace='/foo') |
||||
|
|
||||
|
self.assertEqual(s.handlers['/']['connect'], foo) |
||||
|
self.assertEqual(s.handlers['/']['disconnect'], bar) |
||||
|
self.assertEqual(s.handlers['/foo']['disconnect'], bar) |
||||
|
|
||||
|
def test_emit(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
_run(s.emit('my event', {'foo': 'bar'}, 'room', '123', |
||||
|
namespace='/foo', callback='cb')) |
||||
|
s.manager.emit.mock.assert_called_once_with( |
||||
|
'my event', {'foo': 'bar'}, '/foo', 'room', '123', 'cb') |
||||
|
|
||||
|
def test_emit_default_namespace(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
_run(s.emit('my event', {'foo': 'bar'}, 'room', '123', callback='cb')) |
||||
|
s.manager.emit.mock.assert_called_once_with('my event', {'foo': 'bar'}, |
||||
|
'/', 'room', '123', 'cb') |
||||
|
|
||||
|
def test_send(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
_run(s.send('foo', 'room', '123', namespace='/foo', callback='cb')) |
||||
|
s.manager.emit.mock.assert_called_once_with('message', 'foo', '/foo', |
||||
|
'room', '123', 'cb') |
||||
|
|
||||
|
def test_enter_room(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.enter_room('123', 'room', namespace='/foo') |
||||
|
s.manager.enter_room.assert_called_once_with('123', '/foo', 'room') |
||||
|
|
||||
|
def test_enter_room_default_namespace(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.enter_room('123', 'room') |
||||
|
s.manager.enter_room.assert_called_once_with('123', '/', 'room') |
||||
|
|
||||
|
def test_leave_room(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.leave_room('123', 'room', namespace='/foo') |
||||
|
s.manager.leave_room.assert_called_once_with('123', '/foo', 'room') |
||||
|
|
||||
|
def test_leave_room_default_namespace(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.leave_room('123', 'room') |
||||
|
s.manager.leave_room.assert_called_once_with('123', '/', 'room') |
||||
|
|
||||
|
def test_close_room(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.close_room('room', namespace='/foo') |
||||
|
s.manager.close_room.assert_called_once_with('room', '/foo') |
||||
|
|
||||
|
def test_close_room_default_namespace(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.close_room('room') |
||||
|
s.manager.close_room.assert_called_once_with('room', '/') |
||||
|
|
||||
|
def test_rooms(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.rooms('123', namespace='/foo') |
||||
|
s.manager.get_rooms.assert_called_once_with('123', '/foo') |
||||
|
|
||||
|
def test_rooms_default_namespace(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.rooms('123') |
||||
|
s.manager.get_rooms.assert_called_once_with('123', '/') |
||||
|
|
||||
|
def test_handle_request(self, eio): |
||||
|
eio.return_value.handle_request = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s.handle_request('environ')) |
||||
|
s.eio.handle_request.mock.assert_called_once_with('environ') |
||||
|
|
||||
|
def test_emit_internal(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._emit_internal('123', 'my event', 'my data', namespace='/foo')) |
||||
|
s.eio.send.mock.assert_called_once_with( |
||||
|
'123', '2/foo,["my event","my data"]', binary=False) |
||||
|
|
||||
|
def test_emit_internal_with_tuple(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._emit_internal('123', 'my event', ('foo', 'bar'), |
||||
|
namespace='/foo')) |
||||
|
s.eio.send.mock.assert_called_once_with( |
||||
|
'123', '2/foo,["my event","foo","bar"]', binary=False) |
||||
|
|
||||
|
def test_emit_internal_with_list(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._emit_internal('123', 'my event', ['foo', 'bar'], |
||||
|
namespace='/foo')) |
||||
|
s.eio.send.mock.assert_called_once_with( |
||||
|
'123', '2/foo,["my event",["foo","bar"]]', binary=False) |
||||
|
|
||||
|
def test_emit_internal_with_callback(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
id = s.manager._generate_ack_id('123', '/foo', 'cb') |
||||
|
_run(s._emit_internal('123', 'my event', 'my data', namespace='/foo', |
||||
|
id=id)) |
||||
|
s.eio.send.mock.assert_called_once_with( |
||||
|
'123', '2/foo,1["my event","my data"]', binary=False) |
||||
|
|
||||
|
def test_emit_internal_default_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._emit_internal('123', 'my event', 'my data')) |
||||
|
s.eio.send.mock.assert_called_once_with( |
||||
|
'123', '2["my event","my data"]', binary=False) |
||||
|
|
||||
|
def test_emit_internal_binary(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer(binary=True) |
||||
|
_run(s._emit_internal('123', u'my event', b'my binary data')) |
||||
|
self.assertEqual(s.eio.send.mock.call_count, 2) |
||||
|
|
||||
|
def test_transport(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
s.eio.transport = mock.MagicMock(return_value='polling') |
||||
|
_run(s._handle_eio_connect('foo', 'environ')) |
||||
|
self.assertEqual(s.transport('foo'), 'polling') |
||||
|
s.eio.transport.assert_called_once_with('foo') |
||||
|
|
||||
|
def test_handle_connect(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('connect', handler) |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
handler.assert_called_once_with('123', 'environ') |
||||
|
s.manager.connect.assert_called_once_with('123', '/') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '0', binary=False) |
||||
|
self.assertEqual(mgr.initialize.call_count, 1) |
||||
|
_run(s._handle_eio_connect('456', 'environ')) |
||||
|
self.assertEqual(mgr.initialize.call_count, 1) |
||||
|
|
||||
|
def test_handle_connect_async(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = AsyncMock() |
||||
|
s.on('connect', handler) |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
handler.mock.assert_called_once_with('123', 'environ') |
||||
|
s.manager.connect.assert_called_once_with('123', '/') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '0', binary=False) |
||||
|
self.assertEqual(mgr.initialize.call_count, 1) |
||||
|
_run(s._handle_eio_connect('456', 'environ')) |
||||
|
self.assertEqual(mgr.initialize.call_count, 1) |
||||
|
|
||||
|
def test_handle_connect_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('connect', handler, namespace='/foo') |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
handler.assert_called_once_with('123', 'environ') |
||||
|
s.manager.connect.assert_any_call('123', '/') |
||||
|
s.manager.connect.assert_any_call('123', '/foo') |
||||
|
s.eio.send.mock.assert_any_call('123', '0/foo', binary=False) |
||||
|
|
||||
|
def test_handle_connect_rejected(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock(return_value=False) |
||||
|
s.on('connect', handler) |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
handler.assert_called_once_with('123', 'environ') |
||||
|
self.assertEqual(s.manager.connect.call_count, 1) |
||||
|
self.assertEqual(s.manager.disconnect.call_count, 1) |
||||
|
s.eio.send.mock.assert_called_once_with('123', '4', binary=False) |
||||
|
|
||||
|
def test_handle_connect_namespace_rejected(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock(return_value=False) |
||||
|
s.on('connect', handler, namespace='/foo') |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
self.assertEqual(s.manager.connect.call_count, 2) |
||||
|
self.assertEqual(s.manager.disconnect.call_count, 1) |
||||
|
s.eio.send.mock.assert_any_call('123', '4/foo', binary=False) |
||||
|
|
||||
|
def test_handle_disconnect(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('disconnect', handler) |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_disconnect('123')) |
||||
|
handler.assert_called_once_with('123') |
||||
|
s.manager.disconnect.assert_called_once_with('123', '/') |
||||
|
self.assertEqual(s.environ, {}) |
||||
|
|
||||
|
def test_handle_disconnect_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.manager.get_namespaces = mock.MagicMock(return_value=['/', '/foo']) |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('disconnect', handler) |
||||
|
handler_namespace = mock.MagicMock() |
||||
|
s.on('disconnect', handler_namespace, namespace='/foo') |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
_run(s._handle_eio_disconnect('123')) |
||||
|
handler.assert_called_once_with('123') |
||||
|
handler_namespace.assert_called_once_with('123') |
||||
|
self.assertEqual(s.environ, {}) |
||||
|
|
||||
|
def test_handle_disconnect_only_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.manager.get_namespaces = mock.MagicMock(return_value=['/', '/foo']) |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('disconnect', handler) |
||||
|
handler_namespace = mock.MagicMock() |
||||
|
s.on('disconnect', handler_namespace, namespace='/foo') |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
_run(s._handle_eio_message('123', '1/foo')) |
||||
|
self.assertEqual(handler.call_count, 0) |
||||
|
handler_namespace.assert_called_once_with('123') |
||||
|
self.assertEqual(s.environ, {'123': 'environ'}) |
||||
|
|
||||
|
def test_handle_disconnect_unknown_client(self, eio): |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
_run(s._handle_eio_disconnect('123')) |
||||
|
|
||||
|
def test_handle_event(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
handler = AsyncMock() |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '2["my message","a","b","c"]')) |
||||
|
handler.mock.assert_called_once_with('123', 'a', 'b', 'c') |
||||
|
|
||||
|
def test_handle_event_with_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('my message', handler, namespace='/foo') |
||||
|
_run(s._handle_eio_message('123', '2/foo,["my message","a","b","c"]')) |
||||
|
handler.assert_called_once_with('123', 'a', 'b', 'c') |
||||
|
|
||||
|
def test_handle_event_binary(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
handler = mock.MagicMock() |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '52-["my message","a",' |
||||
|
'{"_placeholder":true,"num":1},' |
||||
|
'{"_placeholder":true,"num":0}]')) |
||||
|
_run(s._handle_eio_message('123', b'foo')) |
||||
|
_run(s._handle_eio_message('123', b'bar')) |
||||
|
handler.assert_called_once_with('123', 'a', b'bar', b'foo') |
||||
|
|
||||
|
def test_handle_event_binary_ack(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
s.manager.initialize(s) |
||||
|
_run(s._handle_eio_message('123', '61-321["my message","a",' |
||||
|
'{"_placeholder":true,"num":0}]')) |
||||
|
_run(s._handle_eio_message('123', b'foo')) |
||||
|
mgr.trigger_callback.mock.assert_called_once_with( |
||||
|
'123', '/', 321, ['my message', 'a', b'foo']) |
||||
|
|
||||
|
def test_handle_event_with_ack(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
handler = mock.MagicMock(return_value='foo') |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '21000["my message","foo"]')) |
||||
|
handler.assert_called_once_with('123', 'foo') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '31000["foo"]', |
||||
|
binary=False) |
||||
|
|
||||
|
def test_handle_event_with_ack_none(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
handler = mock.MagicMock(return_value=None) |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '21000["my message","foo"]')) |
||||
|
handler.assert_called_once_with('123', 'foo') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '31000[]', |
||||
|
binary=False) |
||||
|
|
||||
|
def test_handle_event_with_ack_tuple(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock(return_value=(1, '2', True)) |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '21000["my message","a","b","c"]')) |
||||
|
handler.assert_called_once_with('123', 'a', 'b', 'c') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '31000[1,"2",true]', |
||||
|
binary=False) |
||||
|
|
||||
|
def test_handle_event_with_ack_list(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr) |
||||
|
handler = mock.MagicMock(return_value=[1, '2', True]) |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '21000["my message","a","b","c"]')) |
||||
|
handler.assert_called_once_with('123', 'a', 'b', 'c') |
||||
|
s.eio.send.mock.assert_called_once_with('123', '31000[[1,"2",true]]', |
||||
|
binary=False) |
||||
|
|
||||
|
def test_handle_event_with_ack_binary(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
mgr = self._get_mock_manager() |
||||
|
s = asyncio_server.AsyncServer(client_manager=mgr, binary=True) |
||||
|
handler = mock.MagicMock(return_value=b'foo') |
||||
|
s.on('my message', handler) |
||||
|
_run(s._handle_eio_message('123', '21000["my message","foo"]')) |
||||
|
handler.assert_any_call('123', 'foo') |
||||
|
|
||||
|
def test_handle_error_packet(self, eio): |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
self.assertRaises(ValueError, _run, s._handle_eio_message('123', '4')) |
||||
|
|
||||
|
def test_handle_invalid_packet(self, eio): |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
self.assertRaises(ValueError, _run, s._handle_eio_message('123', '9')) |
||||
|
|
||||
|
def test_send_with_ack(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
cb = mock.MagicMock() |
||||
|
id1 = s.manager._generate_ack_id('123', '/', cb) |
||||
|
id2 = s.manager._generate_ack_id('123', '/', cb) |
||||
|
_run(s._emit_internal('123', 'my event', ['foo'], id=id1)) |
||||
|
_run(s._emit_internal('123', 'my event', ['bar'], id=id2)) |
||||
|
_run(s._handle_eio_message('123', '31["foo",2]')) |
||||
|
cb.assert_called_once_with('foo', 2) |
||||
|
|
||||
|
def test_send_with_ack_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
cb = mock.MagicMock() |
||||
|
id = s.manager._generate_ack_id('123', '/foo', cb) |
||||
|
_run(s._emit_internal('123', 'my event', ['foo'], namespace='/foo', |
||||
|
id=id)) |
||||
|
_run(s._handle_eio_message('123', '3/foo,1["foo",2]')) |
||||
|
cb.assert_called_once_with('foo', 2) |
||||
|
|
||||
|
def test_disconnect(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s.disconnect('123')) |
||||
|
s.eio.send.mock.assert_any_call('123', '1', binary=False) |
||||
|
|
||||
|
def test_disconnect_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
_run(s.disconnect('123', namespace='/foo')) |
||||
|
s.eio.send.mock.assert_any_call('123', '1/foo', binary=False) |
||||
|
|
||||
|
def test_disconnect_twice(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s.disconnect('123')) |
||||
|
calls = s.eio.send.mock.call_count |
||||
|
_run(s.disconnect('123')) |
||||
|
self.assertEqual(calls, s.eio.send.mock.call_count) |
||||
|
|
||||
|
def test_disconnect_twice_namespace(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
_run(s.disconnect('123', namespace='/foo')) |
||||
|
calls = s.eio.send.mock.call_count |
||||
|
_run(s.disconnect('123', namespace='/foo')) |
||||
|
self.assertEqual(calls, s.eio.send.mock.call_count) |
||||
|
|
||||
|
def test_namespace_handler(self, eio): |
||||
|
eio.return_value.send = AsyncMock() |
||||
|
result = {} |
||||
|
|
||||
|
class MyNamespace(asyncio_namespace.AsyncNamespace): |
||||
|
def on_connect(self, sid, environ): |
||||
|
result['result'] = (sid, environ) |
||||
|
|
||||
|
@coroutine |
||||
|
def on_disconnect(self, sid): |
||||
|
result['result'] = ('disconnect', sid) |
||||
|
|
||||
|
@coroutine |
||||
|
def on_foo(self, sid, data): |
||||
|
result['result'] = (sid, data) |
||||
|
|
||||
|
def on_bar(self, sid): |
||||
|
result['result'] = 'bar' |
||||
|
|
||||
|
@coroutine |
||||
|
def on_baz(self, sid, data1, data2): |
||||
|
result['result'] = (data1, data2) |
||||
|
|
||||
|
s = asyncio_server.AsyncServer() |
||||
|
s.register_namespace(MyNamespace('/foo')) |
||||
|
_run(s._handle_eio_connect('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '0/foo')) |
||||
|
self.assertEqual(result['result'], ('123', 'environ')) |
||||
|
_run(s._handle_eio_message('123', '2/foo,["foo","a"]')) |
||||
|
self.assertEqual(result['result'], ('123', 'a')) |
||||
|
_run(s._handle_eio_message('123', '2/foo,["bar"]')) |
||||
|
self.assertEqual(result['result'], 'bar') |
||||
|
_run(s._handle_eio_message('123', '2/foo,["baz","a","b"]')) |
||||
|
self.assertEqual(result['result'], ('a', 'b')) |
||||
|
_run(s.disconnect('123', '/foo')) |
||||
|
self.assertEqual(result['result'], ('disconnect', '123')) |
||||
|
|
||||
|
def test_bad_namespace_handler(self, eio): |
||||
|
class Dummy(object): |
||||
|
pass |
||||
|
|
||||
|
class SyncNS(namespace.Namespace): |
||||
|
pass |
||||
|
|
||||
|
s = asyncio_server.AsyncServer() |
||||
|
self.assertRaises(ValueError, s.register_namespace, 123) |
||||
|
self.assertRaises(ValueError, s.register_namespace, Dummy) |
||||
|
self.assertRaises(ValueError, s.register_namespace, Dummy()) |
||||
|
self.assertRaises(ValueError, s.register_namespace, |
||||
|
namespace.Namespace) |
||||
|
self.assertRaises(ValueError, s.register_namespace, SyncNS()) |
||||
|
|
||||
|
def test_logger(self, eio): |
||||
|
s = asyncio_server.AsyncServer(logger=False) |
||||
|
self.assertEqual(s.logger.getEffectiveLevel(), logging.ERROR) |
||||
|
s.logger.setLevel(logging.NOTSET) |
||||
|
s = asyncio_server.AsyncServer(logger=True) |
||||
|
self.assertEqual(s.logger.getEffectiveLevel(), logging.INFO) |
||||
|
s.logger.setLevel(logging.WARNING) |
||||
|
s = asyncio_server.AsyncServer(logger=True) |
||||
|
self.assertEqual(s.logger.getEffectiveLevel(), logging.WARNING) |
||||
|
s.logger.setLevel(logging.NOTSET) |
||||
|
s = asyncio_server.AsyncServer(logger='foo') |
||||
|
self.assertEqual(s.logger, 'foo') |
||||
|
|
||||
|
def test_engineio_logger(self, eio): |
||||
|
asyncio_server.AsyncServer(engineio_logger='foo') |
||||
|
eio.assert_called_once_with(**{'logger': 'foo', |
||||
|
'async_handlers': False}) |
||||
|
|
||||
|
def test_custom_json(self, eio): |
||||
|
# Warning: this test cannot run in parallel with other tests, as it |
||||
|
# changes the JSON encoding/decoding functions |
||||
|
|
||||
|
class CustomJSON(object): |
||||
|
@staticmethod |
||||
|
def dumps(*args, **kwargs): |
||||
|
return '*** encoded ***' |
||||
|
|
||||
|
@staticmethod |
||||
|
def loads(*args, **kwargs): |
||||
|
return '+++ decoded +++' |
||||
|
|
||||
|
asyncio_server.AsyncServer(json=CustomJSON) |
||||
|
eio.assert_called_once_with(**{'json': CustomJSON, |
||||
|
'async_handlers': False}) |
||||
|
|
||||
|
pkt = packet.Packet(packet_type=packet.EVENT, |
||||
|
data={six.text_type('foo'): six.text_type('bar')}) |
||||
|
self.assertEqual(pkt.encode(), '2*** encoded ***') |
||||
|
pkt2 = packet.Packet(encoded_packet=pkt.encode()) |
||||
|
self.assertEqual(pkt2.data, '+++ decoded +++') |
||||
|
|
||||
|
# restore the default JSON module |
||||
|
packet.Packet.json = json |
||||
|
|
||||
|
def test_start_background_task(self, eio): |
||||
|
eio.return_value.start_background_task = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s.start_background_task('foo', 'bar', baz='baz')) |
||||
|
s.eio.start_background_task.mock.assert_called_once_with('foo', 'bar', |
||||
|
baz='baz') |
||||
|
|
||||
|
def test_sleep(self, eio): |
||||
|
eio.return_value.sleep = AsyncMock() |
||||
|
s = asyncio_server.AsyncServer() |
||||
|
_run(s.sleep(1.23)) |
||||
|
s.eio.sleep.mock.assert_called_once_with(1.23) |
Loading…
Reference in new issue