async def test_receive_message_for_subscribed_group_only(self): """Test that clients subscribed to some groups only receive messages from those.""" # Arrange communicator = WebsocketCommunicator(application, self.url) connected, subprotocol = await communicator.connect() subscription_msg = { 'option': 'subscribe', 'category': 'telemetry', 'csc': 'ScriptQueue', 'salindex': 1, 'stream': 'stream1', } await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() # Act for combination in self.combinations: msg, expected = \ self.build_messages(combination['category'], combination['csc'], combination['salindex'], [ combination['stream']]) await communicator.send_json_to(msg) if combination['category'] == subscription_msg['category'] and \ combination['csc'] == subscription_msg['csc'] and \ combination['salindex'] == subscription_msg['salindex'] and \ combination['stream'] == subscription_msg['stream']: response = await communicator.receive_json_from() # Assert assert response == expected else: # Assert with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for(communicator.receive_json_from(), timeout=self.no_reception_timeout) await communicator.disconnect()
async def test_receive_part_of_message_for_subscribed_groups_only(self): """Test that clients subscribed to some groups only receive the corresponding part of incoming messages.""" # Arrange communicator = WebsocketCommunicator(application, self.url) connected, subprotocol = await communicator.connect() for combination in self.combinations: # Arrange: Subscribe to 1 subscription_msg = { "csc": combination["csc"], "stream": combination["stream"], "category": combination["category"], "salindex": combination["salindex"], } subscription_msg["option"] = "subscribe" await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() # Act: Send the big message msg, ignore = self.build_messages( combination["category"], combination["csc"], combination["salindex"], self.streams, ) await communicator.send_json_to(msg) if ( combination["category"] == subscription_msg["category"] and combination["csc"] == subscription_msg["csc"] and combination["salindex"] == subscription_msg["salindex"] and combination["stream"] == subscription_msg["stream"] ): response = await communicator.receive_json_from() # Assert: receive the one subscribed to ignore, expected = self.build_messages( combination["category"], combination["csc"], combination["salindex"], [combination["stream"]], ) assert response == expected else: # Assert: not receive all the others with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for( communicator.receive_json_from(), timeout=self.no_reception_timeout, ) # Clean: Unsubscribe from 1 subscription_msg["option"] = "unsubscribe" await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() await communicator.disconnect()
async def test_receive_message_for_subscribed_group_only(self): """Test that clients subscribed to some groups only receive messages from those.""" # Arrange communicator = WebsocketCommunicator(application, self.url) connected, subprotocol = await communicator.connect() subscription_msg = { "option": "subscribe", "category": "telemetry", "csc": "ScriptQueue", "salindex": 1, "stream": "stream1", } await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() # Act for combination in self.combinations: msg, expected = self.build_messages( combination["category"], combination["csc"], combination["salindex"], [combination["stream"]], ) await communicator.send_json_to(msg) if ( combination["category"] == subscription_msg["category"] and combination["csc"] == subscription_msg["csc"] and combination["salindex"] == subscription_msg["salindex"] and combination["stream"] == subscription_msg["stream"] ): response = await communicator.receive_json_from() # Assert assert response == expected else: # Assert with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for( communicator.receive_json_from(), timeout=self.no_reception_timeout, ) await communicator.disconnect()
async def test_receive_message_for_subscribed_groups_only(self): """Test that clients subscribed to some groups only receive messages from those.""" # Arrange communicator = WebsocketCommunicator(application, self.url) connected, subprotocol = await communicator.connect() for combination in self.combinations: # Arrange: Subscribe to 1 subscription_msg = { "csc": combination["csc"], "stream": combination["stream"], "category": combination["category"], "salindex": combination["salindex"] } subscription_msg['option'] = 'subscribe' await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() # Act: Send and receive all for combination in self.combinations: msg, expected = \ self.build_messages(combination['category'], combination['csc'], combination['salindex'], [ combination['stream']]) await communicator.send_json_to(msg) if combination['category'] == subscription_msg['category'] and \ combination['csc'] == subscription_msg['csc'] and \ combination['salindex'] == subscription_msg['salindex'] and \ combination['stream'] == subscription_msg['stream']: response = await communicator.receive_json_from() # Assert: receive the one subscribed to assert response == expected else: # Assert: not receive all the others with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for( communicator.receive_json_from(), timeout=self.no_reception_timeout) # Clean: Unsubscribe from 1 subscription_msg['option'] = 'unsubscribe' await communicator.send_json_to(subscription_msg) await communicator.receive_json_from() await communicator.disconnect()
async def test_livechat_flow(self, settings, client: APIClient, populate_db: pytest.fixture) -> None: # settings.CHANNEL_LAYERS = TEST_CHANNEL_LAYERS application = ProtocolTypeRouter({ 'websocket': AuthMiddlewareStack( SessionMiddlewareStack( URLRouter([ re_path(r'ws/chat/(?P<room_name>\w+)/$', TemplateChatConsumer) ]))) }) # Create a dummy admin user admin_user = mixer.blend(User, role='AO') # Login as admin operator admin = APIClient() admin.login(username=admin_user, password='******') user = auth.get_user(admin) # type: ignore assert user.is_authenticated _, bots, variables = populate_db for (bot_id, variable) in zip(bots, variables): # Start a new session for the template chat response = client.get(f'/api/clientwidget/session/{bot_id}') assert response.status_code == 200 response_data = json.loads(response.content) assert response_data["nodeType"] == "INIT" and response_data[ "room_name"] is not None and response_data[ "variables"] == variable room_name = response_data["room_name"] # Create the test room in ChatRoom room_instance, _ = ChatRoom.objects.get_or_create( room_name=room_name, bot_id=bot_id) assert room_instance.room_name == room_name # Create 2 communicators - One for the client and one for the admin client_socket = WebsocketCommunicator(application, f"/ws/chat/{room_name}/") admin_socket = WebsocketCommunicator(application, f"/ws/chat/{room_name}/") admin_socket.scope["user"] = admin_user client_connected, _ = await client_socket.connect() assert client_connected == True admin_connected = None user_inputs = [] # List of variable inputs per bot session variable_dict = room_instance.variables # And the corresponding dictionary from the room instance is_livechat = False while not ("nodeType" in response_data and response_data["nodeType"] == "END"): # Wait for 2 seconds time.sleep(2) if admin_connected == True: # Switch to Livechat is_livechat = True break # The message to be sent message = dict() payload = dict() # Set some flags yes_no, multi_choice = False, False if "nodeType" in response_data and response_data[ "nodeType"] == "YES_NO": # If YES / NO button yes_no = True choice = random.choice(["Yes", "No"]) for node in response_data["buttons"]: if node["text"] == choice: payload['target_id'] = node['targetId'] payload['post_data'] = choice elif "nodeType" in response_data and response_data[ "nodeType"] == "MULTI_CHOICE": # If Multi choice button multi_choice = True choices = set() for node in response_data["buttons"]: choices.add(node["text"]) payload['target_id'] = node['targetId'] payload['post_data'] = random.choice(tuple(choices)) elif "nodeType" in response_data and response_data[ "nodeType"] == "INIT": # Try to go to the next target_id node payload['target_id'] = response_data["targetId"] else: # Try to go to the next target_id node payload['target_id'] = response_data["targetId"] if "variable" in response_data: payload["variable"] = response_data["variable"] if multi_choice: # Multi choice variable already set user_inputs.append(payload["post_data"]) variable_dict[ response_data['variable']] = payload["post_data"] elif yes_no: # Yes / No variable already set user_inputs.append(payload["post_data"]) variable_dict[ response_data['variable']] = payload["post_data"] else: # Give a random input length = 10 payload["post_data"] = ''.join( random.choice(string.ascii_letters) for i in range(length)) user_inputs.append(payload["post_data"]) variable_dict[ response_data['variable']] = payload["post_data"] # Set the bot parameters message["user"] = "******" message["bot_id"] = str(bot_id) message["data"] = payload # type: ignore await client_socket.send_json_to(message) response_data = await client_socket.receive_json_from(timeout=3 ) # If the bot is still active if response_data["user"] == "bot": if 'data' in response_data: response_data = response_data['data'] else: break else: break if (yes_no == True or multi_choice == True) and admin_connected is None: # Make the admin enter at this point admin_connected, _ = await admin_socket.connect() assert admin_connected == True while is_livechat == True: # Send from admin communicator await admin_socket.send_json_to({ "user": "******", "message": "Hello from admin" }) futures = await asyncio.gather( client_socket.receive_json_from(), admin_socket.receive_json_from(), ) response_data_client, response_data_admin = futures assert response_data_client == response_data_admin assert response_data_admin[ "user"] == "admin" and response_data_admin[ "message"] == "Hello from admin" # type: ignore # Now send from client communicator await client_socket.send_json_to({ "user": "******", "message": { "userInputVal": "Hello from client" } }) futures = await asyncio.gather( client_socket.receive_json_from(), admin_socket.receive_json_from(), ) response_data_client, response_data_admin = futures assert response_data_client == response_data_admin assert response_data_client[ "user"] == "end_user" and response_data_client["message"][ "userInputVal"] == "Hello from client" # type: ignore # Now exit break # Verify session variables response = admin.get( f"/api/clientwidget/{room_name}/sessionvariables") assert response.status_code == 200 session_variables = json.loads(response.content) assert session_variables == variable_dict # Variables in DB must be empty response = admin.get(f"/api/clientwidget/{room_name}/variables") assert response.status_code == 200 variables = json.loads(response.content) assert variables == {key: "" for key in variable_dict} # Now verify the chat session history response = admin.get( f"/api/clientwidget/{room_name}/sessionhistory") assert response.status_code == 200 session_history = json.loads(response.content) assert len(session_history) == 2 assert session_history == [{ "user": "******", "message": "Hello from admin" }, { "user": "******", "message": { "userInputVal": "Hello from client" } }] # DB History must be empty response = admin.get(f"/api/clientwidget/{room_name}/history") assert response.status_code == 400 or response.status_code == 200 if response.status_code == 200: # List must be empty history = json.loads(response.content) assert len(history) == 0 # Disconnect await client_socket.disconnect() await admin_socket.disconnect() # Now session history must be empty response = admin.get( f"/api/clientwidget/{room_name}/sessionhistory") assert response.status_code == 400 or response.status_code == 200 if response.status_code == 200: # List must be empty flushed_history = json.loads(response.content) assert len(flushed_history) == 0 # While DB history is not response = admin.get(f"/api/clientwidget/{room_name}/history") assert response.status_code == 200 history = json.loads(response.content) assert history == session_history # Variables in session must be empty response = admin.get( f"/api/clientwidget/{room_name}/sessionvariables") assert response.status_code == 404 # While it must be updated in DB response = admin.get(f"/api/clientwidget/{room_name}/variables") assert response.status_code == 200 variables = json.loads(response.content) assert variables == session_variables