async def test_post_conversation_id_with_slash(rasa_app: SanicASGITestClient): conversation_id = str(uuid.uuid1()) id_len = len(conversation_id) // 2 conversation_id = conversation_id[:id_len] + "/+-_\\=" + conversation_id[id_len:] conversation = f"/conversations/{conversation_id}" events = [e.as_dict() for e in test_events] _, response = await rasa_app.post( f"{conversation}/tracker/events", json=events, headers={"Content-Type": "application/json"}, ) assert response.json() is not None assert response.status == 200 _, tracker_response = await rasa_app.get( f"/conversations/{conversation_id}/tracker" ) tracker = tracker_response.json() assert tracker is not None # there is a session start sequence at the start assert [ Event.from_parameters(event) for event in tracker.get("events") ] == session_start_sequence + test_events
async def test_pushing_event(rasa_app: SanicASGITestClient, event: Event): sender_id = str(uuid.uuid1()) conversation = f"/conversations/{sender_id}" serialized_event = event.as_dict() # Remove timestamp so that a new one is assigned on the server serialized_event.pop("timestamp") time_before_adding_events = time.time() _, response = await rasa_app.post( f"{conversation}/tracker/events", json=serialized_event, headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE}, ) assert response.json() is not None assert response.status == 200 _, tracker_response = await rasa_app.get(f"/conversations/{sender_id}/tracker") tracker = tracker_response.json() assert tracker is not None assert len(tracker.get("events")) == 4 deserialized_events = [Event.from_parameters(event) for event in tracker["events"]] # there is an initial session start sequence at the beginning of the tracker assert deserialized_events[:3] == session_start_sequence assert deserialized_events[3] == event assert deserialized_events[3].timestamp > time_before_adding_events
def test_bot_output_format(): message = { "event": "bot", "text": "Hello!", "data": { "image": "http://example.com/myimage.png", "attachment": "My Attachment", "buttons": [ {"title": "yes", "payload": "/yes"}, {"title": "no", "payload": "/no", "extra": "extra"}, ], "elements": [ { "title": "element1", "buttons": [{"title": "button1", "payload": "/button1"}], }, { "title": "element2", "buttons": [{"title": "button2", "payload": "/button2"}], }, ], "quick_replies": [ { "title": "quick_reply1", "buttons": [{"title": "button3", "payload": "/button3"}], }, { "title": "quick_reply2", "buttons": [{"title": "button4", "payload": "/button4"}], }, ], }, } from rasa.shared.core.events import Event bot_event = Event.from_parameters(message) assert isinstance(bot_event, BotUttered) formatted = interactive.format_bot_output(bot_event) assert formatted == ( "Hello!\n" "Image: http://example.com/myimage.png\n" "Attachment: My Attachment\n" "Buttons:\n" "1: yes (/yes)\n" '2: no (/no) - {"extra": "extra"}\n' "Type out your own message...\n" "Elements:\n" '1: element1 - {"buttons": ' '[{"payload": "/button1", "title": "button1"}]' '}\n2: element2 - {"buttons": ' '[{"payload": "/button2", "title": "button2"}]' "}\nQuick replies:\n" '1: quick_reply1 - {"buttons": ' '[{"payload": "/button3", "title": "button3"}' ']}\n2: quick_reply2 - {"buttons": ' '[{"payload": "/button4", "title": "button4"}' "]}" )
def test_json_parse_user(): evt = { "event": "user", "text": "Hey", "parse_data": { "intent": { "name": "greet", "confidence": 0.9 }, "entities": [] }, "metadata": {}, } assert Event.from_parameters(evt) == UserUttered( "Hey", intent={ "name": "greet", "confidence": 0.9 }, entities=[], parse_data={ "intent": { "name": "greet", "confidence": 0.9 }, "entities": [] }, metadata={}, )
def test_pushing_event(rasa_app: SanicTestClient, event: Event): sender_id = str(uuid.uuid1()) conversation = f"/conversations/{sender_id}" serialized_event = event.as_dict() # Remove timestamp so that a new one is assigned on the server serialized_event.pop("timestamp") time_before_adding_events = time.time() _, response = rasa_app.post( f"{conversation}/tracker/events", json=serialized_event, headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE}, ) assert response.json is not None assert response.status == 200 _, tracker_response = rasa_app.get(f"/conversations/{sender_id}/tracker") tracker = tracker_response.json assert tracker is not None assert len(tracker.get("events")) == 1 evt = tracker.get("events")[0] deserialised_event = Event.from_parameters(evt) assert deserialised_event == event assert deserialised_event.timestamp > time_before_adding_events
def test_json_parse_action_executed_with_no_hide_rule(): evt = { "event": "action", "name": "action_listen", "policy": None, "confidence": None, "timestamp": None, } deserialised: ActionExecuted = Event.from_parameters(evt) expected = ActionExecuted("action_listen", ) assert deserialised == expected assert deserialised.hide_rule_turn == expected.hide_rule_turn
def test_event_metadata_dict(event_class: Type[Event]): metadata = {"foo": "bar", "quux": 42} # Create the event from a `dict` that will be accepted by the # `_from_parameters` method of any `Event` subclass (the values themselves # are not important). event = Event.from_parameters({ "metadata": metadata, "event": event_class.type_name, "parse_data": {}, "date_time": "2019-11-20T16:09:16Z", }) assert event.as_dict()["metadata"] == metadata
def from_parameters(cls, parameters: Dict[Text, Any]) -> "Dialogue": """Create `Dialogue` from parameters. Args: parameters: Serialised dialogue, should contain keys 'name' and 'events'. Returns: Deserialised `Dialogue`. """ return cls( parameters.get("name"), [Event.from_parameters(evt) for evt in parameters.get("events")], )
def test_json_parse_reminder(): evt = { "event": "reminder", "intent": "my_intent", "entities": {"entity1": "value1", "entity2": "value2"}, "date_time": "2018-09-03T11:41:10.128172", "name": "my_reminder", "kill_on_user_msg": True, } assert Event.from_parameters(evt) == ReminderScheduled( "my_intent", parser.parse("2018-09-03T11:41:10.128172"), name="my_reminder", kill_on_user_message=True, )
def test_event_default_metadata(event_class: Type[Event]): # Create an event without metadata. When converting the `Event` to a # `dict`, it should not include a `metadata` property - unless it's a # `UserUttered` or a `BotUttered` event (or subclasses of them), in which # case the metadata should be included with a default value of {}. event = Event.from_parameters({ "event": event_class.type_name, "parse_data": {}, "date_time": "2019-11-20T16:09:16Z", }) if isinstance(event, BotUttered) or isinstance(event, UserUttered): assert event.as_dict()["metadata"] == {} else: assert "metadata" not in event.as_dict()
async def test_file_broker_logs_to_file(tmp_path: Path): log_file_path = str(tmp_path / "events.log") actual = await EventBroker.create( EndpointConfig(**{"type": "file", "path": log_file_path}) ) for e in TEST_EVENTS: actual.publish(e.as_dict()) # reading the events from the file one event per line recovered = [] with open(log_file_path, "r") as log_file: for line in log_file: recovered.append(Event.from_parameters(json.loads(line))) assert recovered == TEST_EVENTS
def test_event_metadata_dict(event_class: Type[Event]): metadata = {"foo": "bar", "quux": 42} parameters = { "metadata": metadata, "event": event_class.type_name, "parse_data": {}, "date_time": "2019-11-20T16:09:16Z", } # `ActionExecuted` class and its subclasses require either that action_name # is not None if it is not an end-to-end predicted action if event_class.type_name in ["action", "wrong_action", "warning_predicted"]: parameters["name"] = "test" # Create the event from a `dict` that will be accepted by the # `_from_parameters` method of any `Event` subclass (the values themselves # are not important). event = Event.from_parameters(parameters) assert event.as_dict()["metadata"] == metadata
async def test_file_broker_properly_logs_newlines(tmp_path: Path): log_file_path = str(tmp_path / "events.log") actual = await EventBroker.create( EndpointConfig(**{"type": "file", "path": log_file_path}) ) event_with_newline = UserUttered("hello \n there") actual.publish(event_with_newline.as_dict()) # reading the events from the file one event per line recovered = [] with open(log_file_path, "r") as log_file: for line in log_file: recovered.append(Event.from_parameters(json.loads(line))) assert recovered == [event_with_newline]
def test_json_parse_reminder_cancelled(): evt = { "event": "cancel_reminder", "name": "my_reminder", "intent": "my_intent", "entities": [ {"entity": "entity1", "value": "value1"}, {"entity": "entity2", "value": "value2"}, ], "date_time": "2018-09-03T11:41:10.128172", } assert Event.from_parameters(evt) == ReminderCancelled( name="my_reminder", intent="my_intent", entities=[ {"entity": "entity1", "value": "value1"}, {"entity": "entity2", "value": "value2"}, ], timestamp=parser.parse("2018-09-03T11:41:10.128172"), )
def test_event_default_metadata(event_class: Type[Event]): parameters = { "event": event_class.type_name, "parse_data": {}, "date_time": "2019-11-20T16:09:16Z", } # `ActionExecuted` class and its subclasses require either that action_name # is not None if it is not an end-to-end predicted action if event_class.type_name in ["action", "wrong_action", "warning_predicted"]: parameters["name"] = "test" # Create an event without metadata. When converting the `Event` to a # `dict`, it should not include a `metadata` property - unless it's a # `UserUttered` or a `BotUttered` event (or subclasses of them), in which # case the metadata should be included with a default value of {}. event = Event.from_parameters(parameters) if isinstance(event, BotUttered) or isinstance(event, UserUttered): assert event.as_dict()["metadata"] == {} else: assert "metadata" not in event.as_dict()
def _get_events_from_request_body(request: Request) -> List[Event]: events = request.json if not isinstance(events, list): events = [events] events = [Event.from_parameters(event) for event in events] events = [event for event in events if event] if not events: rasa.shared.utils.io.raise_warning( f"Append event called, but could not extract a valid event. " f"Request JSON: {request.json}" ) raise ErrorResponse( 400, "BadRequest", "Couldn't extract a proper event from the request body.", {"parameter": "", "in": "body"}, ) return events
async def test_push_multiple_events(rasa_app: SanicASGITestClient): conversation_id = str(uuid.uuid1()) conversation = f"/conversations/{conversation_id}" events = [e.as_dict() for e in test_events] _, response = await rasa_app.post( f"{conversation}/tracker/events", json=events, headers={"Content-Type": rasa.server.JSON_CONTENT_TYPE}, ) assert response.json() is not None assert response.status == 200 _, tracker_response = await rasa_app.get( f"/conversations/{conversation_id}/tracker" ) tracker = tracker_response.json() assert tracker is not None # there is an initial session start sequence at the beginning assert [ Event.from_parameters(event) for event in tracker.get("events") ] == session_start_sequence + test_events
def test_json_parse_undo(): evt = {"event": "undo"} assert Event.from_parameters(evt) == ActionReverted()
def test_json_parse_rewind(): evt = {"event": "rewind"} assert Event.from_parameters(evt) == UserUtteranceReverted()
def test_json_parse_bot(): evt = {"event": "bot", "text": "Hey there!", "data": {}} assert Event.from_parameters(evt) == BotUttered("Hey there!", {})
def test_json_parse_pause(): evt = {"event": "pause"} assert Event.from_parameters(evt) == ConversationPaused()
def test_json_parse_restarted(): evt = {"event": "restart"} assert Event.from_parameters(evt) == Restarted()
def test_json_parse_action(): evt = {"event": "action", "name": "my_action"} assert Event.from_parameters(evt) == ActionExecuted("my_action")
def test_json_parse_export(): evt = {"event": "export"} assert Event.from_parameters(evt) == StoryExported()
def test_json_parse_followup(): evt = {"event": "followup", "name": "my_action"} assert Event.from_parameters(evt) == FollowupAction("my_action")
def test_json_parse_session_started(): evt = {"event": "session_started"} assert Event.from_parameters(evt) == SessionStarted()
def test_json_parse_resume(): evt = {"event": "resume"} assert Event.from_parameters(evt) == ConversationResumed()
def test_json_parse_reset(): evt = {"event": "reset_slots"} assert Event.from_parameters(evt) == AllSlotsReset()
def test_json_parse_agent(): evt = {"event": "agent", "text": "Hey, how are you?"} assert Event.from_parameters(evt) == AgentUttered("Hey, how are you?")
def test_json_parse_setslot(): evt = {"event": "slot", "name": "departure_airport", "value": "BER"} assert Event.from_parameters(evt) == SlotSet("departure_airport", "BER")