daphne/channels/tests/test_binding.py
Paul f4f45dbb9f Sort imports and make Travis run isort (#425)
* Sort imports

* Make Travis run isort
2016-11-05 12:08:38 +01:00

428 lines
16 KiB
Python

from __future__ import unicode_literals
import json
from django.contrib.auth import get_user_model
from channels import Group, route
from channels.binding.base import CREATE, DELETE, UPDATE
from channels.binding.websockets import WebsocketBinding
from channels.generic.websockets import WebsocketDemultiplexer
from channels.signals import consumer_finished
from channels.tests import ChannelTestCase, HttpClient, apply_routes
User = get_user_model()
class TestsBinding(ChannelTestCase):
def test_trigger_outbound_create(self):
class TestBinding(WebsocketBinding):
model = User
stream = 'test'
fields = ['username', 'email', 'password', 'last_name']
@classmethod
def group_names(cls, instance, action):
return ["users"]
def has_permission(self, user, action, pk):
return True
client = HttpClient()
client.join_group('users')
user = User.objects.create(username='test', email='test@test.com')
consumer_finished.send(sender=None)
received = client.receive()
self.assertTrue('payload' in received)
self.assertTrue('action' in received['payload'])
self.assertTrue('data' in received['payload'])
self.assertTrue('username' in received['payload']['data'])
self.assertTrue('email' in received['payload']['data'])
self.assertTrue('password' in received['payload']['data'])
self.assertTrue('last_name' in received['payload']['data'])
self.assertTrue('model' in received['payload'])
self.assertTrue('pk' in received['payload'])
self.assertEqual(received['payload']['action'], 'create')
self.assertEqual(received['payload']['model'], 'auth.user')
self.assertEqual(received['payload']['pk'], user.pk)
self.assertEqual(received['payload']['data']['email'], 'test@test.com')
self.assertEqual(received['payload']['data']['username'], 'test')
self.assertEqual(received['payload']['data']['password'], '')
self.assertEqual(received['payload']['data']['last_name'], '')
received = client.receive()
self.assertIsNone(received)
def test_trigger_outbound_create_exclude(self):
class TestBinding(WebsocketBinding):
model = User
stream = 'test'
exclude = ['first_name', 'last_name']
@classmethod
def group_names(cls, instance, action):
return ["users_exclude"]
def has_permission(self, user, action, pk):
return True
with apply_routes([route('test', TestBinding.consumer)]):
client = HttpClient()
client.join_group('users_exclude')
user = User.objects.create(username='test', email='test@test.com')
consumer_finished.send(sender=None)
consumer_finished.send(sender=None)
received = client.receive()
self.assertTrue('payload' in received)
self.assertTrue('action' in received['payload'])
self.assertTrue('data' in received['payload'])
self.assertTrue('username' in received['payload']['data'])
self.assertTrue('email' in received['payload']['data'])
self.assertTrue('password' in received['payload']['data'])
self.assertTrue('model' in received['payload'])
self.assertTrue('pk' in received['payload'])
self.assertFalse('last_name' in received['payload']['data'])
self.assertFalse('first_name' in received['payload']['data'])
self.assertEqual(received['payload']['action'], 'create')
self.assertEqual(received['payload']['model'], 'auth.user')
self.assertEqual(received['payload']['pk'], user.pk)
self.assertEqual(received['payload']['data']['email'], 'test@test.com')
self.assertEqual(received['payload']['data']['username'], 'test')
self.assertEqual(received['payload']['data']['password'], '')
received = client.receive()
self.assertIsNone(received)
def test_omit_fields_and_exclude(self):
def _declare_class():
class TestBinding(WebsocketBinding):
model = User
stream = 'test'
@classmethod
def group_names(cls, instance, action):
return ["users_omit"]
def has_permission(self, user, action, pk):
return True
self.assertRaises(ValueError, _declare_class)
def test_trigger_outbound_update(self):
class TestBinding(WebsocketBinding):
model = User
stream = 'test'
fields = ['__all__']
@classmethod
def group_names(cls, instance, action):
return ["users2"]
def has_permission(self, user, action, pk):
return True
# Make model and clear out pending sends
user = User.objects.create(username='test', email='test@test.com')
consumer_finished.send(sender=None)
client = HttpClient()
client.join_group('users2')
user.username = 'test_new'
user.save()
consumer_finished.send(sender=None)
received = client.receive()
self.assertTrue('payload' in received)
self.assertTrue('action' in received['payload'])
self.assertTrue('data' in received['payload'])
self.assertTrue('username' in received['payload']['data'])
self.assertTrue('email' in received['payload']['data'])
self.assertTrue('password' in received['payload']['data'])
self.assertTrue('last_name' in received['payload']['data'])
self.assertTrue('model' in received['payload'])
self.assertTrue('pk' in received['payload'])
self.assertEqual(received['payload']['action'], 'update')
self.assertEqual(received['payload']['model'], 'auth.user')
self.assertEqual(received['payload']['pk'], user.pk)
self.assertEqual(received['payload']['data']['email'], 'test@test.com')
self.assertEqual(received['payload']['data']['username'], 'test_new')
self.assertEqual(received['payload']['data']['password'], '')
self.assertEqual(received['payload']['data']['last_name'], '')
received = client.receive()
self.assertIsNone(received)
def test_trigger_outbound_delete(self):
class TestBinding(WebsocketBinding):
model = User
stream = 'test'
fields = ['username']
@classmethod
def group_names(cls, instance, action):
return ["users3"]
def has_permission(self, user, action, pk):
return True
# Make model and clear out pending sends
user = User.objects.create(username='test', email='test@test.com')
consumer_finished.send(sender=None)
client = HttpClient()
client.join_group('users3')
user.delete()
consumer_finished.send(sender=None)
received = client.receive()
self.assertTrue('payload' in received)
self.assertTrue('action' in received['payload'])
self.assertTrue('data' in received['payload'])
self.assertTrue('username' in received['payload']['data'])
self.assertTrue('model' in received['payload'])
self.assertTrue('pk' in received['payload'])
self.assertEqual(received['payload']['action'], 'delete')
self.assertEqual(received['payload']['model'], 'auth.user')
self.assertEqual(received['payload']['pk'], 1)
self.assertEqual(received['payload']['data']['username'], 'test')
received = client.receive()
self.assertIsNone(received)
def test_demultiplexer(self):
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
with apply_routes([Demultiplexer.as_route(path='/')]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
# assert in group
Group('inbound').send({'text': json.dumps({'test': 'yes'})}, immediately=True)
self.assertEqual(client.receive(), {'test': 'yes'})
# assert that demultiplexer stream message
client.send_and_consume('websocket.receive', path='/',
text={'stream': 'users', 'payload': {'test': 'yes'}})
message = client.get_next_message('binding.users')
self.assertIsNotNone(message)
self.assertEqual(message.content['test'], 'yes')
def test_demultiplexer_with_wrong_stream(self):
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
with apply_routes([Demultiplexer.as_route(path='/')]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
with self.assertRaises(ValueError) as value_error:
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'wrong', 'payload': {'test': 'yes'}
})
self.assertIn('stream not mapped', value_error.exception.args[0])
message = client.get_next_message('binding.users')
self.assertIsNone(message)
def test_demultiplexer_with_wrong_payload(self):
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
with apply_routes([Demultiplexer.as_route(path='/')]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
with self.assertRaises(ValueError) as value_error:
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users', 'payload': 'test',
})
self.assertEqual(value_error.exception.args[0], 'Multiplexed frame payload is not a dict')
message = client.get_next_message('binding.users')
self.assertIsNone(message)
def test_demultiplexer_without_payload_and_steam(self):
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
with apply_routes([Demultiplexer.as_route(path='/')]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
with self.assertRaises(ValueError) as value_error:
client.send_and_consume('websocket.receive', path='/', text={
'nostream': 'users', 'payload': 'test',
})
self.assertIn('no channel/payload key', value_error.exception.args[0])
message = client.get_next_message('binding.users')
self.assertIsNone(message)
with self.assertRaises(ValueError) as value_error:
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users',
})
self.assertIn('no channel/payload key', value_error.exception.args[0])
message = client.get_next_message('binding.users')
self.assertIsNone(message)
def test_inbound_create(self):
self.assertEqual(User.objects.all().count(), 0)
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
class UserBinding(WebsocketBinding):
model = User
stream = 'users'
fields = ['username', 'email', 'password', 'last_name']
@classmethod
def group_names(cls, instance, action):
return ['users_outbound']
def has_permission(self, user, action, pk):
return True
with apply_routes([Demultiplexer.as_route(path='/'), route('binding.users', UserBinding.consumer)]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users',
'payload': {'action': CREATE, 'data': {'username': 'test_inbound', 'email': 'test@user_steam.com'}}
})
# our Demultiplexer route message to the inbound consumer, so call Demultiplexer consumer
client.consume('binding.users')
self.assertEqual(User.objects.all().count(), 1)
user = User.objects.all().first()
self.assertEqual(user.username, 'test_inbound')
self.assertEqual(user.email, 'test@user_steam.com')
self.assertIsNone(client.receive())
def test_inbound_update(self):
user = User.objects.create(username='test', email='test@channels.com')
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
class UserBinding(WebsocketBinding):
model = User
stream = 'users'
fields = ['username', ]
@classmethod
def group_names(cls, instance, action):
return ['users_outbound']
def has_permission(self, user, action, pk):
return True
with apply_routes([Demultiplexer.as_route(path='/'), route('binding.users', UserBinding.consumer)]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users',
'payload': {'action': UPDATE, 'pk': user.pk, 'data': {'username': 'test_inbound'}}
})
# our Demultiplexer route message to the inbound consumer, so call Demultiplexer consumer
client.consume('binding.users')
user = User.objects.get(pk=user.pk)
self.assertEqual(user.username, 'test_inbound')
self.assertEqual(user.email, 'test@channels.com')
# trying change field that not in binding fields
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users',
'payload': {'action': UPDATE, 'pk': user.pk, 'data': {'email': 'new@test.com'}}
})
client.consume('binding.users')
user = User.objects.get(pk=user.pk)
self.assertEqual(user.username, 'test_inbound')
self.assertEqual(user.email, 'test@channels.com')
self.assertIsNone(client.receive())
def test_inbound_delete(self):
user = User.objects.create(username='test', email='test@channels.com')
class Demultiplexer(WebsocketDemultiplexer):
mapping = {
'users': 'binding.users',
}
groups = ['inbound']
class UserBinding(WebsocketBinding):
model = User
stream = 'users'
fields = ['username', ]
@classmethod
def group_names(cls, instance, action):
return ['users_outbound']
def has_permission(self, user, action, pk):
return True
with apply_routes([Demultiplexer.as_route(path='/'), route('binding.users', UserBinding.consumer)]):
client = HttpClient()
client.send_and_consume('websocket.connect', path='/')
client.send_and_consume('websocket.receive', path='/', text={
'stream': 'users',
'payload': {'action': DELETE, 'pk': user.pk}
})
# our Demultiplexer route message to the inbound consumer, so call Demultiplexer consumer
client.consume('binding.users')
self.assertIsNone(User.objects.filter(pk=user.pk).first())
self.assertIsNone(client.receive())