def test_receive_online_success(self): slave = SlaveOnlineFactory(online=False) expected_status = Status.ok({'method': 'online'}) expected_status.uuid = slave.command_uuid # connect webinterface on /notifications webinterface = WSClient() webinterface.join_group('notifications') # send online answer ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': expected_status.to_json()}, ) self.assertTrue(SlaveModel.objects.get(id=slave.id).is_online) # test if a connected message was send on /notifications self.assertEqual( Status.ok({ 'slave_status': 'connected', 'sid': str(slave.id), }), Status.from_json(json.dumps(webinterface.receive())), )
def test_room_join_with_wrong_room_id(self): client = WSClient() client.login(username='******', password='******') client.send_and_consume('websocket.connect', path='/api/websocket/') client.receive() data = { 'room_id': 'room3', } req = request('room-join', data, nonce='test') client.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) response = client.receive() player_room_cache = cache.get('player-room:skystar1') self.assertFalse(response['success']) self.assertEqual(response['error']['reason'], 'Room does not exist') self.assertIsNone(player_room_cache)
def test_receive_online_with_error_status(self): slave = SlaveOnlineFactory(online=False) error_status = Status.err({ 'method': 'online', 'result': str(Exception('foobar')) }) error_status.uuid = slave.command_uuid # connect webinterface on /notifications webinterface = WSClient() webinterface.join_group('notifications') # send online answer ws_client = WSClient() ws_client.send_and_consume('websocket.receive', path='/commands', content={'text': error_status.to_json()}) self.assertFalse(SlaveModel.objects.get(id=slave.id).is_online) # test if a connected message was send on /notifications self.assertEqual( Status.err( 'An error occurred while connecting to client {}!'.format( slave.name)), Status.from_json(json.dumps(webinterface.receive())), )
def test_inbound_delete(self): user = User.objects.create(username='******', email='*****@*****.**') class UserBinding(WebsocketBinding): model = User stream = 'users' fields = ['username', ] @classmethod def group_names(cls, instance): return ['users_outbound'] def has_permission(self, user, action, pk): return True class Demultiplexer(WebsocketDemultiplexer): consumers = { 'users': UserBinding.consumer, } groups = ['inbound'] with apply_routes([Demultiplexer.as_route(path='/')]): client = WSClient() client.send_and_consume('websocket.connect', path='/') client.send_and_consume('websocket.receive', path='/', text={ 'stream': 'users', 'payload': {'action': DELETE, 'pk': user.pk} }) self.assertIsNone(User.objects.filter(pk=user.pk).first()) self.assertIsNone(client.receive())
def test_receives_messages(self): client = WSClient() user = UserFactory() author = UserFactory() # join a conversation conversation = ConversationFactory() conversation.join(user) conversation.join(author) # login and connect client.force_login(user) client.send_and_consume('websocket.connect', path='/') # add a message to the conversation message = ConversationMessage.objects.create(conversation=conversation, content='yay', author=author) # hopefully they receive it! response = client.receive(json=True) response['payload']['created_at'] = parse(response['payload']['created_at']) self.assertEqual(response, { 'topic': 'conversations:message', 'payload': { 'id': message.id, 'content': message.content, 'author': message.author.id, 'conversation': conversation.id, 'created_at': message.created_at } })
def test_receive_execute_success(self): program_status = ProgramStatusFactory(running=True) program = program_status.program expected_status = Status.ok({'method': 'execute', 'result': 0}) expected_status.uuid = program_status.command_uuid # connect webinterface webinterface = WSClient() webinterface.send_and_consume( 'websocket.connect', path='/notifications', ) ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': expected_status.to_json()}, ) query = ProgramStatusModel.objects.filter(program=program, code=0) self.assertTrue(query.count() == 1) self.assertFalse(query.first().running) # test if the webinterface gets the "finished" message self.assertEqual( Status.ok({ 'program_status': 'finished', 'pid': str(program.id), 'code': 0, }), Status.from_json(json.dumps(webinterface.receive())), )
def test_receive_execute_with_error_status(self): program_status = ProgramStatusFactory(running=True) program = program_status.program error_status = Status.err({ 'method': 'execute', 'result': str(Exception('foobar')), }) error_status.uuid = program_status.command_uuid # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_status.to_json()}, ) query = ProgramStatusModel.objects.get(program=program) self.assertFalse(query.running) self.assertEqual(query.code, 'foobar') # test if the webinterface gets the error message self.assertEqual( Status.ok({ 'program_status': 'finished', 'pid': str(program.id), 'code': 'foobar', }), Status.from_json(json.dumps(webinterface.receive())), )
def test_receive_execute_slave_not_exists(self): program_status = ProgramStatusFactory(running=True) program = program_status.program expected_status = Status.ok({'method': 'execute', 'result': 0}) expected_status.uuid = program_status.command_uuid # connect webinterface webinterface = WSClient() webinterface.send_and_consume( 'websocket.connect', path='/notifications', ) program.delete() ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': expected_status.to_json()}, ) self.assertFalse( ProgramStatusModel.objects.filter(program=program).exists()) # test if the webinterface gets the "finished" message self.assertIsNone(webinterface.receive())
def test_receive_get_log_success(self): program_status = ProgramStatusFactory(running=True) program = program_status.program error_status = Status.ok({ 'method': 'get_log', 'result': { 'log': 'this is the content of a logfile', 'uuid': program_status.command_uuid, }, }) # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_status.to_json()}, ) # test if the webinterface gets the error message self.assertEqual( Status.ok({ 'log': 'this is the content of a logfile', 'pid': str(program.id), }), Status.from_json(json.dumps(webinterface.receive())), )
def test_receive_get_log_program_not_exists(self): error_status = Status.ok({ 'method': 'get_log', 'result': { 'log': '', 'uuid': '0' }, }) # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_status.to_json()}, ) # test if the webinterface gets the error message self.assertEqual( Status.err('Received log from unknown program!'), Status.from_json(json.dumps(webinterface.receive())), )
def test_receive_filesystem_moved_success(self): filesystem = FileFactory() moved = MovedFileFactory.build() error_status = Status.ok({ 'method': 'filesystem_move', 'result': moved.hash_value, }) error_status.uuid = filesystem.command_uuid # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_status.to_json()}, ) query = FilesystemModel.objects.get(id=filesystem.id) self.assertEqual(query.hash_value, moved.hash_value) self.assertEqual(query.error_code, "") self.assertEqual( Status.ok({ 'filesystem_status': 'moved', 'fid': str(filesystem.id), }), Status.from_json(json.dumps(webinterface.receive())), )
class FinishedPickupReceiverTest(ChannelTestCase): def setUp(self): self.client = WSClient() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.pickup = PickupDateFactory(store=self.store, collectors=[self.member]) def test_receive_feedback_possible_and_history(self): self.pickup.date = timezone.now() - relativedelta(days=1) self.pickup.save() self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') call_command('process_finished_pickup_dates') response = self.client.receive(json=True) self.assertEqual(response['topic'], 'history:history') self.assertEqual(response['payload']['typus'], 'PICKUP_DONE') response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:feedback_possible') self.assertEqual(response['payload']['id'], self.pickup.id) self.assertIsNone(self.client.receive(json=True))
def test_receive_no_content(self): ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', ) self.assertIsNone(ws_client.receive())
def test_connection_session_duplication(self): first_client = WSClient() second_client = WSClient() first_client.login(username='******', password='******') second_client.login(username='******', password='******') first_client.send_and_consume('websocket.connect', path='/api/websocket/') session_cache = cache.get('session:skystar') self.assertIsNotNone(session_cache) second_client.send_and_consume('websocket.connect', path='/api/websocket/') response = second_client.receive() self.assertIn('event', response) self.assertEqual(response['data']['reason'], 'Session duplication detected') self.assertEqual(response['data']['type'], 'connection-dup') response = second_client.receive() self.assertEqual(response['close'], 4001) self.assertEqual(cache.get('session:skystar'), session_cache)
def test_receive_filesystem_restore_with_error_code(self): filesystem = MovedFileFactory() error_code = 'any kind of string' error_status = Status.err({ 'method': 'filesystem_restore', 'result': error_code, }) error_status.uuid = filesystem.command_uuid # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_status.to_json()}, ) query = FilesystemModel.objects.get(id=filesystem.id) self.assertEqual(query.error_code, error_code) self.assertEqual( Status.ok({ 'filesystem_status': 'error', 'fid': str(filesystem.id), 'error_code': error_code, }), Status.from_json(json.dumps(webinterface.receive())), )
def test_simple_as_route_method(self): class WebsocketConsumer(websockets.WebsocketConsumer): def connect(self, message, **kwargs): self.message.reply_channel.send({'accept': True}) self.send(text=message.get('order')) routes = [ WebsocketConsumer.as_route(attrs={"strict_ordering": True}, path='^/path$'), WebsocketConsumer.as_route(path='^/path/2$'), ] self.assertIsNot(routes[0].consumer, WebsocketConsumer) self.assertIs(routes[1].consumer, WebsocketConsumer) with apply_routes(routes): client = WSClient() client.send('websocket.connect', {'path': '/path', 'order': 1}) client.send('websocket.connect', {'path': '/path', 'order': 0}) client.consume('websocket.connect', check_accept=False) client.consume('websocket.connect') self.assertEqual(client.receive(json=False), 0) client.consume('websocket.connect') self.assertEqual(client.receive(json=False), 1) client.send_and_consume('websocket.connect', { 'path': '/path/2', 'order': 'next' }) self.assertEqual(client.receive(json=False), 'next')
def test_room_join_with_password(self): client = WSClient() client.login(username='******', password='******') client.send_and_consume('websocket.connect', path='/api/websocket/') client.receive() data = {'room_id': 'room2', 'password': '******'} req = request('room-join', data, nonce='test') client.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) response = client.receive() room_cache = cache.get('room:room2') player_room_cache = cache.get('player-room:skystar1') self.assertTrue(response['success']) result = response['result'] self.assertEqual(result['room_id'], 'room2') self.assertEqual(result['room_id'], player_room_cache) self.assertEqual(len(room_cache['players']), 1) self.assertEqual(room_cache['players'][0]['username'], 'skystar1')
def test_websockets_demultiplexer_custom_multiplexer(self): class MyWebsocketConsumer(websockets.JsonWebsocketConsumer): def connect(self, message, multiplexer=None, **kwargs): multiplexer.send({"THIS_SHOULD_BE_LOWERCASED": "1"}) class MyMultiplexer(websockets.WebsocketMultiplexer): @classmethod def encode_json(cls, content): lowered = { "stream": content["stream"], "payload": dict((key.lower(), content["payload"][key]) for key in content["payload"]) } return json.dumps(lowered) class Demultiplexer(websockets.WebsocketDemultiplexer): multiplexer_class = MyMultiplexer consumers = {"mystream": MyWebsocketConsumer} with apply_routes( [route_class(Demultiplexer, path='/path/(?P<ID>\d+)')]): client = WSClient() client.send_and_consume('websocket.connect', path='/path/1') self.assertEqual( client.receive(), { "stream": "mystream", "payload": { "this_should_be_lowercased": "1" }, })
def test_submit_card(self): client = WSClient() client.send_and_consume( 'websocket.connect', path='/game/' ) # Connect is forwarded to ALL multiplexed consumers under this demultiplexer while client.receive(): pass # Grab connection success message from each consumer # Invalid Test client.send_and_consume( 'websocket.receive', path='/game/', text={ 'stream': 'submit_card', 'payload': { 'game_code': '1234' } }) # Text arg is JSON as if it came from browser receive_reply = client.receive( ) # receive() grabs the content of the next message off of the client's reply_channel self.assertEqual(receive_reply.get('stream'), 'submit_card') self.assertFalse(receive_reply.get('payload').get('data').get('valid')) disconnect_consumer = client.send_and_consume('websocket.disconnect', path='/game/') disconnect_consumer.close()
def test_game_server(self): client = WSClient() with apply_routes([ GameConsumer.as_route( path=r"^/minesweeper/stream/(?P<game_id>[^/]+)") ]): client.send_and_consume('websocket.connect', path='/minesweeper/stream/1') user_map = np.array(client.receive()['data']) self.assertEqual(client.receive()['type'], 'game_change') self.assertTrue( np.array_equal(user_map, np.full(user_map.shape, -2))) client.send_and_consume('websocket.receive', text=json.dumps({ 'type': 'reveal', 'data': { 'x': 0, 'y': 0, } }), path='/minesweeper/stream/1') self.assertEqual(client.receive()['type'], 'game_change') client.send_and_consume('websocket.receive', text=json.dumps({ 'type': 'mark', 'data': { 'x': 0, 'y': 0, } }), path='/minesweeper/stream/1') self.assertEqual(client.receive()['type'], 'game_change') client.send_and_consume('websocket.receive', text=json.dumps({ 'type': 'restart', 'data': { 'x': 0, 'y': 0, } }), path='/minesweeper/stream/1') self.assertEqual(client.receive()['type'], 'game_change') client.send_and_consume('websocket.receive', text=json.dumps({ 'type': 'reveal_multiple', 'data': { 'points': [{ 'x': 0, 'y': 0, }], } }), path='/minesweeper/stream/1') self.assertEqual(client.receive()['type'], 'game_change')
def test_authentication_with_wrong_token_failed(self): client = WSClient() client.send_and_consume('websocket.connect', path='/accounts/user/wrong/', check_accept=False) received = client.receive(json=False) self.assertEqual(received, {"close": True})
def test_receives_messages(self): self.maxDiff = None client = WSClient() user = UserFactory() author_client = WSClient() author = UserFactory() # join a conversation conversation = ConversationFactory() conversation.join(user) conversation.join(author) # login and connect client.force_login(user) client.send_and_consume('websocket.connect', path='/') author_client.force_login(author) author_client.send_and_consume('websocket.connect', path='/') # add a message to the conversation message = ConversationMessage.objects.create(conversation=conversation, content='yay', author=author) # hopefully they receive it! response = client.receive(json=True) parse_dates(response) self.assertEqual( response, make_conversation_message_broadcast(message) ) # and they should get an updated conversation object response = client.receive(json=True) parse_dates(response) del response['payload']['participants'] self.assertEqual( response, make_conversation_broadcast(conversation, unread_message_count=1) ) # author should get message & updated conversations object too response = author_client.receive(json=True) parse_dates(response) self.assertEqual( response, make_conversation_message_broadcast(message, is_editable=True) ) # Author receives more recent `update_at` time, # because their `seen_up_to` status is set after sending the message. author_participant = conversation.conversationparticipant_set.get(user=author) response = author_client.receive(json=True) parse_dates(response) del response['payload']['participants'] self.assertEqual( response, make_conversation_broadcast(conversation, seen_up_to=message.id, updated_at=author_participant.updated_at) )
class PickupDateReceiverTests(ChannelTestCase): def setUp(self): self.client = WSClient() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.store = StoreFactory(group=self.group) self.pickup = PickupDateFactory(store=self.store) def test_receive_pickup_changes(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') # change property date = faker.future_datetime(end_date='+30d', tzinfo=timezone.utc) self.pickup.date = date self.pickup.save() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:pickupdate') self.assertEqual(parse(response['payload']['date']), date) # join self.pickup.collectors.add(self.member) response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:pickupdate') self.assertEqual(response['payload']['collector_ids'], [self.member.id]) response = self.client.receive(json=True) self.assertEqual(response['topic'], 'conversations:conversation') self.assertEqual(response['payload']['participants'], [self.member.id]) # leave self.pickup.collectors.remove(self.member) response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:pickupdate') self.assertEqual(response['payload']['collector_ids'], []) response = self.client.receive(json=True) self.assertEqual(response['topic'], 'conversations:leave') self.assertIsNone(self.client.receive(json=True)) def test_receive_pickup_delete(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') self.pickup.deleted = True self.pickup.save() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'pickups:pickupdate_deleted') self.assertEqual(response['payload']['id'], self.pickup.id) self.assertIsNone(self.client.receive(json=True))
def test_websocket(self): client = WSClient() client.send_and_consume('websocket.connect', path='/test/') self.assertIsNone(client.receive()) client.send_and_consume('websocket.receive', text={'message': 'echo'}, path='/test/') self.assertEqual(client.receive(), {'message': 'echo'})
def test_connection_not_authenticated(self): client = WSClient() client.send_and_consume('websocket.connect', path='/api/websocket/') response = client.receive() self.assertIn('event', response) self.assertEqual(response['data']['reason'], 'Not authenticated') self.assertEqual(response['data']['type'], 'connection-auth') response = client.receive() self.assertEqual(response['close'], 4000)
def test_adds_subscription(self): client = WSClient() user = UserFactory() client.force_login(user) self.assertEqual( ChannelSubscription.objects.filter(user=user).count(), 0) client.send_and_consume('websocket.connect', path='/') self.assertEqual( ChannelSubscription.objects.filter(user=user).count(), 1, 'Did not add subscription')
def test_receive_unknown_message_type(self): ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': Status.ok({ 'method': '' }).to_json()}, ) self.assertIsNone(ws_client.receive())
def test_websocket_close_exception_close_code(self): def consumer(message): raise WebsocketCloseException(3001) client = WSClient(reply_channel='daphne.response.1') with apply_routes(route('websocket.receive', consumer)): client.send_and_consume('websocket.receive') self.assertEqual( client.get_next_message(client.reply_channel).content, {'close': 3001})
def test_authentication_with_token_success(self): client = WSClient() resident = ResidentFactory.create() token = TokenFactory.create(user=resident) client.send_and_consume('websocket.connect', path='/accounts/user/{0}/'.format(token.key), check_accept=False) received = client.receive(json=False) self.assertEqual(received, {"accept": True})
def test_saves_reply_channel(self): client = WSClient() user = UserFactory() client.force_login(user) client.send_and_consume('websocket.connect', path='/') subscription = ChannelSubscription.objects.filter(user=user).first() self.assertIsNotNone(subscription.reply_channel) # send a message on it Channel(subscription.reply_channel).send({'message': 'hey! whaatsup?'}) self.assertEqual(client.receive(json=True), {'message': 'hey! whaatsup?'})
def test_connection_authenticated(self): self.assertIsNone(cache.get('session:skystar')) client = WSClient() client.login(username='******', password='******') client.send_and_consume('websocket.connect', path='/api/websocket/') self.assertIsNotNone(cache.get('session:skystar')) response = client.receive() self.assertEqual(response['event'], 'connected')
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')
def test_route_params_saved_in_kwargs(self): class UserBinding(WebsocketBinding): model = User stream = 'users' fields = ['username', 'email', 'password', 'last_name'] @classmethod def group_names(cls, instance): return ['users_outbound'] def has_permission(self, user, action, pk): return True class Demultiplexer(WebsocketDemultiplexer): consumers = { 'users': UserBinding.consumer, } groups = ['inbound'] with apply_routes([Demultiplexer.as_route(path='/path/(?P<id>\d+)')]): client = WSClient() consumer = client.send_and_consume('websocket.connect', path='/path/789') self.assertEqual(consumer.kwargs['id'], '789')
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_notification(self): client = WSClient() client.send_and_consume('websocket.connect', path='/knocker/en/') post = Post.objects.create( title='first post', slug='first-post', ) notification = client.receive() self.assertEqual(notification['title'], 'new {0}'.format(post._meta.verbose_name)) self.assertEqual(notification['message'], post.title) self.assertEqual(notification['url'], post.get_absolute_url()) # This model does not send notifications NoKnockPost.objects.create( title='first post', slug='first-post', ) self.assertIsNone(client.receive())
def test_inbound_create(self): self.assertEqual(User.objects.all().count(), 0) class UserBinding(WebsocketBinding): model = User stream = 'users' fields = ['username', 'email', 'password', 'last_name'] @classmethod def group_names(cls, instance): return ['users_outbound'] def has_permission(self, user, action, pk): return True class Demultiplexer(WebsocketDemultiplexer): consumers = { 'users': UserBinding.consumer, } groups = ['inbound'] with apply_routes([Demultiplexer.as_route(path='/')]): client = WSClient() client.send_and_consume('websocket.connect', path='/') client.send_and_consume('websocket.receive', path='/', text={ 'stream': 'users', 'payload': { 'action': CREATE, 'data': {'username': '******', 'email': 'test@user_steam.com'}, }, }) 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_ws_message(self): client = WSClient() client.send_and_consume('websocket.receive', text={'event': 'ConnectionEstablished', 'socketId': '54'}) self.assertIsNone(client.receive()) client.send_and_consume('websocket.receive', text={'event': 'fetchCurrentPort'}) receive = client.receive()["data"] self.assertEqual(receive, settings.PORT) client.send_and_consume('websocket.receive', text={'event': 'getPublicIPaddress'}) receive = client.receive()["data"] self.assertEqual(receive, settings.HOST_NAME)
def test_inbound_update(self): user = User.objects.create(username='******', email='*****@*****.**') class UserBinding(WebsocketBinding): model = User stream = 'users' fields = ['username', ] @classmethod def group_names(cls, instance): return ['users_outbound'] def has_permission(self, user, action, pk): return True class Demultiplexer(WebsocketDemultiplexer): consumers = { 'users': UserBinding.consumer, } groups = ['inbound'] with apply_routes([Demultiplexer.as_route(path='/')]): client = WSClient() 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': '******'}} }) user = User.objects.get(pk=user.pk) self.assertEqual(user.username, 'test_inbound') self.assertEqual(user.email, '*****@*****.**') # 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': '*****@*****.**'}} }) user = User.objects.get(pk=user.pk) self.assertEqual(user.username, 'test_inbound') self.assertEqual(user.email, '*****@*****.**') self.assertIsNone(client.receive())
def test_ws_connect(self): client = WSClient() client.send_and_consume('websocket.connect') self.assertIsNone(client.receive())
class ResourceBindingTestCase(ChannelTestCase): def setUp(self): super(ResourceBindingTestCase, self).setUp() self.client = WSClient() def _send_and_consume(self, channel, data): """Helper that sends and consumes message and returns the next message.""" self.client.send_and_consume(force_text(channel), data) return self._get_next_message() def _get_next_message(self): msg = self.client.get_next_message(self.client.reply_channel) return json.loads(msg['text']) def _build_message(self, stream, payload): return {"text": json.dumps({"stream": stream, "payload": payload}), "path": "/"} def test_create(self): """Integration that asserts routing a message to the create channel. Asserts response is correct and an object is created. """ json_content = self._send_and_consume("websocket.receive", self._build_message("testmodel", { 'action': 'create', 'pk': None, 'request_id': 'client-request-id', 'data': {'name': 'some-thing'} })) # it should create an object self.assertEqual(TestModel.objects.count(), 1) expected = { 'action': 'create', 'data': TestModelSerializer(TestModel.objects.first()).data, 'errors': [], 'request_id': 'client-request-id', 'response_status': 201 } # it should respond with the serializer.data self.assertEqual(json_content['payload'], expected) def test_create_failure(self): """Integration that asserts error handling of a message to the create channel.""" json_content = self._send_and_consume('websocket.receive', self._build_message("testmodel", { 'action': 'create', 'pk': None, 'request_id': 'client-request-id', 'data': {}, })) # it should not create an object self.assertEqual(TestModel.objects.count(), 0) expected = { 'action': 'create', 'data': None, 'request_id': 'client-request-id', 'errors': [{'name': ['This field is required.']}], 'response_status': 400 } # it should respond with an error self.assertEqual(json_content['payload'], expected) def test_delete(self): instance = TestModel.objects.create(name='test-name') json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'delete', 'pk': instance.id, 'request_id': 'client-request-id', })) expected = { 'action': 'delete', 'errors': [], 'data': {}, 'request_id': 'client-request-id', 'response_status': 200 } self.assertEqual(json_content['payload'], expected) self.assertEqual(TestModel.objects.count(), 0) def test_delete_failure(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'delete', 'pk': -1, 'request_id': 'client-request-id' })) expected = { 'action': 'delete', 'errors': ['Not found.'], 'data': None, 'request_id': 'client-request-id', 'response_status': 404 } self.assertEqual(json_content['payload'], expected) def test_list(self): for n in range(api_settings.DEFAULT_PAGE_SIZE + 1): TestModel.objects.create(name='Name-{}'.format(str(n))) json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'list', 'request_id': 'client-request-id', 'data': None, })) self.assertEqual(len(json_content['payload']['data']), api_settings.DEFAULT_PAGE_SIZE) json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'list', 'request_id': 'client-request-id', 'data': { 'page': 2 } })) self.assertEqual(len(json_content['payload']['data']), 1) self.assertEqual('client-request-id', json_content['payload']['request_id']) def test_retrieve(self): instance = TestModel.objects.create(name="Test") json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'retrieve', 'pk': instance.id, 'request_id': 'client-request-id' })) expected = { 'action': 'retrieve', 'data': TestModelSerializer(instance).data, 'errors': [], 'response_status': 200, 'request_id': 'client-request-id' } self.assertTrue(json_content['payload'] == expected) def test_retrieve_404(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'retrieve', 'pk': 1, 'request_id': 'client-request-id' })) expected = { 'action': 'retrieve', 'data': None, 'errors': ['Not found.'], 'response_status': 404, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_retrieve_invalid_pk_404(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'retrieve', 'pk': 'invalid-pk-value', 'request_id': 'client-request-id' })) expected = { 'action': 'retrieve', 'data': None, 'errors': ['Not found.'], 'response_status': 404, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_subscribe(self): json_content = self._send_and_consume('websocket.receive', self._build_message("testmodel",{ 'action': 'subscribe', 'data': { 'action': 'create' }, 'request_id': 'client-request-id' })) expected_response = { 'action': 'subscribe', 'request_id': 'client-request-id', 'data': { 'action': 'create' }, 'errors': [], 'response_status': 200 } self.assertEqual(json_content['payload'], expected_response) # it should be on the create group instance = TestModel.objects.create(name='test-name') expected = { 'action': 'create', 'data': TestModelSerializer(instance).data, 'model': 'tests.testmodel', 'pk': instance.id } actual = self._get_next_message() self.assertEqual(expected, actual['payload']) def test_subscribe_failure(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'subscribe', 'data': { }, 'request_id': 'client-request-id' })) expected = { 'action': 'subscribe', 'data': None, 'errors': ['action required'], 'request_id': 'client-request-id', 'response_status': 400 } self.assertEqual(expected, json_content['payload']) def test_update(self): instance = TestModel.objects.create(name='some-test') json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'update', 'pk': instance.id, 'data': {'name': 'some-value'}, 'request_id': 'client-request-id' })) instance.refresh_from_db() expected = { 'action': 'update', 'errors': [], 'data': TestModelSerializer(instance).data, 'response_status': 200, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_update_failure(self): instance = TestModel.objects.create(name='some-test') json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', { 'action': 'update', 'pk': -1, 'data': {'name': 'some-value'}, 'request_id': 'client-request-id' })) expected = { 'data': None, 'action': 'update', 'errors': ['Not found.'], 'response_status': 404, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_list_action(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'test_list', 'pk': None, 'data': {}, 'request_id': 'client-request-id', })) expected = { 'action': 'test_list', 'errors': [], 'data': 'some data', 'response_status': 200, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_detail_action(self): instance = TestModel.objects.create(name='some-test') json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'test_detail', 'pk': instance.id, 'data': {}, 'request_id': 'client-request-id' })) expected = { 'action': 'test_detail', 'errors': [], 'data': instance.name, 'response_status': 200, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_named_list_action(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'named_list', 'pk': None, 'data': {}, 'request_id': 'client-request-id', })) expected = { 'action': 'named_list', 'errors': [], 'data': 'some data', 'response_status': 200, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_named_detail_action(self): instance = TestModel.objects.create(name='some-test') json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'named_detail', 'pk': instance.id, 'data': {}, 'request_id': 'client-request-id' })) expected = { 'action': 'named_detail', 'errors': [], 'data': instance.name, 'response_status': 200, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_bad_permission_reply(self): mock_has_perm = Mock() mock_has_perm.return_value = False with patch.object(TestModelResourceBinding, 'has_permission', mock_has_perm): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'named_detail', 'pk': 546, 'data': {}, 'request_id': 'client-request-id' })) expected = { 'action': 'named_detail', 'errors': ['Permission Denied'], 'data': None, 'response_status': 401, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) self.assertEqual(mock_has_perm.called, True) def test_bad_action_reply(self): json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel',{ 'action': 'named_detail_not_set', 'pk': 123, 'data': {}, 'request_id': 'client-request-id' })) expected = { 'action': 'named_detail_not_set', 'errors': ['Invalid Action'], 'data': None, 'response_status': 400, 'request_id': 'client-request-id' } self.assertEqual(json_content['payload'], expected) def test_is_authenticated_permission(self): with patch.object(TestModelResourceBinding, 'permission_classes', (IsAuthenticated,)): content = { 'action': 'test_list', 'pk': None, 'data': {}, 'request_id': 'client-request-id', } json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', content)) # It should block the request self.assertEqual(json_content['payload']['response_status'], 401) user = User.objects.create(username="******", password="******") self.client.force_login(user) self.client._session_cookie = True json_content = self._send_and_consume('websocket.receive', self._build_message('testmodel', content)) self.assertEqual(json_content['payload']['response_status'], 200)
def test_connect(self): client = WSClient() client.send_and_consume('websocket.connect', path='/knocker/en/') self.assertIsNone(client.receive())