async def test_remote_action_without_endpoint(default_channel, default_nlg, default_tracker, default_domain): remote_action = action.RemoteAction("my_action", None) with pytest.raises(Exception) as execinfo: await remote_action.run(default_channel, default_nlg, default_tracker, default_domain) assert "Failed to execute custom action." in str(execinfo.value)
async def test_remote_action_logs_events(default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [ {"event": "slot", "value": "rasa", "name": "name"}], "responses": [{"text": "test text", "buttons": [{"title": "cheap", "payload": "cheap"}]}, {"template": "utter_greet"}]} with aioresponses() as mocked: mocked.post('https://example.com/webhooks/actions', payload=response) events = await remote_action.run(default_dispatcher_collecting, tracker, default_domain) r = latest_request(mocked, 'post', "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { 'domain': default_domain.as_dict(), 'next_action': 'my_action', 'sender_id': 'default', 'version': rasa.__version__, 'tracker': { 'latest_message': { 'entities': [], 'intent': {}, 'text': None }, 'active_form': {}, 'latest_action_name': None, 'sender_id': 'default', 'paused': False, 'followup_action': 'action_listen', 'latest_event_time': None, 'slots': {'name': None}, 'events': [], 'latest_input_channel': None } } assert events == [SlotSet("name", "rasa")] channel = default_dispatcher_collecting.output_channel assert channel.messages == [ {"text": "test text", "recipient_id": "my-sender", "buttons": [{"title": "cheap", "payload": "cheap"}]}, {"text": "hey there None!", "recipient_id": "my-sender"}]
async def test_remote_action_endpoint_not_running( default_channel, default_nlg, default_tracker, domain: Domain ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with pytest.raises(Exception) as execinfo: await remote_action.run(default_channel, default_nlg, default_tracker, domain) assert "Failed to execute custom action." in str(execinfo.value)
async def test_remote_action_runs( default_channel: OutputChannel, default_nlg: NaturalLanguageGenerator, default_tracker: DialogueStateTracker, domain: Domain, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: mocked.post( "https://example.com/webhooks/actions", payload={ "events": [], "responses": [] }, ) await remote_action.run(default_channel, default_nlg, default_tracker, domain) r = latest_request(mocked, "post", "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { "domain": domain.as_dict(), "next_action": "my_action", "sender_id": "my-sender", "version": rasa.__version__, "tracker": { "latest_message": { "entities": [], "intent": {}, "text": None, "message_id": None, "metadata": {}, }, ACTIVE_LOOP: {}, "latest_action": {}, "latest_action_name": None, "sender_id": "my-sender", "paused": False, "latest_event_time": None, FOLLOWUP_ACTION: "action_listen", "slots": { "name": None, REQUESTED_SLOT: None, SESSION_START_METADATA_SLOT: None, }, "events": [], "latest_input_channel": None, }, }
async def test_remote_action_without_endpoint(default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) remote_action = action.RemoteAction("my_action", None) with pytest.raises(Exception) as execinfo: await remote_action.run(default_dispatcher_collecting, tracker, default_domain) assert "you didn't configure an endpoint" in str(execinfo.value)
async def test_remote_action_logs_events( default_channel, default_nlg, default_tracker, default_domain ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [{"event": "slot", "value": "rasa", "name": "name"}], "responses": [ {"text": "test text", "buttons": [{"title": "cheap", "payload": "cheap"}]}, {"template": "utter_greet"}, ], } with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run( default_channel, default_nlg, default_tracker, default_domain ) r = latest_request(mocked, "post", "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { "domain": default_domain.as_dict(), "next_action": "my_action", "sender_id": "my-sender", "version": rasa.__version__, "tracker": { "latest_message": { "entities": [], "intent": {}, "text": None, "message_id": None, "metadata": None, }, "active_form": {}, "latest_action_name": None, "sender_id": "my-sender", "paused": False, "followup_action": "action_listen", "latest_event_time": None, "slots": {"name": None}, "events": [], "latest_input_channel": None, }, } assert len(events) == 3 # first two events are bot utterances assert events[0] == BotUttered( "test text", {"buttons": [{"title": "cheap", "payload": "cheap"}]} ) assert events[1] == BotUttered("hey there None!") assert events[2] == SlotSet("name", "rasa")
async def test_remote_action_endpoint_not_running( default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with pytest.raises(Exception) as execinfo: await remote_action.run(default_dispatcher_collecting, tracker, default_domain) assert "Failed to execute custom action." in str(execinfo.value)
async def test_remote_action_logs_events(default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [{"event": "slot", "value": "rasa", "name": "name"}], "responses": [ {"text": "test text", "buttons": [{"title": "cheap", "payload": "cheap"}]}, {"template": "utter_greet"}, ], } with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run( default_dispatcher_collecting, tracker, default_domain ) r = latest_request(mocked, "post", "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { "domain": default_domain.as_dict(), "next_action": "my_action", "sender_id": "default", "version": rasa.__version__, "tracker": { "latest_message": {"entities": [], "intent": {}, "text": None}, "active_form": {}, "latest_action_name": None, "sender_id": "default", "paused": False, "followup_action": "action_listen", "latest_event_time": None, "slots": {"name": None}, "events": [], "latest_input_channel": None, }, } assert events == [SlotSet("name", "rasa")] channel = default_dispatcher_collecting.output_channel assert channel.messages == [ { "text": "test text", "recipient_id": "my-sender", "buttons": [{"title": "cheap", "payload": "cheap"}], }, {"text": "hey there None!", "recipient_id": "my-sender"}, ]
async def test_remote_action_multiple_events_payload( default_channel: OutputChannel, default_nlg: NaturalLanguageGenerator, default_tracker: DialogueStateTracker, domain: Domain, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [ { "event": "action", "name": "action_listen", "policy": None, "confidence": None, "timestamp": None, }, { "event": "slot", "name": "name", "value": None, "timestamp": None }, { "event": "user", "timestamp": None, "text": "hello", "parse_data": { "intent": { "name": "greet", "confidence": 0.99 }, "entities": [], }, }, ], "responses": [], } with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run(default_channel, default_nlg, default_tracker, domain) assert isinstance(events[0], ActionExecuted) assert events[0].as_dict().get("name") == "action_listen" assert isinstance(events[1], SlotSet) assert events[1].as_dict().get("name") == "name" assert isinstance(events[2], UserUttered) assert events[2].as_dict().get("text") == "hello"
async def test_remote_action_runs(default_channel, default_nlg, default_tracker, default_domain): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: mocked.post( "https://example.com/webhooks/actions", payload={ "events": [], "responses": [] }, ) await remote_action.run(default_channel, default_nlg, default_tracker, default_domain) r = latest_request(mocked, "post", "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { "domain": default_domain.as_dict(), "next_action": "my_action", "sender_id": "my-sender", "version": rasa.__version__, "tracker": { "latest_message": { "entities": [], "intent": {}, "text": None, "message_id": None, "metadata": {}, }, ACTIVE_LOOP: {}, "latest_action": {}, "latest_action_name": None, "sender_id": "my-sender", "paused": False, "latest_event_time": None, "followup_action": "action_listen", "slots": { "name": None }, "events": [], "latest_input_channel": None, }, }
async def test_remote_action_with_template_param( default_channel: OutputChannel, default_tracker: DialogueStateTracker, domain: Domain, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [ { "event": "form", "name": "restaurant_form", "timestamp": None }, { "event": "slot", "timestamp": None, "name": "requested_slot", "value": "cuisine", }, ], "responses": [{ "text": None, "buttons": [], "elements": [], "custom": {}, "template": "utter_ask_cuisine", "image": None, "attachment": None, }], } nlg = TemplatedNaturalLanguageGenerator( {"utter_ask_cuisine": [{ "text": "what dou want to eat?" }]}) with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) with pytest.warns(FutureWarning): events = await remote_action.run(default_channel, nlg, default_tracker, domain) assert events == [ BotUttered("what dou want to eat?", metadata={"utter_action": "utter_ask_cuisine"}), ActiveLoop("restaurant_form"), SlotSet("requested_slot", "cuisine"), ]
async def test_remote_action_endpoint_responds_500(default_channel, default_nlg, default_tracker, default_domain): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", status=500) with pytest.raises(Exception) as execinfo: await remote_action.run(default_channel, default_nlg, default_tracker, default_domain) assert "Failed to execute custom action." in str(execinfo.value)
async def test_remote_action_runs(default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: mocked.post('https://example.com/webhooks/actions', payload={ "events": [], "responses": [] }) await remote_action.run(default_dispatcher_collecting, tracker, default_domain) r = latest_request(mocked, 'post', "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { 'domain': default_domain.as_dict(), 'next_action': 'my_action', 'sender_id': 'default', 'version': rasa.__version__, 'tracker': { 'latest_message': { 'entities': [], 'intent': {}, 'text': None }, 'active_form': {}, 'latest_action_name': None, 'sender_id': 'default', 'paused': False, 'latest_event_time': None, 'followup_action': 'action_listen', 'slots': { 'name': None }, 'events': [], 'latest_input_channel': None } }
async def test_remote_action_utterances_with_none_values( default_channel, default_tracker, default_domain): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [ { "event": "form", "name": "restaurant_form", "timestamp": None }, { "event": "slot", "timestamp": None, "name": "requested_slot", "value": "cuisine", }, ], "responses": [{ "text": None, "buttons": None, "elements": [], "custom": None, "template": "utter_ask_cuisine", "image": None, "attachment": None, }], } nlg = TemplatedNaturalLanguageGenerator( {"utter_ask_cuisine": [{ "text": "what dou want to eat?" }]}) with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run(default_channel, nlg, default_tracker, default_domain) assert events == [ BotUttered("what dou want to eat?"), Form("restaurant_form"), SlotSet("requested_slot", "cuisine"), ]
async def test_remote_action_valid_payload_all_events( default_channel: OutputChannel, default_nlg: NaturalLanguageGenerator, default_tracker: DialogueStateTracker, domain: Domain, event: Event, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) events = [event.as_dict()] response = {"events": events, "responses": []} with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run(default_channel, default_nlg, default_tracker, domain) assert len(events) == 1
async def test_remote_action_endpoint_responds_400( default_dispatcher_collecting, default_domain): tracker = DialogueStateTracker("default", default_domain.slots) endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: # noinspection PyTypeChecker mocked.post('https://example.com/webhooks/actions', exception=ClientResponseError( 400, None, '{"action_name": "my_action"}')) with pytest.raises(Exception) as execinfo: await remote_action.run(default_dispatcher_collecting, tracker, default_domain) assert execinfo.type == ActionExecutionRejection assert "Custom action 'my_action' rejected to run" in str(execinfo.value)
async def test_remote_action_endpoint_responds_400( default_channel, default_nlg, default_tracker, default_domain ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) with aioresponses() as mocked: # noinspection PyTypeChecker mocked.post( "https://example.com/webhooks/actions", exception=ClientResponseError(400, None, '{"action_name": "my_action"}'), ) with pytest.raises(Exception) as execinfo: await remote_action.run( default_channel, default_nlg, default_tracker, default_domain ) assert execinfo.type == ActionExecutionRejection assert "Custom action 'my_action' rejected to run" in str(execinfo.value)
async def test_remote_action_invalid_entities_payload( default_channel: OutputChannel, default_nlg: NaturalLanguageGenerator, default_tracker: DialogueStateTracker, domain: Domain, event: Event, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [event], "responses": [], } with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) with pytest.raises(ValidationError) as e: await remote_action.run(default_channel, default_nlg, default_tracker, domain) assert "Failed to validate Action server response from API" in str(e.value)
async def test_remote_action_logs_events( default_channel: OutputChannel, default_nlg: NaturalLanguageGenerator, default_tracker: DialogueStateTracker, domain: Domain, ): endpoint = EndpointConfig("https://example.com/webhooks/actions") remote_action = action.RemoteAction("my_action", endpoint) response = { "events": [{ "event": "slot", "value": "rasa", "name": "name" }], "responses": [ { "text": "test text", "response": None, "buttons": [{ "title": "cheap", "payload": "cheap" }], }, { "response": "utter_greet" }, ], } with aioresponses() as mocked: mocked.post("https://example.com/webhooks/actions", payload=response) events = await remote_action.run(default_channel, default_nlg, default_tracker, domain) r = latest_request(mocked, "post", "https://example.com/webhooks/actions") assert r assert json_of_latest_request(r) == { "domain": domain.as_dict(), "next_action": "my_action", "sender_id": "my-sender", "version": rasa.__version__, "tracker": { "latest_message": { "entities": [], "intent": {}, "text": None, "message_id": None, "metadata": {}, }, ACTIVE_LOOP: {}, "latest_action": {}, "latest_action_name": None, "sender_id": "my-sender", "paused": False, FOLLOWUP_ACTION: ACTION_LISTEN_NAME, "latest_event_time": None, "slots": { "name": None, REQUESTED_SLOT: None, SESSION_START_METADATA_SLOT: None, }, "events": [], "latest_input_channel": None, }, } assert len(events) == 3 # first two events are bot utterances assert events[0] == BotUttered( "test text", {"buttons": [{ "title": "cheap", "payload": "cheap" }]}) assert events[1] == BotUttered("hey there None!", metadata={"utter_action": "utter_greet"}) assert events[2] == SlotSet("name", "rasa")