def test_trigger_outbound_create_non_auto_pk(self): class TestBinding(WebsocketBinding): model = models.TestUUIDModel stream = 'test' fields = ['name'] @classmethod def group_names(cls, instance): return ["testuuidmodels"] def has_permission(self, user, action, pk): return True client = WSClient() client.join_group('testuuidmodels') instance = models.TestUUIDModel.objects.create(name='testname') received = client.receive() self.assertTrue('payload' in received) self.assertTrue('action' in received['payload']) self.assertTrue('data' in received['payload']) self.assertTrue('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'], 'tests.testuuidmodel') self.assertEqual(received['payload']['pk'], str(instance.pk)) self.assertEqual(received['payload']['data']['name'], 'testname') received = client.receive() self.assertIsNone(received)
def test_join_subscription(self): game = Game.objects.first() client = WSClient() client.join_group(GameBinding.group_name(GameBinding.JOIN_SUB, game.pk)) user = User.objects.get(username='******') game.join(user) received = client.receive() self.assertIsNotNone(received) self.assertEqual(received['stream'], GameBinding.stream) self.assertEqual(received['payload']['action'], GameBinding.JOIN_SUB) self.assertEqual(received['payload']['pk'], game.pk) self.assertEqual(received['payload']['data']['user']['username'], user.username) user2 = User.objects.get(username='******') game.join(user2) received = client.receive() self.assertIsNotNone(received) self.assertEqual(received['stream'], GameBinding.stream) self.assertEqual(received['payload']['action'], GameBinding.JOIN_SUB) self.assertEqual(received['payload']['pk'], game.pk) self.assertEqual(received['payload']['data']['user']['username'], user2.username)
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_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_next_question_subscription(self): game = Game.objects.first() client = WSClient() client.join_group( GameBinding.group_name(GameBinding.NEXT_QUESTION_SUB, game.pk)) # Start game game.next_question() received = client.receive() self.assertIsNotNone(received) self.assertEqual(received['stream'], GameBinding.stream) self.assertEqual(received['payload']['action'], GameBinding.NEXT_QUESTION_SUB) self.assertEqual(received['payload']['pk'], game.pk) self.assertEqual(received['payload']['data']['id'], game.pk) self.assertIsNotNone(received['payload']['data']['current_question']) # Next question game.next_question() received = client.receive() self.assertIsNotNone(received) self.assertEqual(received['stream'], GameBinding.stream) self.assertEqual(received['payload']['action'], GameBinding.NEXT_QUESTION_SUB) self.assertEqual(received['payload']['pk'], game.pk) self.assertEqual(received['payload']['data']['id'], game.pk) self.assertIsNotNone(received['payload']['data']['current_question'])
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_websocket_custom_json_serialization(self): class WebsocketConsumer(websockets.JsonWebsocketConsumer): @classmethod def decode_json(cls, text): obj = json.loads(text) return dict((key.upper(), obj[key]) for key in obj) @classmethod def encode_json(cls, content): lowered = dict((key.lower(), content[key]) for key in content) return json.dumps(lowered) def receive(self, content, multiplexer=None, **kwargs): self.content_received = content self.send({"RESPONSE": "HI"}) class MyMultiplexer(websockets.WebsocketMultiplexer): @classmethod def encode_json(cls, content): lowered = dict((key.lower(), content[key]) for key in content) return json.dumps(lowered) with apply_routes([route_class(WebsocketConsumer, path='/path')]): client = WSClient() consumer = client.send_and_consume('websocket.receive', path='/path', text={"key": "value"}) self.assertEqual(consumer.content_received, {"KEY": "value"}) self.assertEqual(client.receive(), {"response": "HI"}) client.join_group('test_group') WebsocketConsumer.group_send('test_group', {"KEY": "VALUE"}) self.assertEqual(client.receive(), {"key": "VALUE"})
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_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)
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_disconnect_slave_not_exists(self): slave = SlaveOnlineFactory() program_status = ProgramStatusFactory(program__slave=slave) program = program_status.program # connect client on /commands ws_client = WSClient() ws_client.send_and_consume( 'websocket.connect', path='/commands', content={'client': [slave.ip_address, slave.mac_address]}) # connect webinterface on /notifications webinterface = WSClient() webinterface.send_and_consume( 'websocket.connect', path='/notifications', ) slave.delete() # throw away connect response ws_client.receive() ws_client.send_and_consume('websocket.disconnect', path='/commands') self.assertFalse(SlaveModel.objects.filter(id=slave.id).exists()) self.assertFalse( ProgramStatusModel.objects.filter(program=program).exists()) # test if a "disconnected" message has been send to the webinterface self.assertIsNone(webinterface.receive())
def test_ws_connect(self): client = WSClient() default = 'turnex' # Inject a message onto the channel to use in a consumer #Channel("input").send({"value": 33}) # Run the consumer with the new Message object #message = self.get_next_message("input", require=True) #consumer.ws_connect(message) # Verify there's a reply and that it's accurate #result = self.get_next_message(message.reply_channel.name, # require=True) #self.assertIsNotNone(result) client.send_and_consume('websocket.connect', path='/') self.assertIsNone(client.receive()) Group(default).send({'text': 'ok'}, immediately=True) self.assertEqual(client.receive(json=False), 'ok') client.send_and_consume('websocket.receive', text={'message': 'hey'}, path='/') self.assertEqual(client.receive(), {'event': 'error', 'body': 'Stop Hacking.'}) client.send_and_consume('websocket.disconnect', text={'message': 'hey'}, path='/')
class UserReceiverTest(ChannelTestCase): def setUp(self): self.client = WSClient() self.member = UserFactory() self.other_member = UserFactory() self.unrelated_user = UserFactory() self.group = GroupFactory(members=[self.member, self.other_member]) pathlib.Path(settings.MEDIA_ROOT).mkdir(exist_ok=True) copyfile(os.path.join(os.path.dirname(__file__), './photo.jpg'), os.path.join(settings.MEDIA_ROOT, 'photo.jpg')) self.member.photo = 'photo.jpg' self.member.save() self.other_member.photo = 'photo.jpg' self.other_member.save() def test_receive_own_user_changes(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') name = faker.name() self.member.display_name = name self.member.save() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'auth:user') self.assertEqual(response['payload']['display_name'], name) self.assertTrue('current_group' in response['payload']) self.assertTrue( response['payload']['photo_urls']['full_size'].startswith( settings.HOSTNAME)) self.assertIsNone(self.client.receive(json=True)) def test_receive_changes_of_other_user(self): self.client.force_login(self.member) self.client.send_and_consume('websocket.connect', path='/') name = faker.name() self.other_member.display_name = name self.other_member.save() response = self.client.receive(json=True) self.assertEqual(response['topic'], 'users:user') self.assertEqual(response['payload']['display_name'], name) self.assertTrue('current_group' not in response['payload']) self.assertTrue( response['payload']['photo_urls']['full_size'].startswith( settings.HOSTNAME)) self.assertIsNone(self.client.receive(json=True)) def test_unrelated_user_receives_no_changes(self): self.client.force_login(self.unrelated_user) self.client.send_and_consume('websocket.connect', path='/') self.member.display_name = faker.name() self.member.save() self.assertIsNone(self.client.receive(json=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) )
def test_receive_chain_commands_success(self): filesystem = FileFactory() moved = MovedFileFactory.build() error_status1 = Status.ok({ 'method': 'filesystem_move', 'result': moved.hash_value, }) error_status1.uuid = filesystem.command_uuid error_status2 = Status.ok({ 'method': 'filesystem_move', 'result': moved.hash_value, }) error_status2.uuid = filesystem.command_uuid error_chain = Status.ok({ 'method': 'chain_execution', 'result': [dict(error_status1), dict(error_status2)], }) # connect webinterface webinterface = WSClient() webinterface.join_group('notifications') ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', content={'text': error_chain.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())), ) self.assertEqual( Status.ok({ 'filesystem_status': 'moved', 'fid': str(filesystem.id), }), Status.from_json(json.dumps(webinterface.receive())), ) self.assertIsNone(webinterface.receive())
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_create_contestant_invalid_room(self): """ Attempt to create multiple contestants, and verify the contestant list propagated to all contestants is correct """ john_client = WSClient() jane_client = WSClient() john_client.send_and_consume('websocket.connect') john_client.send_and_consume( 'quiz.receive', { 'command': 'new_contestant', 'room_code': Room.objects.last().code, 'contestant_name': 'John Doe' }) # Verify server responded with correct status code response = john_client.receive() self.assertEqual(response['status_code'], StatusCode.OK) # Verify server updates john with complete contestant list response = john_client.receive() self.assertDictEqual(response, { 'command': 'contestant_list', 'contestants': ['John Doe'] }) jane_client.send_and_consume('websocket.connect') jane_client.send_and_consume( 'quiz.receive', { 'command': 'new_contestant', 'room_code': Room.objects.last().code, 'contestant_name': 'Jane Doe' }) # Verify server responded with correct status code response = jane_client.receive() self.assertEqual(response['status_code'], StatusCode.OK) # Verify server updates jane with complete contestant list response = jane_client.receive() self.assertDictEqual(response, { 'command': 'contestant_list', 'contestants': ['Jane Doe', 'John Doe'] }) # Verify server updates john with complete contestant list response = john_client.receive() self.assertDictEqual(response, { 'command': 'contestant_list', 'contestants': ['Jane Doe', 'John Doe'] }) jane_client.send_and_consume('websocket.disconnect') john_client.send_and_consume('websocket.disconnect')
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_validate_player_name(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 # Available Test client.send_and_consume( 'websocket.receive', path='/game/', text={ 'stream': 'validate_player_name', 'payload': { 'game_code': 'abcd', 'player_name': 'tim' } }) # 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'), 'validate_player_name') self.assertEqual( 'abcd', receive_reply.get('payload').get('data').get('game_code')) self.assertTrue(receive_reply.get('payload').get('data').get('valid')) # Invalid Test add_player_to_game(self.game1.code, 'tim') client.send_and_consume( 'websocket.receive', path='/game/', text={ 'stream': 'validate_player_name', 'payload': { 'game_code': 'abcd', 'player_name': 'tim' } }) # 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'), 'validate_player_name') self.assertEqual( 'abcd', receive_reply.get('payload').get('data').get('game_code')) 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_connection_force_login(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) first_client.receive() second_client.send_and_consume('websocket.connect', path='/api/websocket/?force=true') second_client.receive() first_client.receive() data = {'text': json.dumps({'action': 'room-join', 'data': {}})} first_client.send_and_consume('websocket.receive', data, path='/api/websocket/') response = first_client.receive() self.assertIn('error', response) self.assertEqual(response['error']['reason'], 'Session duplication detected') self.assertEqual(response['error']['type'], 'receive') response = first_client.receive() self.assertEqual(response['close'], 4011) self.assertNotEqual(cache.get('session:skystar'), session_cache)
def test_websockets_demultiplexer(self): class MyWebsocketConsumer(websockets.JsonWebsocketConsumer): def connect(self, message, multiplexer=None, **kwargs): multiplexer.send(kwargs) def disconnect(self, message, multiplexer=None, **kwargs): multiplexer.send(kwargs) def receive(self, content, multiplexer=None, **kwargs): multiplexer.send(content) class Demultiplexer(websockets.WebsocketDemultiplexer): 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": { "id": "1" }, }) client.send_and_consume('websocket.receive', text={ "stream": "mystream", "payload": { "text_field": "mytext" }, }, path='/path/1') self.assertEqual(client.receive(), { "stream": "mystream", "payload": { "text_field": "mytext" }, }) client.send_and_consume('websocket.disconnect', path='/path/1') self.assertEqual(client.receive(), { "stream": "mystream", "payload": { "id": "1" }, })
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_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_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_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_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_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_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_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_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_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_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_trigger_outbound_update(self): class TestBinding(WebsocketBinding): model = User stream = 'test' fields = ['__all__'] @classmethod def group_names(cls, instance): return ["users2"] def has_permission(self, user, action, pk): return True # Make model and clear out pending sends user = User.objects.create(username='******', email='*****@*****.**') client = WSClient() client.join_group('users2') user.username = '******' user.save() 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'], '*****@*****.**') 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_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_trigger_outbound_create_exclude(self): class TestBinding(WebsocketBinding): model = User stream = 'test' exclude = ['first_name', 'last_name'] @classmethod def group_names(cls, instance): return ["users_exclude"] def has_permission(self, user, action, pk): return True with apply_routes([route('test', TestBinding.consumer)]): client = WSClient() client.join_group('users_exclude') user = User.objects.create(username='******', email='*****@*****.**') 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'], '*****@*****.**') self.assertEqual(received['payload']['data']['username'], 'test') self.assertEqual(received['payload']['data']['password'], '') received = client.receive() self.assertIsNone(received)
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_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_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_connect(self): client = WSClient() client.send_and_consume('websocket.connect') self.assertIsNone(client.receive())
def test_connect(self): client = WSClient() client.send_and_consume('websocket.connect', path='/knocker/en/') self.assertIsNone(client.receive())