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_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_room_ready(self): client1 = WSClient() client1.login(username='******', password='******') client1.send_and_consume('websocket.connect', path='/api/websocket/') client1.receive() client2 = WSClient() client2.login(username='******', password='******') client2.send_and_consume('websocket.connect', path='/api/websocket/') client2.receive() data = { 'room_id': 'room', } req = request('room-join', data, nonce='test') client1.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) client1.receive() client1.receive() client2.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) client2.receive() client2.receive() client1.receive() req = request('room-ready', {'ready': True}, nonce='test') client1.send_and_consume('websocket.receive', req, path='/api/websocket/') room_ready_consumer(self.get_next_message('room-ready')) room_cache = cache.get('room:room') response = client1.receive() self.assertTrue(response['success']) self.assertTrue(room_cache['players'][0]['ready']) self.assertFalse(room_cache['players'][1]['ready']) client1.receive() response = client2.receive() self.assertEqual(response['event'], 'room-ready') self.assertEqual(response['data']['player'], 'skystar1') req = request('room-ready', {'ready': False}, nonce='test') client1.send_and_consume('websocket.receive', req, path='/api/websocket/') room_ready_consumer(self.get_next_message('room-ready')) room_cache = cache.get('room:room') response = client1.receive() self.assertTrue(response['success']) self.assertFalse(room_cache['players'][0]['ready'])
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())), )
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_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_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_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_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_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_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_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_room_join_broadcast(self): client1 = WSClient() client1.login(username='******', password='******') client1.send_and_consume('websocket.connect', path='/api/websocket/') client2 = WSClient() client2.login(username='******', password='******') client2.send_and_consume('websocket.connect', path='/api/websocket/') client3 = WSClient() client3.login(username='******', password='******') client3.send_and_consume('websocket.connect', path='/api/websocket/') client1.receive() client2.receive() client3.receive() data = { 'room_id': 'room', } req = request('room-join', data, nonce='test') client1.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) client1.receive() self.assertEqual(client1.receive()['data']['player'], 'skystar1') client2.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) self.assertEqual(len(client2.receive()['result']['players']), 2) response = client1.receive() room_cache = cache.get('room:room') self.assertIn('event', response) self.assertEqual(response['event'], 'room-join') result = response['data'] self.assertEqual(len(room_cache['players']), 2) self.assertEqual(room_cache['players'][0]['username'], 'skystar1') self.assertEqual(room_cache['players'][1]['username'], 'skystar2') self.assertEqual(result['player'], 'skystar2') client3.send_and_consume('websocket.receive', req, path='/api/websocket/') room_join_consumer(self.get_next_message('room-join')) response = client3.receive() self.assertFalse(response['success']) self.assertEqual(response['error']['reason'], 'Room is full')
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_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_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_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_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_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_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_receive_no_content(self): ws_client = WSClient() ws_client.send_and_consume( 'websocket.receive', path='/commands', ) self.assertIsNone(ws_client.receive())
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 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_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_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_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='/')
def test_create_contestant_valid_room(self): """ Attempt to create a contestant in a valid room """ room = Room.objects.last() client = WSClient() client.send_and_consume('websocket.connect') client.send_and_consume( 'quiz.receive', { 'command': 'new_contestant', 'room_code': room.code, 'contestant_name': 'Joe Bloggs' }) response = client.receive() # Verify server responded with correct status code self.assertEqual(response['status_code'], StatusCode.OK) # Verify room contestant count is one self.assertEquals(room.contestant_set.count(), 1) # Verify it is indeed Joe Bloggs in the room self.assertEquals(room.contestant_set.last().handle, 'Joe Bloggs') client.send_and_consume('websocket.disconnect')
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_timer_slave_timeout(self): from threading import Timer webinterface = WSClient() webinterface.join_group('notifications') self.sched._Scheduler__event = asyncio.Event(loop=self.sched.loop) self.sched._Scheduler__script = self.script.id self.sched._Scheduler__state = SchedulerStatus.WAITING_FOR_SLAVES timer = Timer( 1, self.sched.slave_timeout_callback, ) timer.start() timer.join() self.assertEqual( self.sched._Scheduler__state, SchedulerStatus.ERROR, ) self.assertEqual( self.sched._Scheduler__error_code, "Not all slaves connected within 5 minutes.", )