Skip to content

Commit

Permalink
Improvements for test client (django#613)
Browse files Browse the repository at this point in the history
* Tests for httpclient sending content

* Testing ordered consumers

* Added docs

* Added testing for ordering

* Added GET params at HttpClient

* Remove blank line

* Fix py3 bites

* Test Client now support ChannelSocketException

* Fix flake and isort

* Conflict resolution
  • Loading branch information
Krukov authored and andrewgodwin committed Apr 19, 2017
1 parent b7ea0b9 commit fa413af
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 4 deletions.
3 changes: 3 additions & 0 deletions channels/test/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .. import DEFAULT_CHANNEL_LAYER
from ..asgi import ChannelLayerWrapper, channel_layers
from ..channel import Group
from ..exceptions import ChannelSocketException
from ..message import Message
from ..routing import Router, include
from ..signals import consumer_finished, consumer_started
Expand Down Expand Up @@ -134,6 +135,8 @@ def consume(self, channel, fail_on_none=True):
try:
consumer_started.send(sender=self.__class__)
return consumer(message, **kwargs)
except ChannelSocketException as e:
e.run(message)
finally:
# Copy Django's workaround so we don't actually close DB conns
consumer_finished.disconnect(close_old_connections)
Expand Down
28 changes: 25 additions & 3 deletions channels/test/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ class WSClient(Client):
"""

def __init__(self, **kwargs):
self._ordered = kwargs.pop('ordered', False)
super(WSClient, self).__init__(**kwargs)
self._session = None
self._headers = {}
self._cookies = {}
self._session_cookie = True
self.order = 0

def set_cookie(self, key, value):
"""
Expand Down Expand Up @@ -76,18 +78,38 @@ def send(self, to, content={}, text=None, path='/'):
Send a message to a channel.
Adds reply_channel name and channel_session to the message.
"""
if to != 'websocket.connect' and '?' in path:
path = path.split('?')[0]
self.channel_layer.send(to, self._get_content(content, text, path))
self._session_cookie = False

def _get_content(self, content={}, text=None, path='/'):
content = copy.deepcopy(content)
content.setdefault('reply_channel', self.reply_channel)
content.setdefault('path', path)

if '?' in path:
path, query_string = path.split('?')
content.setdefault('path', path)
content.setdefault('query_string', query_string)
else:
content.setdefault('path', path)

content.setdefault('headers', self.headers)

if self._ordered:
if 'order' in content:
raise ValueError('Do not use "order" manually with "ordered=True"')
content['order'] = self.order
self.order += 1

text = text or content.get('text', None)

if text is not None:
if not isinstance(text, six.string_types):
content['text'] = json.dumps(text)
else:
content['text'] = text
self.channel_layer.send(to, content)
self._session_cookie = False
return content

def send_and_consume(self, channel, content={}, text=None, path='/', fail_on_none=True, check_accept=True):
"""
Expand Down
20 changes: 20 additions & 0 deletions docs/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,26 @@ may call ``WSClient.force_login`` (like at django client) with the user object.
``receive`` method by default trying to deserialize json text content of a message,
so if you need to pass decoding use ``receive(json=False)``, like in the example.

For testing consumers with ``enforce_ordering`` initialize ``HttpClient`` with ``ordered``
flag, but if you wanna use your own order don't use it, use content::

client = HttpClient(ordered=True)
client.send_and_consume('websocket.receive', text='1', path='/ws') # order = 0
client.send_and_consume('websocket.receive', text='2', path='/ws') # order = 1
client.send_and_consume('websocket.receive', text='3', path='/ws') # order = 2

# manually
client = HttpClient()
client.send('websocket.receive', content={'order': 0}, text='1')
client.send('websocket.receive', content={'order': 2}, text='2')
client.send('websocket.receive', content={'order': 1}, text='3')

# calling consume 4 time for `waiting` message with order 1
client.consume('websocket.receive')
client.consume('websocket.receive')
client.consume('websocket.receive')
client.consume('websocket.receive')


Applying routes
---------------
Expand Down
101 changes: 100 additions & 1 deletion tests/test_wsclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

from django.http.cookie import parse_cookie

from channels.test import ChannelTestCase, WSClient
from channels import route
from channels.exceptions import ChannelSocketException
from channels.handler import AsgiRequest
from channels.test import ChannelTestCase, WSClient, apply_routes
from channels.sessions import enforce_ordering


class WSClientTests(ChannelTestCase):
Expand All @@ -22,3 +26,98 @@ def test_cookies(self):
'qux': 'qu;x',
'sessionid': client.get_cookies()['sessionid']},
cookie_dict)

def test_simple_content(self):
client = WSClient()
content = client._get_content(text={'key': 'value'}, path='/my/path')

self.assertEqual(content['text'], '{"key": "value"}')
self.assertEqual(content['path'], '/my/path')
self.assertTrue('reply_channel' in content)
self.assertTrue('headers' in content)

def test_path_in_content(self):
client = WSClient()
content = client._get_content(content={'path': '/my_path'}, text={'path': 'hi'}, path='/my/path')

self.assertEqual(content['text'], '{"path": "hi"}')
self.assertEqual(content['path'], '/my_path')
self.assertTrue('reply_channel' in content)
self.assertTrue('headers' in content)

def test_session_in_headers(self):
client = WSClient()
content = client._get_content()
self.assertTrue('path' in content)
self.assertEqual(content['path'], '/')

self.assertTrue('headers' in content)
self.assertTrue('cookie' in content['headers'])
self.assertTrue(b'sessionid' in content['headers']['cookie'])

def test_ordering_in_content(self):
client = WSClient(ordered=True)
content = client._get_content()
self.assertTrue('order' in content)
self.assertEqual(content['order'], 0)
client.order = 2
content = client._get_content()
self.assertTrue('order' in content)
self.assertEqual(content['order'], 2)

def test_ordering(self):

client = WSClient(ordered=True)

@enforce_ordering
def consumer(message):
message.reply_channel.send({'text': message['text']})

with apply_routes(route('websocket.receive', consumer)):
client.send_and_consume('websocket.receive', text='1') # order = 0
client.send_and_consume('websocket.receive', text='2') # order = 1
client.send_and_consume('websocket.receive', text='3') # order = 2

self.assertEqual(client.receive(), 1)
self.assertEqual(client.receive(), 2)
self.assertEqual(client.receive(), 3)

def test_get_params(self):
client = WSClient()
content = client._get_content(path='/my/path?test=1&token=2')
self.assertTrue('path' in content)
self.assertTrue('query_string' in content)
self.assertEqual(content['path'], '/my/path')
self.assertEqual(content['query_string'], 'test=1&token=2')

def test_get_params_with_consumer(self):
client = WSClient(ordered=True)

def consumer(message):
message.content['method'] = 'FAKE'
message.reply_channel.send({'text': dict(AsgiRequest(message).GET)})

with apply_routes([route('websocket.receive', consumer, path=r'^/test'),
route('websocket.connect', consumer, path=r'^/test')]):
path = '/test?key1=val1&key2=val2&key1=val3'
client.send_and_consume('websocket.connect', path=path, check_accept=False)
self.assertDictEqual(client.receive(), {'key2': ['val2'], 'key1': ['val1', 'val3']})

client.send_and_consume('websocket.receive', path=path)
self.assertDictEqual(client.receive(), {})

def test_channel_socket_exception(self):

class MyChannelSocketException(ChannelSocketException):

def run(self, message):
message.reply_channel.send({'text': 'error'})

def consumer(message):
raise MyChannelSocketException

client = WSClient()
with apply_routes(route('websocket.receive', consumer)):
client.send_and_consume('websocket.receive')

self.assertEqual(client.receive(json=False), 'error')

0 comments on commit fa413af

Please sign in to comment.