dc6079821b
CI Github Actions / Run Tests (push) Waiting to run
Automatic PR Merger / mergepal (push) Waiting to run
Semgrep / Semgrep Workflow Security Scan (push) Waiting to run
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
719 lines
23 KiB
Python
719 lines
23 KiB
Python
import logging
|
|
|
|
import jwt
|
|
from typing import Dict
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import pytest
|
|
from _pytest.logging import LogCaptureFixture
|
|
from _pytest.monkeypatch import MonkeyPatch
|
|
from aiogram.utils.exceptions import TelegramAPIError
|
|
from aiohttp import ClientTimeout
|
|
from aioresponses import aioresponses
|
|
from sanic import Sanic
|
|
|
|
import rasa.core.run
|
|
import rasa.core.channels.channel
|
|
from rasa.core import utils
|
|
from rasa.core.channels import RasaChatInput, console
|
|
from rasa.core.channels.channel import UserMessage
|
|
from rasa.core.channels.rasa_chat import (
|
|
JWT_USERNAME_KEY,
|
|
CONVERSATION_ID_KEY,
|
|
INTERACTIVE_LEARNING_PERMISSION,
|
|
)
|
|
from rasa.core.channels.telegram import TelegramOutput
|
|
from rasa.shared.exceptions import RasaException
|
|
from rasa.utils.endpoints import EndpointConfig
|
|
from tests.core import utilities
|
|
|
|
# this is needed so that the tests included as code examples look better
|
|
from tests.utilities import json_of_latest_request, latest_request
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def noop(*args, **kwargs):
|
|
"""Just do nothing."""
|
|
pass
|
|
|
|
|
|
async def test_send_response(default_channel, default_tracker):
|
|
text_only_message = {"text": "hey"}
|
|
multiline_text_message = {
|
|
"text": "This message should come first: \n\n"
|
|
"This is message two \nThis as well\n\n"
|
|
}
|
|
image_only_message = {"image": "https://i.imgur.com/nGF1K8f.jpg"}
|
|
text_and_image_message = {
|
|
"text": "look at this",
|
|
"image": "https://i.imgur.com/T5xVo.jpg",
|
|
}
|
|
custom_json_message = {
|
|
"text": "look at this",
|
|
"custom": {"some_random_arg": "value", "another_arg": "value2"},
|
|
}
|
|
|
|
await default_channel.send_response(default_tracker.sender_id, text_only_message)
|
|
await default_channel.send_response(
|
|
default_tracker.sender_id, multiline_text_message
|
|
)
|
|
await default_channel.send_response(default_tracker.sender_id, image_only_message)
|
|
await default_channel.send_response(
|
|
default_tracker.sender_id, text_and_image_message
|
|
)
|
|
await default_channel.send_response(default_tracker.sender_id, custom_json_message)
|
|
collected = default_channel.messages
|
|
|
|
assert len(collected) == 8
|
|
|
|
# text only message
|
|
assert collected[0] == {"recipient_id": "my-sender", "text": "hey"}
|
|
|
|
# multiline text message, should split on '\n\n'
|
|
assert collected[1] == {
|
|
"recipient_id": "my-sender",
|
|
"text": "This message should come first: ",
|
|
}
|
|
assert collected[2] == {
|
|
"recipient_id": "my-sender",
|
|
"text": "This is message two \nThis as well",
|
|
}
|
|
|
|
# image only message
|
|
assert collected[3] == {
|
|
"recipient_id": "my-sender",
|
|
"image": "https://i.imgur.com/nGF1K8f.jpg",
|
|
}
|
|
|
|
# text & image combined - will result in two messages
|
|
assert collected[4] == {"recipient_id": "my-sender", "text": "look at this"}
|
|
assert collected[5] == {
|
|
"recipient_id": "my-sender",
|
|
"image": "https://i.imgur.com/T5xVo.jpg",
|
|
}
|
|
assert collected[6] == {"recipient_id": "my-sender", "text": "look at this"}
|
|
assert collected[7] == {
|
|
"recipient_id": "my-sender",
|
|
"custom": {"some_random_arg": "value", "another_arg": "value2"},
|
|
}
|
|
|
|
|
|
async def test_console_input():
|
|
from rasa.core.channels import console
|
|
|
|
# Overwrites the input() function and when someone else tries to read
|
|
# something from the command line this function gets called.
|
|
with utilities.mocked_cmd_input(console, text="Test Input"):
|
|
with aioresponses() as mocked:
|
|
mocked.post(
|
|
"https://example.com/webhooks/rest/webhook?stream=true",
|
|
repeat=True,
|
|
payload={},
|
|
)
|
|
|
|
await console.record_messages(
|
|
server_url="https://example.com",
|
|
max_message_limit=3,
|
|
sender_id="default",
|
|
)
|
|
|
|
r = latest_request(
|
|
mocked, "POST", "https://example.com/webhooks/rest/webhook?stream=true"
|
|
)
|
|
|
|
assert r
|
|
|
|
b = json_of_latest_request(r)
|
|
|
|
assert b == {"message": "Test Input", "sender": "default"}
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_webexteams_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.webexteams import WebexTeamsInput
|
|
|
|
input_channel = WebexTeamsInput(
|
|
access_token="YOUR_ACCESS_TOKEN",
|
|
# this is the `bot access token`
|
|
room="YOUR_WEBEX_ROOM"
|
|
# the name of your channel to which the bot posts (optional)
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["webexteams_webhook.health"].startswith("/webhooks/webexteams")
|
|
assert routes_list["webexteams_webhook.webhook"].startswith(
|
|
"/webhooks/webexteams/webhook"
|
|
)
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_slack_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.slack import SlackInput
|
|
|
|
input_channel = SlackInput(
|
|
# this is the Slack Bot Token
|
|
slack_token="YOUR_SLACK_TOKEN",
|
|
# the name of your channel to which the bot posts (optional)
|
|
slack_channel="YOUR_SLACK_CHANNEL",
|
|
# signing secret from slack to verify incoming webhook messages
|
|
slack_signing_secret="YOUR_SIGNING_SECRET",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["slack_webhook.health"].startswith("/webhooks/slack")
|
|
assert routes_list["slack_webhook.webhook"].startswith("/webhooks/slack/webhook")
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_mattermost_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.mattermost import MattermostInput
|
|
|
|
input_channel = MattermostInput(
|
|
# this is the url of the api for your mattermost instance
|
|
url="http://chat.example.com/api/v4",
|
|
# the bot token of the bot account that will post messages
|
|
token="xxxxx",
|
|
# the password of your bot user that will post messages
|
|
# the webhook-url your bot should listen for messages
|
|
webhook_url="YOUR_WEBHOOK_URL",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["mattermost_webhook.health"].startswith("/webhooks/mattermost")
|
|
assert routes_list["mattermost_webhook.webhook"].startswith(
|
|
"/webhooks/mattermost/webhook"
|
|
)
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_botframework_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.botframework import BotFrameworkInput
|
|
|
|
input_channel = BotFrameworkInput(
|
|
# you get this from your Bot Framework account
|
|
app_id="MICROSOFT_APP_ID",
|
|
# also from your Bot Framework account
|
|
app_password="MICROSOFT_APP_PASSWORD",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["botframework_webhook.health"].startswith(
|
|
"/webhooks/botframework"
|
|
)
|
|
assert routes_list["botframework_webhook.webhook"].startswith(
|
|
"/webhooks/botframework/webhook"
|
|
)
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_rocketchat_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.rocketchat import RocketChatInput
|
|
|
|
input_channel = RocketChatInput(
|
|
# your bots rocket chat user name
|
|
user="yourbotname",
|
|
# the password for your rocket chat bots account
|
|
password="YOUR_PASSWORD",
|
|
# url where your rocket chat instance is running
|
|
server_url="https://demo.rocket.chat",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["rocketchat_webhook.health"].startswith("/webhooks/rocketchat")
|
|
assert routes_list["rocketchat_webhook.webhook"].startswith(
|
|
"/webhooks/rocketchat/webhook"
|
|
)
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
@pytest.mark.filterwarnings("ignore:unclosed file.*:ResourceWarning")
|
|
# telegram channel will try to set a webhook, so we need to mock the api
|
|
@patch.object(TelegramOutput, "set_webhook", noop)
|
|
def test_telegram_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.telegram import TelegramInput
|
|
|
|
input_channel = TelegramInput(
|
|
# you get this when setting up a bot
|
|
access_token="123:YOUR_ACCESS_TOKEN",
|
|
# this is your bots username
|
|
verify="YOUR_TELEGRAM_BOT",
|
|
# the url your bot should listen for messages
|
|
webhook_url="YOUR_WEBHOOK_URL",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["telegram_webhook.health"].startswith("/webhooks/telegram")
|
|
assert routes_list["telegram_webhook.message"].startswith(
|
|
"/webhooks/telegram/webhook"
|
|
)
|
|
|
|
|
|
def test_telegram_channel_raise_rasa_exception_webhook_not_set(
|
|
monkeypatch: MonkeyPatch,
|
|
):
|
|
from rasa.core.channels.telegram import TelegramInput
|
|
|
|
input_channel = TelegramInput(
|
|
# you get this when setting up a bot
|
|
access_token="123:YOUR_ACCESS_TOKEN",
|
|
# this is your bots username
|
|
verify="YOUR_TELEGRAM_BOT",
|
|
# the url your bot should listen for messages
|
|
webhook_url="",
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
rasa.core.channels.telegram.TelegramOutput,
|
|
"set_webhook",
|
|
MagicMock(side_effect=TelegramAPIError("Error from Telegram.")),
|
|
)
|
|
|
|
with pytest.raises(RasaException) as e:
|
|
rasa.core.run.configure_app([input_channel], port=5004)
|
|
|
|
assert "Failed to set channel webhook:" in str(e.value)
|
|
|
|
|
|
async def test_handling_of_integer_user_id():
|
|
# needed for telegram to work properly as this channel sends integer ids,
|
|
# but we expect the sender_id to be a string everywhere else
|
|
|
|
assert UserMessage("hello", sender_id=123).sender_id == "123"
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_twilio_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.twilio import TwilioInput
|
|
|
|
input_channel = TwilioInput(
|
|
# you get this from your twilio account
|
|
account_sid="YOUR_ACCOUNT_SID",
|
|
# also from your twilio account
|
|
auth_token="YOUR_AUTH_TOKEN",
|
|
# a number associated with your twilio account
|
|
twilio_number="YOUR_TWILIO_NUMBER",
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["twilio_webhook.health"].startswith("/webhooks/twilio")
|
|
assert routes_list["twilio_webhook.message"].startswith("/webhooks/twilio/webhook")
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_callback_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.callback import CallbackInput
|
|
|
|
input_channel = CallbackInput(
|
|
# URL Core will call to send the bot responses
|
|
endpoint=EndpointConfig("http://localhost:5004")
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["callback_webhook.health"].startswith("/webhooks/callback")
|
|
assert routes_list["callback_webhook.webhook"].startswith(
|
|
"/webhooks/callback/webhook"
|
|
)
|
|
|
|
|
|
# USED FOR DOCS - don't rename without changing in the docs
|
|
def test_socketio_channel():
|
|
# START DOC INCLUDE
|
|
from rasa.core.channels.socketio import SocketIOInput
|
|
|
|
input_channel = SocketIOInput(
|
|
# event name for messages sent from the user
|
|
user_message_evt="user_uttered",
|
|
# event name for messages sent from the bot
|
|
bot_message_evt="bot_uttered",
|
|
# socket.io namespace to use for the messages
|
|
namespace=None,
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["socketio_webhook.health"].startswith("/webhooks/socketio")
|
|
assert routes_list["handle_request"].startswith("/socket.io")
|
|
|
|
|
|
def test_socketio_channel_metadata():
|
|
from rasa.core.channels.socketio import SocketIOInput
|
|
|
|
input_channel = SocketIOInput(
|
|
# event name for messages sent from the user
|
|
user_message_evt="user_uttered",
|
|
# event name for messages sent from the bot
|
|
bot_message_evt="bot_uttered",
|
|
# optional metadata key name
|
|
metadata_key="customData",
|
|
# socket.io namespace to use for the messages
|
|
namespace=None,
|
|
)
|
|
|
|
s = rasa.core.run.configure_app([input_channel], port=5004)
|
|
# END DOC INCLUDE
|
|
# the above marker marks the end of the code snipped included
|
|
# in the docs
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["socketio_webhook.health"].startswith("/webhooks/socketio")
|
|
assert routes_list["handle_request"].startswith("/socket.io")
|
|
|
|
|
|
async def test_socketio_channel_jwt_authentication():
|
|
from rasa.core.channels.socketio import SocketIOInput
|
|
|
|
public_key = "random_key123"
|
|
jwt_algorithm = "HS256"
|
|
auth_token = jwt.encode({"payload": "value"}, public_key, algorithm=jwt_algorithm)
|
|
|
|
input_channel = SocketIOInput(
|
|
# event name for messages sent from the user
|
|
user_message_evt="user_uttered",
|
|
# event name for messages sent from the bot
|
|
bot_message_evt="bot_uttered",
|
|
# socket.io namespace to use for the messages
|
|
namespace=None,
|
|
# public key for JWT methods
|
|
jwt_key=public_key,
|
|
# method used for the signature of the JWT authentication payload
|
|
jwt_method=jwt_algorithm,
|
|
)
|
|
|
|
assert input_channel.jwt_key == public_key
|
|
assert input_channel.jwt_algorithm == jwt_algorithm
|
|
assert rasa.core.channels.channel.decode_bearer_token(
|
|
auth_token, input_channel.jwt_key, input_channel.jwt_algorithm
|
|
)
|
|
|
|
|
|
async def test_socketio_channel_jwt_authentication_invalid_key(
|
|
caplog: LogCaptureFixture,
|
|
):
|
|
from rasa.core.channels.socketio import SocketIOInput
|
|
|
|
public_key = "random_key123"
|
|
invalid_public_key = "my_invalid_key"
|
|
jwt_algorithm = "HS256"
|
|
invalid_auth_token = jwt.encode(
|
|
{"payload": "value"}, invalid_public_key, algorithm=jwt_algorithm
|
|
)
|
|
|
|
input_channel = SocketIOInput(
|
|
# event name for messages sent from the user
|
|
user_message_evt="user_uttered",
|
|
# event name for messages sent from the bot
|
|
bot_message_evt="bot_uttered",
|
|
# socket.io namespace to use for the messages
|
|
namespace=None,
|
|
# public key for JWT methods
|
|
jwt_key=public_key,
|
|
# method used for the signature of the JWT authentication payload
|
|
jwt_method=jwt_algorithm,
|
|
)
|
|
|
|
assert input_channel.jwt_key == public_key
|
|
assert input_channel.jwt_algorithm == jwt_algorithm
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
rasa.core.channels.channel.decode_bearer_token(
|
|
invalid_auth_token, input_channel.jwt_key, input_channel.jwt_algorithm
|
|
)
|
|
|
|
assert any("JWT public key invalid." in message for message in caplog.messages)
|
|
|
|
|
|
async def test_callback_calls_endpoint():
|
|
from rasa.core.channels.callback import CallbackOutput
|
|
|
|
with aioresponses() as mocked:
|
|
mocked.post(
|
|
"https://example.com/callback",
|
|
repeat=True,
|
|
headers={"Content-Type": "application/json"},
|
|
)
|
|
|
|
output = CallbackOutput(EndpointConfig("https://example.com/callback"))
|
|
|
|
await output.send_response(
|
|
"test-id", {"text": "Hi there!", "image": "https://example.com/image.jpg"}
|
|
)
|
|
|
|
r = latest_request(mocked, "post", "https://example.com/callback")
|
|
|
|
assert r
|
|
|
|
image = r[-1].kwargs["json"]
|
|
text = r[-2].kwargs["json"]
|
|
|
|
assert image["recipient_id"] == "test-id"
|
|
assert image["image"] == "https://example.com/image.jpg"
|
|
|
|
assert text["recipient_id"] == "test-id"
|
|
assert text["text"] == "Hi there!"
|
|
|
|
|
|
def test_botframework_attachments():
|
|
from rasa.core.channels.botframework import BotFrameworkInput
|
|
from copy import deepcopy
|
|
|
|
ch = BotFrameworkInput("app_id", "app_pass")
|
|
|
|
payload = {
|
|
"type": "message",
|
|
"id": "123",
|
|
"channelId": "msteams",
|
|
"serviceUrl": "https://smba.trafficmanager.net/emea/",
|
|
"from": {"id": "12:123", "name": "Rasa", "aadObjectId": "123"},
|
|
"conversation": {
|
|
"conversationType": "personal",
|
|
"tenantId": "123",
|
|
"id": "a:123",
|
|
},
|
|
"recipient": {"id": "12:123", "name": "Rasa chat"},
|
|
}
|
|
assert ch.add_attachments_to_metadata(payload, None) is None
|
|
|
|
attachments = [
|
|
{
|
|
"contentType": "application/vnd.microsoft.teams.file.download.info",
|
|
"content": {
|
|
"downloadUrl": "https://test.sharepoint.com/personal/rasa/123",
|
|
"uniqueId": "123",
|
|
"fileType": "csv",
|
|
},
|
|
"contentUrl": "https://test.sharepoint.com/personal/rasa/123",
|
|
"name": "rasa-test.csv",
|
|
}
|
|
]
|
|
payload["attachments"] = attachments
|
|
|
|
assert ch.add_attachments_to_metadata(payload, None) == {"attachments": attachments}
|
|
|
|
metadata = {"test": 1, "bigger_test": {"key": "value"}}
|
|
updated_metadata = deepcopy(metadata)
|
|
updated_metadata.update({"attachments": attachments})
|
|
|
|
assert ch.add_attachments_to_metadata(payload, metadata) == updated_metadata
|
|
|
|
|
|
@pytest.mark.filterwarnings("ignore:unclosed.*:ResourceWarning")
|
|
def test_channel_inheritance():
|
|
from rasa.core.channels import RestInput
|
|
from rasa.core.channels.rasa_chat import RasaChatInput
|
|
|
|
rasa_input = RasaChatInput("https://example.com")
|
|
|
|
s = rasa.core.run.configure_app([RestInput(), rasa_input], port=5004)
|
|
|
|
routes_list = utils.list_routes(s)
|
|
assert routes_list["custom_webhook_RasaChatInput.health"].startswith(
|
|
"/webhooks/rasa"
|
|
)
|
|
assert routes_list["custom_webhook_RasaChatInput.receive"].startswith(
|
|
"/webhooks/rasa/webhook"
|
|
)
|
|
|
|
|
|
def test_int_sender_id_in_user_message():
|
|
from rasa.core.channels.channel import UserMessage
|
|
|
|
# noinspection PyTypeChecker
|
|
message = UserMessage("A text", sender_id=1234567890)
|
|
|
|
assert message.sender_id == "1234567890"
|
|
|
|
|
|
def test_int_message_id_in_user_message():
|
|
from rasa.core.channels.channel import UserMessage
|
|
|
|
# noinspection PyTypeChecker
|
|
message = UserMessage("B text", message_id=987654321)
|
|
|
|
assert message.message_id == "987654321"
|
|
|
|
|
|
async def test_send_elements_without_buttons():
|
|
from rasa.core.channels.channel import OutputChannel
|
|
|
|
async def test_message(sender, message):
|
|
assert sender == "user"
|
|
assert message == "a : b"
|
|
|
|
channel = OutputChannel()
|
|
channel.send_text_message = test_message
|
|
await channel.send_elements("user", [{"title": "a", "subtitle": "b"}])
|
|
|
|
|
|
def test_newsline_strip():
|
|
from rasa.core.channels.channel import UserMessage
|
|
|
|
message = UserMessage("\n/restart\n")
|
|
|
|
assert message.text == "/restart"
|
|
|
|
|
|
def test_register_channel_without_route():
|
|
"""Check we properly connect the input channel blueprint if route is None"""
|
|
from rasa.core.channels import RestInput
|
|
import rasa.core
|
|
|
|
input_channel = RestInput()
|
|
|
|
app = Sanic("test_channels")
|
|
rasa.core.channels.channel.register([input_channel], app, route=None)
|
|
|
|
routes_list = utils.list_routes(app)
|
|
assert routes_list["test_channels.custom_webhook_RestInput.receive"].startswith(
|
|
"/webhook"
|
|
)
|
|
|
|
|
|
def test_channel_registration_with_absolute_url_prefix_overwrites_route():
|
|
from rasa.core.channels import RestInput
|
|
import rasa.core
|
|
|
|
input_channel = RestInput()
|
|
test_route = "/absolute_route"
|
|
input_channel.url_prefix = lambda: test_route
|
|
|
|
app = Sanic("test_channels")
|
|
ignored_base_route = "/should_be_ignored"
|
|
rasa.core.channels.channel.register(
|
|
[input_channel], app, route="/should_be_ignored"
|
|
)
|
|
|
|
# Assure that an absolute url returned by `url_prefix` overwrites route parameter
|
|
# given in `register`.
|
|
routes_list = utils.list_routes(app)
|
|
assert routes_list["test_channels.custom_webhook_RestInput.health"].startswith(
|
|
test_route
|
|
)
|
|
assert ignored_base_route not in routes_list.get(
|
|
"test_channels.custom_webhook_RestInput.health"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"test_input, expected",
|
|
[
|
|
({}, "rest"),
|
|
({"input_channel": None}, "rest"),
|
|
({"input_channel": "custom"}, "custom"),
|
|
],
|
|
)
|
|
def test_extract_input_channel(test_input, expected):
|
|
from rasa.core.channels import RestInput
|
|
|
|
input_channel = RestInput()
|
|
|
|
fake_request = MagicMock()
|
|
fake_request.json = test_input
|
|
|
|
assert input_channel._extract_input_channel(fake_request) == expected
|
|
|
|
|
|
async def test_rasa_chat_input():
|
|
from rasa.core.channels import RasaChatInput
|
|
|
|
rasa_x_api_url = "https://rasa-x.com:5002"
|
|
rasa_chat_input = RasaChatInput(rasa_x_api_url)
|
|
public_key = "random_key123"
|
|
jwt_algorithm = "RS256"
|
|
with aioresponses() as mocked:
|
|
mocked.get(
|
|
rasa_x_api_url + "/version",
|
|
payload={"keys": [{"key": public_key, "alg": jwt_algorithm}]},
|
|
repeat=True,
|
|
status=200,
|
|
)
|
|
await rasa_chat_input._fetch_public_key()
|
|
assert rasa_chat_input.jwt_key == public_key
|
|
assert rasa_chat_input.jwt_algorithm == jwt_algorithm
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"jwt, message",
|
|
[
|
|
({JWT_USERNAME_KEY: "abc"}, {CONVERSATION_ID_KEY: "abc"}),
|
|
(
|
|
{
|
|
JWT_USERNAME_KEY: "abc",
|
|
"scopes": ["a", "b", INTERACTIVE_LEARNING_PERMISSION],
|
|
},
|
|
{CONVERSATION_ID_KEY: "test"},
|
|
),
|
|
],
|
|
)
|
|
def test_has_user_permission_to_send_messages_to_conversation(jwt: Dict, message: Dict):
|
|
assert RasaChatInput._has_user_permission_to_send_messages_to_conversation(
|
|
jwt, message
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"jwt, message",
|
|
[
|
|
({JWT_USERNAME_KEY: "abc"}, {CONVERSATION_ID_KEY: "xyz"}),
|
|
(
|
|
{JWT_USERNAME_KEY: "abc", "scopes": ["a", "b"]},
|
|
{CONVERSATION_ID_KEY: "test"},
|
|
),
|
|
],
|
|
)
|
|
def test_has_user_permission_to_send_messages_to_conversation_without_permission(
|
|
jwt: Dict, message: Dict
|
|
):
|
|
assert not RasaChatInput._has_user_permission_to_send_messages_to_conversation(
|
|
jwt, message
|
|
)
|
|
|
|
|
|
def test_set_console_stream_reading_timeout(monkeypatch: MonkeyPatch):
|
|
expected = 100
|
|
monkeypatch.setenv(console.STREAM_READING_TIMEOUT_ENV, str(100))
|
|
|
|
assert console._get_stream_reading_timeout() == ClientTimeout(expected)
|