Merge branch '11-amelioration-de-l-experience-utilisateur' into 'master'
Resolve "Amélioration de l'expérience utilisateur" Closes #11 See merge request Neutrinet/matrix-alertbot!10
This commit is contained in:
commit
db69401061
10 changed files with 324 additions and 121 deletions
8
SETUP.md
8
SETUP.md
|
@ -112,12 +112,12 @@ matrix-alertbot other-config.yaml
|
||||||
|
|
||||||
Invite the bot to a room and it should accept the invite and join.
|
Invite the bot to a room and it should accept the invite and join.
|
||||||
|
|
||||||
Matrix AlertBot will process any message starting with the prefix defined in the config. By default, this prefix is `!alert` . Let's test this now.
|
Matrix AlertBot will process any message where its name is mentionned. Let's test this now.
|
||||||
After the bot has successfully joined the room, try sending the following
|
After the bot has successfully joined the room, try sending the following
|
||||||
in a message:
|
in a message:
|
||||||
|
|
||||||
```
|
```
|
||||||
!alert help
|
@bot_name help
|
||||||
```
|
```
|
||||||
|
|
||||||
The bot should reply with an help message, explaining how to handle alerts.
|
The bot should reply with an help message, explaining how to handle alerts.
|
||||||
|
@ -129,7 +129,7 @@ or by reacting with certain emojis.
|
||||||
For instance, if you reply to the alert with:
|
For instance, if you reply to the alert with:
|
||||||
|
|
||||||
```
|
```
|
||||||
!alert ack
|
@bot_name ack
|
||||||
```
|
```
|
||||||
|
|
||||||
This will create a silence for this alert until it is resolved.
|
This will create a silence for this alert until it is resolved.
|
||||||
|
@ -138,7 +138,7 @@ You can at any moment reply to the alert with the following to remove the
|
||||||
silence:
|
silence:
|
||||||
|
|
||||||
```
|
```
|
||||||
!alert unack
|
@bot_name unack
|
||||||
```
|
```
|
||||||
|
|
||||||
Removing a reaction to an alert will also remove the silence.
|
Removing a reaction to an alert will also remove the silence.
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
# Below you will find various config sections and options
|
# Below you will find various config sections and options
|
||||||
# Default values are shown
|
# Default values are shown
|
||||||
|
|
||||||
# The string to prefix messages with to talk to the bot in group chats
|
|
||||||
command_prefix: "!alert"
|
|
||||||
|
|
||||||
# Options for connecting to the bot's Matrix account
|
# Options for connecting to the bot's Matrix account
|
||||||
matrix:
|
matrix:
|
||||||
accounts:
|
accounts:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
from diskcache import Cache
|
from diskcache import Cache
|
||||||
from nio.client import AsyncClient
|
from nio.client import AsyncClient
|
||||||
|
@ -23,7 +24,12 @@ from nio.rooms import MatrixRoom
|
||||||
import matrix_alertbot.matrix
|
import matrix_alertbot.matrix
|
||||||
from matrix_alertbot.alertmanager import AlertmanagerClient
|
from matrix_alertbot.alertmanager import AlertmanagerClient
|
||||||
from matrix_alertbot.chat_functions import strip_fallback
|
from matrix_alertbot.chat_functions import strip_fallback
|
||||||
from matrix_alertbot.command import AckAlertCommand, CommandFactory, UnackAlertCommand
|
from matrix_alertbot.command import (
|
||||||
|
AckAlertCommand,
|
||||||
|
AngryUserCommand,
|
||||||
|
CommandFactory,
|
||||||
|
UnackAlertCommand,
|
||||||
|
)
|
||||||
from matrix_alertbot.config import Config
|
from matrix_alertbot.config import Config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -53,7 +59,6 @@ class Callbacks:
|
||||||
self.cache = cache
|
self.cache = cache
|
||||||
self.alertmanager_client = alertmanager_client
|
self.alertmanager_client = alertmanager_client
|
||||||
self.config = config
|
self.config = config
|
||||||
self.command_prefix = config.command_prefix
|
|
||||||
|
|
||||||
async def message(self, room: MatrixRoom, event: RoomMessageText) -> None:
|
async def message(self, room: MatrixRoom, event: RoomMessageText) -> None:
|
||||||
"""Callback for when a message event is received
|
"""Callback for when a message event is received
|
||||||
|
@ -83,13 +88,22 @@ class Callbacks:
|
||||||
f"Event ID {event.event_id} | Sender {event.sender} | "
|
f"Event ID {event.event_id} | Sender {event.sender} | "
|
||||||
f"Message received: {msg}"
|
f"Message received: {msg}"
|
||||||
)
|
)
|
||||||
# Process as message if in a public room without command prefix
|
|
||||||
has_command_prefix = msg.startswith(self.command_prefix)
|
user_id_patterns = []
|
||||||
if not has_command_prefix:
|
for user_id in self.config.user_ids:
|
||||||
|
user, homeserver = user_id.split(":")
|
||||||
|
username = user[1:]
|
||||||
|
user_id_patterns.append(rf"@?{username}(:{homeserver})?")
|
||||||
|
|
||||||
|
pattern = re.compile(
|
||||||
|
rf"(^|\s+)({'|'.join(user_id_patterns)})(\s+|$)",
|
||||||
|
re.IGNORECASE | re.MULTILINE,
|
||||||
|
)
|
||||||
|
if pattern.search(msg) is None:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Bot {self.matrix_client.user_id} | Room ID {room.room_id} | "
|
f"Bot {self.matrix_client.user_id} | Room ID {room.room_id} | "
|
||||||
f"Event ID {event.event_id} | Sender {event.sender} | "
|
f"Event ID {event.event_id} | Sender {event.sender} | "
|
||||||
f"Cannot process message: Command prefix {self.command_prefix} not provided."
|
f"Cannot process message: Bot was not mentionned."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -107,8 +121,8 @@ class Callbacks:
|
||||||
f"Command received is in reply to event ID {reacted_to_event_id}"
|
f"Command received is in reply to event ID {reacted_to_event_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove the command prefix
|
# Remove the mention of the bot
|
||||||
cmd = msg[len(self.command_prefix) :]
|
cmd = pattern.sub(" ", msg).strip()
|
||||||
try:
|
try:
|
||||||
command = CommandFactory.create(
|
command = CommandFactory.create(
|
||||||
cmd,
|
cmd,
|
||||||
|
@ -271,6 +285,27 @@ class Callbacks:
|
||||||
exc_info=e,
|
exc_info=e,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if event.key in self.config.insult_reactions:
|
||||||
|
command = AngryUserCommand(
|
||||||
|
self.matrix_client,
|
||||||
|
self.cache,
|
||||||
|
self.alertmanager_client,
|
||||||
|
self.config,
|
||||||
|
room,
|
||||||
|
event.sender,
|
||||||
|
event.event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await command.process()
|
||||||
|
except (SendRetryError, LocalProtocolError) as e:
|
||||||
|
logger.exception(
|
||||||
|
f"Bot {self.matrix_client.user_id} | Room ID {room.room_id} | "
|
||||||
|
f"Event ID {event.event_id} | Sender {event.sender} | "
|
||||||
|
f"Cannot send message to room.",
|
||||||
|
exc_info=e,
|
||||||
|
)
|
||||||
|
|
||||||
async def redaction(self, room: MatrixRoom, event: RedactionEvent) -> None:
|
async def redaction(self, room: MatrixRoom, event: RedactionEvent) -> None:
|
||||||
# Ignore message when we aren't the leader in the client pool
|
# Ignore message when we aren't the leader in the client pool
|
||||||
if self.matrix_client is not self.matrix_client_pool.matrix_client:
|
if self.matrix_client is not self.matrix_client_pool.matrix_client:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
from typing import Optional, Tuple, cast
|
from typing import Optional, Tuple, cast
|
||||||
|
|
||||||
import pytimeparse2
|
import pytimeparse2
|
||||||
|
@ -237,22 +238,58 @@ class HelpCommand(BaseCommand):
|
||||||
async def process(self) -> None:
|
async def process(self) -> None:
|
||||||
"""Show the help text"""
|
"""Show the help text"""
|
||||||
logger.debug(f"Displaying help to room {self.room.display_name}")
|
logger.debug(f"Displaying help to room {self.room.display_name}")
|
||||||
if not self.args:
|
if len(self.args) == 0:
|
||||||
text = (
|
text = (
|
||||||
"Hello, I am a bot made with matrix-nio! Use `help commands` to view "
|
"Hello, I am a bot made with matrix-nio! Use 'help commands' to view "
|
||||||
"available commands."
|
"available commands."
|
||||||
)
|
)
|
||||||
await send_text_to_room(self.matrix_client, self.room.room_id, text)
|
|
||||||
return
|
|
||||||
|
|
||||||
topic = self.args[0]
|
|
||||||
if topic == "rules":
|
|
||||||
text = "These are the rules!"
|
|
||||||
elif topic == "commands":
|
|
||||||
text = "Available commands: ..."
|
|
||||||
else:
|
else:
|
||||||
text = "Unknown help topic!"
|
topic = self.args[0]
|
||||||
await send_text_to_room(self.matrix_client, self.room.room_id, text)
|
if topic == "commands":
|
||||||
|
reactions = " ".join(
|
||||||
|
sorted(self.config.allowed_reactions - self.config.insult_reactions)
|
||||||
|
)
|
||||||
|
text = (
|
||||||
|
"Here is the list of available commands:\n"
|
||||||
|
"- help: Display this help message.\n"
|
||||||
|
"- ack: Create a silence for the alert that is replied to.\n"
|
||||||
|
"- unack: Remove a silence for the alert that is replied to.\n\n"
|
||||||
|
"You can also react with an emoji to an alert to create a silence. "
|
||||||
|
"Removing a reaction will remove the silence.\n"
|
||||||
|
f"Here is the list of allowed emoji to trigger a silence: {reactions}\n"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
text = (
|
||||||
|
"I'm sorry, I don't know much about this topic. "
|
||||||
|
"You can type 'help commands' to view a list of available commands."
|
||||||
|
)
|
||||||
|
await send_text_to_room(
|
||||||
|
self.matrix_client, self.room.room_id, text, notice=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AngryUserCommand(BaseCommand):
|
||||||
|
async def process(self) -> None:
|
||||||
|
"""React to an insult from the user"""
|
||||||
|
sender_user_name = self.room.user_name(self.sender)
|
||||||
|
if sender_user_name is None:
|
||||||
|
sender_user_name = self.sender
|
||||||
|
|
||||||
|
replies = [
|
||||||
|
"You seem upset 😕 Take a deep breath 😌 and a cup of coffee ☕",
|
||||||
|
"Don't shoot the messenger! 😰",
|
||||||
|
"You're doing just fine, you're trying your best. If no one ever told you, it's all gonna be okay! 🎶",
|
||||||
|
]
|
||||||
|
random.shuffle(replies)
|
||||||
|
reply = replies.pop()
|
||||||
|
|
||||||
|
await send_text_to_room(
|
||||||
|
self.matrix_client,
|
||||||
|
self.room.room_id,
|
||||||
|
plaintext=f"{sender_user_name} {reply}",
|
||||||
|
html=f'<a href="https://matrix.to/#/{self.sender}">{sender_user_name}</a> {reply}',
|
||||||
|
notice=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UnknownCommand(BaseCommand):
|
class UnknownCommand(BaseCommand):
|
||||||
|
|
|
@ -21,7 +21,37 @@ logging.getLogger("peewee").setLevel(
|
||||||
) # Prevent debug messages from peewee lib
|
) # Prevent debug messages from peewee lib
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_REACTIONS = {"🤫", "😶", "🤐", "🙊", "🔇", "🔕"}
|
DEFAULT_REACTIONS = {
|
||||||
|
"🤫",
|
||||||
|
"😶",
|
||||||
|
"🤐",
|
||||||
|
"🙊",
|
||||||
|
"🔇",
|
||||||
|
"🔕",
|
||||||
|
"🚮",
|
||||||
|
"⛔",
|
||||||
|
"🚫",
|
||||||
|
"🤬",
|
||||||
|
"🫥",
|
||||||
|
"😶🌫️",
|
||||||
|
"🫣",
|
||||||
|
"🫢",
|
||||||
|
"😪",
|
||||||
|
"😴",
|
||||||
|
"💤",
|
||||||
|
"🥱",
|
||||||
|
"🤌",
|
||||||
|
"🤏",
|
||||||
|
"🤚",
|
||||||
|
"👎",
|
||||||
|
"🖕",
|
||||||
|
}
|
||||||
|
|
||||||
|
INSULT_REACTIONS = {
|
||||||
|
"🤬",
|
||||||
|
"🤌",
|
||||||
|
"🖕",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class AccountConfig:
|
class AccountConfig:
|
||||||
|
@ -147,6 +177,9 @@ class Config:
|
||||||
self.allowed_reactions = set(
|
self.allowed_reactions = set(
|
||||||
self._get_cfg(["matrix", "allowed_reactions"], default=DEFAULT_REACTIONS)
|
self._get_cfg(["matrix", "allowed_reactions"], default=DEFAULT_REACTIONS)
|
||||||
)
|
)
|
||||||
|
self.insult_reactions = set(
|
||||||
|
self._get_cfg(["matrix", "insult_reactions"], default=INSULT_REACTIONS)
|
||||||
|
)
|
||||||
|
|
||||||
self.address: str = self._get_cfg(["webhook", "address"], required=False)
|
self.address: str = self._get_cfg(["webhook", "address"], required=False)
|
||||||
self.port: int = self._get_cfg(["webhook", "port"], required=False)
|
self.port: int = self._get_cfg(["webhook", "port"], required=False)
|
||||||
|
@ -164,10 +197,6 @@ class Config:
|
||||||
"Supplied both webhook.socket and both webhook.address"
|
"Supplied both webhook.socket and both webhook.address"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.command_prefix: str = (
|
|
||||||
self._get_cfg(["command_prefix"], default="!alert") + " "
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_cfg(
|
def _get_cfg(
|
||||||
self,
|
self,
|
||||||
path: List[str],
|
path: List[str],
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
# Below you will find various config sections and options
|
# Below you will find various config sections and options
|
||||||
# Default values are shown
|
# Default values are shown
|
||||||
|
|
||||||
# The string to prefix messages with to talk to the bot in group chats
|
|
||||||
command_prefix: "!alert"
|
|
||||||
|
|
||||||
# Options for connecting to the bot's Matrix account
|
# Options for connecting to the bot's Matrix account
|
||||||
matrix:
|
matrix:
|
||||||
accounts:
|
accounts:
|
||||||
|
@ -62,7 +59,8 @@ matrix:
|
||||||
- "!abcdefgh:matrix.example.com"
|
- "!abcdefgh:matrix.example.com"
|
||||||
|
|
||||||
# List of allowed reactions to create silences.
|
# List of allowed reactions to create silences.
|
||||||
allowed_reactions: [🤫, 😶, 🤐]
|
allowed_reactions: [🤫, 😶, 🤐, 🤗]
|
||||||
|
insult_reactions: [🤗]
|
||||||
|
|
||||||
webhook:
|
webhook:
|
||||||
# Path to the socket for which the bot should listen to.
|
# Path to the socket for which the bot should listen to.
|
||||||
|
|
|
@ -34,8 +34,8 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# We don't spec config, as it doesn't currently have well defined attributes
|
# We don't spec config, as it doesn't currently have well defined attributes
|
||||||
self.fake_config = Mock()
|
self.fake_config = Mock()
|
||||||
self.fake_config.allowed_rooms = [self.fake_room.room_id]
|
self.fake_config.allowed_rooms = [self.fake_room.room_id]
|
||||||
self.fake_config.allowed_reactions = ["🤫"]
|
self.fake_config.allowed_reactions = ["🤫", "🤗"]
|
||||||
self.fake_config.command_prefix = "!alert "
|
self.fake_config.insult_reactions = ["🤗"]
|
||||||
self.fake_config.user_ids = [self.fake_matrix_client.user_id]
|
self.fake_config.user_ids = [self.fake_matrix_client.user_id]
|
||||||
|
|
||||||
self.fake_matrix_client_pool = Mock(
|
self.fake_matrix_client_pool = Mock(
|
||||||
|
@ -100,8 +100,8 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback.CommandFactory, "create", autospec=True)
|
@patch.object(matrix_alertbot.callback.CommandFactory, "create", autospec=True)
|
||||||
async def test_message_without_prefix(self, fake_command_create: Mock) -> None:
|
async def test_message_without_mention(self, fake_command_create: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText without any command prefix"""
|
"""Tests the callback for RoomMessageText without any mention of the bot"""
|
||||||
# Tests that the bot process messages in the room
|
# Tests that the bot process messages in the room
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
|
@ -116,12 +116,12 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
||||||
async def test_message_help_client_not_in_pool(self, fake_command: Mock) -> None:
|
async def test_message_help_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText without any command prefix"""
|
"""Tests the callback for RoomMessageText without any mention of the bot"""
|
||||||
# Tests that the bot process messages in the room
|
# Tests that the bot process messages in the room
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert help"
|
fake_message_event.body = "@fake_user help"
|
||||||
fake_message_event.source = {"content": {}}
|
fake_message_event.source = {"content": {}}
|
||||||
|
|
||||||
self.fake_matrix_client_pool.matrix_client = None
|
self.fake_matrix_client_pool.matrix_client = None
|
||||||
|
@ -133,15 +133,15 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_command.assert_not_called()
|
fake_command.assert_not_called()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
||||||
async def test_message_help_not_in_reply_with_prefix(
|
async def test_message_help_not_in_reply_with_mention(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert help"
|
fake_message_event.body = "@fake_user help"
|
||||||
fake_message_event.source = {"content": {}}
|
fake_message_event.source = {"content": {}}
|
||||||
|
|
||||||
# Pretend that we received a text message event
|
# Pretend that we received a text message event
|
||||||
|
@ -161,14 +161,14 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_command.return_value.process.assert_called_once()
|
fake_command.return_value.process.assert_called_once()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
||||||
async def test_message_help_in_reply_with_prefix(self, fake_command: Mock) -> None:
|
async def test_message_help_in_reply_with_mention(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
|
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert help"
|
fake_message_event.body = "@fake_user help"
|
||||||
fake_message_event.source = {
|
fake_message_event.source = {
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||||
|
@ -193,7 +193,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command.CommandFactory, "create", autospec=True)
|
@patch.object(matrix_alertbot.command.CommandFactory, "create", autospec=True)
|
||||||
async def test_ignore_message_sent_by_bot(self, fake_create_command: Mock) -> None:
|
async def test_ignore_message_sent_by_bot(self, fake_create_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
|
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
|
@ -209,7 +209,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_ignore_message_sent_on_unauthorized_room(
|
async def test_ignore_message_sent_on_unauthorized_room(
|
||||||
self, fake_create_command: Mock
|
self, fake_create_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
|
|
||||||
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
||||||
|
@ -224,15 +224,15 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_create_command.assert_not_called()
|
fake_create_command.assert_not_called()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
||||||
async def test_message_ack_not_in_reply_with_prefix(
|
async def test_message_ack_not_in_reply_with_mention(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert ack"
|
fake_message_event.body = "@fake_user ack"
|
||||||
fake_message_event.source = {"content": {}}
|
fake_message_event.source = {"content": {}}
|
||||||
|
|
||||||
# Pretend that we received a text message event
|
# Pretend that we received a text message event
|
||||||
|
@ -242,13 +242,48 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_command.assert_not_called()
|
fake_command.assert_not_called()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
||||||
async def test_message_ack_in_reply_with_prefix(self, fake_command: Mock) -> None:
|
async def test_message_ack_in_reply_with_full_mention(
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
self, fake_command: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert ack"
|
fake_message_event.body = "@fake_user:example.com ack"
|
||||||
|
fake_message_event.source = {
|
||||||
|
"content": {
|
||||||
|
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pretend that we received a text message event
|
||||||
|
await self.callbacks.message(self.fake_room, fake_message_event)
|
||||||
|
|
||||||
|
# Check that the command was not executed
|
||||||
|
fake_command.assert_called_once_with(
|
||||||
|
self.fake_matrix_client,
|
||||||
|
self.fake_cache,
|
||||||
|
self.fake_alertmanager_client,
|
||||||
|
self.fake_config,
|
||||||
|
self.fake_room,
|
||||||
|
fake_message_event.sender,
|
||||||
|
fake_message_event.event_id,
|
||||||
|
"some alert event id",
|
||||||
|
(),
|
||||||
|
)
|
||||||
|
fake_command.return_value.process.assert_called_once()
|
||||||
|
|
||||||
|
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
||||||
|
async def test_message_ack_in_reply_with_short_mention(
|
||||||
|
self, fake_command: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
|
# Tests that the bot process messages in the room that contain a command
|
||||||
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
|
fake_message_event.event_id = "some event id"
|
||||||
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
|
fake_message_event.body = "fake_user ack"
|
||||||
fake_message_event.source = {
|
fake_message_event.source = {
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||||
|
@ -273,15 +308,15 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_command.return_value.process.assert_called_once()
|
fake_command.return_value.process.assert_called_once()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||||
async def test_message_unack_not_in_reply_with_prefix(
|
async def test_message_unack_not_in_reply_with_mention(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert unack"
|
fake_message_event.body = "@fake_user unack"
|
||||||
fake_message_event.source = {"content": {}}
|
fake_message_event.source = {"content": {}}
|
||||||
|
|
||||||
# Pretend that we received a text message event
|
# Pretend that we received a text message event
|
||||||
|
@ -291,13 +326,15 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
fake_command.assert_not_called()
|
fake_command.assert_not_called()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "UnackAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.command, "UnackAlertCommand", autospec=True)
|
||||||
async def test_message_unack_in_reply_with_prefix(self, fake_command: Mock) -> None:
|
async def test_message_unack_in_reply_with_mention(
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
self, fake_command: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert unack"
|
fake_message_event.body = "@fake_user unack"
|
||||||
fake_message_event.source = {
|
fake_message_event.source = {
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||||
|
@ -326,12 +363,12 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_message_raise_exception(
|
async def test_message_raise_exception(
|
||||||
self, fake_command: Mock, fake_logger
|
self, fake_command: Mock, fake_logger
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_message_event = Mock(spec=nio.RoomMessageText)
|
fake_message_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_message_event.event_id = "some event id"
|
fake_message_event.event_id = "some event id"
|
||||||
fake_message_event.sender = "@some_other_fake_user:example.com"
|
fake_message_event.sender = "@some_other_fake_user:example.com"
|
||||||
fake_message_event.body = "!alert ack"
|
fake_message_event.body = "@fake_user ack"
|
||||||
fake_message_event.source = {
|
fake_message_event.source = {
|
||||||
"content": {
|
"content": {
|
||||||
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||||
|
@ -363,7 +400,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
async def test_reaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
async def test_reaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_alert_event.event_id = "some alert event id"
|
fake_alert_event.event_id = "some alert event id"
|
||||||
|
@ -387,9 +424,12 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# Check that we attempted to execute the command
|
# Check that we attempted to execute the command
|
||||||
fake_command.assert_not_called()
|
fake_command.assert_not_called()
|
||||||
|
|
||||||
|
@patch.object(matrix_alertbot.callback, "AngryUserCommand", autospec=True)
|
||||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
async def test_reaction_to_existing_alert(self, fake_command: Mock) -> None:
|
async def test_reaction_to_existing_alert(
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
self, fake_command: Mock, fake_angry_user_command
|
||||||
|
) -> None:
|
||||||
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_alert_event.event_id = "some alert event id"
|
fake_alert_event.event_id = "some alert event id"
|
||||||
|
@ -424,9 +464,62 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_room.room_id, fake_alert_event.event_id
|
self.fake_room.room_id, fake_alert_event.event_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fake_angry_user_command.assert_not_called()
|
||||||
|
|
||||||
|
@patch.object(matrix_alertbot.callback, "AngryUserCommand", autospec=True)
|
||||||
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
|
async def test_insult_reaction(
|
||||||
|
self, fake_command: Mock, fake_angry_user_command: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
|
# Tests that the bot process messages in the room that contain a command
|
||||||
|
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
||||||
|
fake_alert_event.event_id = "some alert event id"
|
||||||
|
fake_alert_event.sender = self.fake_matrix_client.user_id
|
||||||
|
|
||||||
|
fake_reaction_event = Mock(spec=nio.ReactionEvent)
|
||||||
|
fake_reaction_event.event_id = "some event id"
|
||||||
|
fake_reaction_event.sender = "@some_other_fake_user:example.com"
|
||||||
|
fake_reaction_event.reacts_to = fake_alert_event.event_id
|
||||||
|
fake_reaction_event.key = "🤗"
|
||||||
|
|
||||||
|
fake_event_response = Mock(spec=nio.RoomGetEventResponse)
|
||||||
|
fake_event_response.event = fake_alert_event
|
||||||
|
self.fake_matrix_client.room_get_event.return_value = fake_event_response
|
||||||
|
|
||||||
|
# Pretend that we received a text message event
|
||||||
|
await self.callbacks.reaction(self.fake_room, fake_reaction_event)
|
||||||
|
|
||||||
|
# Check that we attempted to execute the command
|
||||||
|
fake_command.assert_called_once_with(
|
||||||
|
self.fake_matrix_client,
|
||||||
|
self.fake_cache,
|
||||||
|
self.fake_alertmanager_client,
|
||||||
|
self.fake_config,
|
||||||
|
self.fake_room,
|
||||||
|
fake_reaction_event.sender,
|
||||||
|
fake_reaction_event.event_id,
|
||||||
|
"some alert event id",
|
||||||
|
)
|
||||||
|
fake_command.return_value.process.assert_called_once()
|
||||||
|
self.fake_matrix_client.room_get_event.assert_called_once_with(
|
||||||
|
self.fake_room.room_id, fake_alert_event.event_id
|
||||||
|
)
|
||||||
|
|
||||||
|
fake_angry_user_command.assert_called_once_with(
|
||||||
|
self.fake_matrix_client,
|
||||||
|
self.fake_cache,
|
||||||
|
self.fake_alertmanager_client,
|
||||||
|
self.fake_config,
|
||||||
|
self.fake_room,
|
||||||
|
fake_reaction_event.sender,
|
||||||
|
fake_reaction_event.event_id,
|
||||||
|
)
|
||||||
|
fake_command.return_value.process.assert_called_once()
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
async def test_reaction_to_inexistent_event(self, fake_command: Mock) -> None:
|
async def test_reaction_to_inexistent_event(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -454,7 +547,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_reaction_to_event_not_from_bot_user(
|
async def test_reaction_to_event_not_from_bot_user(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_alert_event.event_id = "some alert event id"
|
fake_alert_event.event_id = "some alert event id"
|
||||||
|
@ -486,7 +579,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_reaction_raise_exception(
|
async def test_reaction_raise_exception(
|
||||||
self, fake_command: Mock, fake_logger: Mock
|
self, fake_command: Mock, fake_logger: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
fake_alert_event = Mock(spec=nio.RoomMessageText)
|
||||||
fake_alert_event.event_id = "some alert event id"
|
fake_alert_event.event_id = "some alert event id"
|
||||||
|
@ -529,7 +622,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
async def test_reaction_unknown(self, fake_command: Mock) -> None:
|
async def test_reaction_unknown(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -549,7 +642,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||||
async def test_ignore_reaction_sent_by_bot_user(self, fake_command: Mock) -> None:
|
async def test_ignore_reaction_sent_by_bot_user(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -571,7 +664,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_ignore_reaction_in_unauthorized_room(
|
async def test_ignore_reaction_in_unauthorized_room(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
||||||
|
|
||||||
|
@ -593,7 +686,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||||
async def test_redaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
async def test_redaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -615,7 +708,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||||
async def test_redaction(self, fake_command: Mock) -> None:
|
async def test_redaction(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -648,7 +741,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_redaction_raise_exception(
|
async def test_redaction_raise_exception(
|
||||||
self, fake_command: Mock, fake_logger
|
self, fake_command: Mock, fake_logger
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_alert_event_id = "some alert event id"
|
fake_alert_event_id = "some alert event id"
|
||||||
|
|
||||||
|
@ -684,7 +777,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||||
async def test_ignore_redaction_sent_by_bot_user(self, fake_command: Mock) -> None:
|
async def test_ignore_redaction_sent_by_bot_user(self, fake_command: Mock) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_redaction_event = Mock(spec=nio.RedactionEvent)
|
fake_redaction_event = Mock(spec=nio.RedactionEvent)
|
||||||
fake_redaction_event.sender = self.fake_matrix_client.user_id
|
fake_redaction_event.sender = self.fake_matrix_client.user_id
|
||||||
|
@ -703,7 +796,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_ignore_redaction_in_unauthorized_room(
|
async def test_ignore_redaction_in_unauthorized_room(
|
||||||
self, fake_command: Mock
|
self, fake_command: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
||||||
|
|
||||||
|
@ -721,7 +814,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_cache.__getitem__.assert_not_called()
|
self.fake_cache.__getitem__.assert_not_called()
|
||||||
|
|
||||||
async def test_key_verification_start(self) -> None:
|
async def test_key_verification_start(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -745,7 +838,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.share_key())
|
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.share_key())
|
||||||
|
|
||||||
async def test_key_verification_start_with_emoji_not_supported(self) -> None:
|
async def test_key_verification_start_with_emoji_not_supported(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -769,7 +862,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_key_verification_start_with_accept_key_verification_error(
|
async def test_key_verification_start_with_accept_key_verification_error(
|
||||||
self,
|
self,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -799,7 +892,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
async def test_key_verification_start_with_to_device_error(
|
async def test_key_verification_start_with_to_device_error(
|
||||||
self,
|
self,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -825,7 +918,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.share_key())
|
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.share_key())
|
||||||
|
|
||||||
async def test_key_verification_cancel(self) -> None:
|
async def test_key_verification_cancel(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_key_verification_event = Mock(spec=nio.KeyVerificationCancel)
|
fake_key_verification_event = Mock(spec=nio.KeyVerificationCancel)
|
||||||
fake_key_verification_event.sender = "@some_other_fake_user:example.com"
|
fake_key_verification_event.sender = "@some_other_fake_user:example.com"
|
||||||
|
@ -837,7 +930,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# Check that we attempted to execute the command
|
# Check that we attempted to execute the command
|
||||||
|
|
||||||
async def test_key_verification_confirm(self) -> None:
|
async def test_key_verification_confirm(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -862,7 +955,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def test_key_verification_confirm_with_error(self) -> None:
|
async def test_key_verification_confirm_with_error(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -891,7 +984,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def test_key_verification_end(self) -> None:
|
async def test_key_verification_end(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -912,7 +1005,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.get_mac())
|
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.get_mac())
|
||||||
|
|
||||||
async def test_key_verification_end_with_missing_transaction_id(self) -> None:
|
async def test_key_verification_end_with_missing_transaction_id(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -932,7 +1025,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_matrix_client.to_device.assert_not_called()
|
self.fake_matrix_client.to_device.assert_not_called()
|
||||||
|
|
||||||
async def test_key_verification_end_with_mac_error(self) -> None:
|
async def test_key_verification_end_with_mac_error(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
@ -953,7 +1046,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_matrix_client.to_device.assert_not_called()
|
self.fake_matrix_client.to_device.assert_not_called()
|
||||||
|
|
||||||
async def test_key_verification_end_with_to_device_error(self) -> None:
|
async def test_key_verification_end_with_to_device_error(self) -> None:
|
||||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
"""Tests the callback for RoomMessageText with a mention of the bot"""
|
||||||
# Tests that the bot process messages in the room that contain a command
|
# Tests that the bot process messages in the room that contain a command
|
||||||
fake_transaction_id = "fake transaction id"
|
fake_transaction_id = "fake transaction id"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import random
|
||||||
import unittest
|
import unittest
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
from unittest.mock import MagicMock, Mock, call, patch
|
from unittest.mock import MagicMock, Mock, call, patch
|
||||||
|
@ -10,6 +11,7 @@ import matrix_alertbot.command
|
||||||
from matrix_alertbot.alertmanager import AlertmanagerClient
|
from matrix_alertbot.alertmanager import AlertmanagerClient
|
||||||
from matrix_alertbot.command import (
|
from matrix_alertbot.command import (
|
||||||
AckAlertCommand,
|
AckAlertCommand,
|
||||||
|
AngryUserCommand,
|
||||||
CommandFactory,
|
CommandFactory,
|
||||||
HelpCommand,
|
HelpCommand,
|
||||||
UnackAlertCommand,
|
UnackAlertCommand,
|
||||||
|
@ -79,6 +81,8 @@ async def delete_silence_raise_silence_not_found_error(silence_id: str) -> None:
|
||||||
|
|
||||||
class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
random.seed(42)
|
||||||
|
|
||||||
# Create a Command object and give it some Mock'd objects to use
|
# Create a Command object and give it some Mock'd objects to use
|
||||||
self.fake_matrix_client = Mock(spec=nio.AsyncClient)
|
self.fake_matrix_client = Mock(spec=nio.AsyncClient)
|
||||||
self.fake_matrix_client.user = "@fake_user:example.com"
|
self.fake_matrix_client.user = "@fake_user:example.com"
|
||||||
|
@ -105,7 +109,8 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# We don't spec config, as it doesn't currently have well defined attributes
|
# We don't spec config, as it doesn't currently have well defined attributes
|
||||||
self.fake_config = Mock()
|
self.fake_config = Mock()
|
||||||
self.fake_config.allowed_rooms = [self.fake_room.room_id]
|
self.fake_config.allowed_rooms = [self.fake_room.room_id]
|
||||||
self.fake_config.command_prefix = "!alert "
|
self.fake_config.allowed_reactions = {"🤫", "😶", "🤐", "🤗"}
|
||||||
|
self.fake_config.insult_reactions = {"🤗"}
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command.AckAlertCommand, "process")
|
@patch.object(matrix_alertbot.command.AckAlertCommand, "process")
|
||||||
async def test_process_ack_command(self, fake_ack: Mock) -> None:
|
async def test_process_ack_command(self, fake_ack: Mock) -> None:
|
||||||
|
@ -645,29 +650,6 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
_, _, text = fake_send_text_to_room.call_args.args
|
_, _, text = fake_send_text_to_room.call_args.args
|
||||||
self.assertIn("help commands", text)
|
self.assertIn("help commands", text)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
|
||||||
async def test_help_with_rules_topic(self, fake_send_text_to_room: Mock) -> None:
|
|
||||||
"""Tests the callback for InviteMemberEvents"""
|
|
||||||
# Tests that the bot attempts to join a room after being invited to it
|
|
||||||
|
|
||||||
command = HelpCommand(
|
|
||||||
self.fake_matrix_client,
|
|
||||||
self.fake_cache,
|
|
||||||
self.fake_alertmanager_client,
|
|
||||||
self.fake_config,
|
|
||||||
self.fake_room,
|
|
||||||
self.fake_sender,
|
|
||||||
self.fake_event_id,
|
|
||||||
("rules",),
|
|
||||||
)
|
|
||||||
|
|
||||||
await command.process()
|
|
||||||
|
|
||||||
# Check that we attempted to create silences
|
|
||||||
fake_send_text_to_room.assert_called_once()
|
|
||||||
_, _, text = fake_send_text_to_room.call_args.args
|
|
||||||
self.assertIn("rules!", text)
|
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
||||||
async def test_help_with_commands_topic(self, fake_send_text_to_room: Mock) -> None:
|
async def test_help_with_commands_topic(self, fake_send_text_to_room: Mock) -> None:
|
||||||
"""Tests the callback for InviteMemberEvents"""
|
"""Tests the callback for InviteMemberEvents"""
|
||||||
|
@ -689,7 +671,43 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# Check that we attempted to create silences
|
# Check that we attempted to create silences
|
||||||
fake_send_text_to_room.assert_called_once()
|
fake_send_text_to_room.assert_called_once()
|
||||||
_, _, text = fake_send_text_to_room.call_args.args
|
_, _, text = fake_send_text_to_room.call_args.args
|
||||||
self.assertIn("Available commands", text)
|
self.assertIn("Here is the list of available commands", text)
|
||||||
|
reactions = (
|
||||||
|
self.fake_config.allowed_reactions - self.fake_config.insult_reactions
|
||||||
|
)
|
||||||
|
for reaction in reactions:
|
||||||
|
self.assertIn(reaction, text)
|
||||||
|
for reaction in self.fake_config.insult_reactions:
|
||||||
|
self.assertNotIn(reaction, text)
|
||||||
|
|
||||||
|
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
||||||
|
async def test_angry_user(self, fake_send_text_to_room: Mock) -> None:
|
||||||
|
"""Tests the callback for InviteMemberEvents"""
|
||||||
|
# Tests that the bot attempts to join a room after being invited to it
|
||||||
|
|
||||||
|
command = AngryUserCommand(
|
||||||
|
self.fake_matrix_client,
|
||||||
|
self.fake_cache,
|
||||||
|
self.fake_alertmanager_client,
|
||||||
|
self.fake_config,
|
||||||
|
self.fake_room,
|
||||||
|
self.fake_sender,
|
||||||
|
self.fake_event_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
await command.process()
|
||||||
|
|
||||||
|
# Check that we attempted to create silences
|
||||||
|
fake_send_text_to_room.assert_called_once()
|
||||||
|
text, html, _ = fake_send_text_to_room.call_args.kwargs.values()
|
||||||
|
self.assertRegex(
|
||||||
|
text,
|
||||||
|
"^@some_other_fake_user:example.com ",
|
||||||
|
)
|
||||||
|
self.assertRegex(
|
||||||
|
html,
|
||||||
|
'^<a href="https://matrix.to/#/@some_other_fake_user:example.com">@some_other_fake_user:example.com</a> ',
|
||||||
|
)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
||||||
async def test_help_with_unknown_topic(self, fake_send_text_to_room: Mock) -> None:
|
async def test_help_with_unknown_topic(self, fake_send_text_to_room: Mock) -> None:
|
||||||
|
@ -712,7 +730,7 @@ class CommandTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
# Check that we attempted to create silences
|
# Check that we attempted to create silences
|
||||||
fake_send_text_to_room.assert_called_once()
|
fake_send_text_to_room.assert_called_once()
|
||||||
_, _, text = fake_send_text_to_room.call_args.args
|
_, _, text = fake_send_text_to_room.call_args.args
|
||||||
self.assertEqual("Unknown help topic!", text)
|
self.assertIn("I'm sorry, I don't know much about this topic.", text)
|
||||||
|
|
||||||
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
@patch.object(matrix_alertbot.command, "send_text_to_room")
|
||||||
async def test_unknown_command(self, fake_send_text_to_room: Mock) -> None:
|
async def test_unknown_command(self, fake_send_text_to_room: Mock) -> None:
|
||||||
|
|
|
@ -91,8 +91,6 @@ class ConfigTestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertIsNone(config.template_dir)
|
self.assertIsNone(config.template_dir)
|
||||||
|
|
||||||
self.assertEqual("!alert ", config.command_prefix)
|
|
||||||
|
|
||||||
@patch("os.path.isdir")
|
@patch("os.path.isdir")
|
||||||
@patch("os.path.exists")
|
@patch("os.path.exists")
|
||||||
@patch("os.mkdir")
|
@patch("os.mkdir")
|
||||||
|
@ -140,7 +138,8 @@ class ConfigTestCase(unittest.TestCase):
|
||||||
self.assertEqual("https://matrix.domain.tld", config.accounts[1].homeserver_url)
|
self.assertEqual("https://matrix.domain.tld", config.accounts[1].homeserver_url)
|
||||||
self.assertEqual("fake_device_name", config.device_name)
|
self.assertEqual("fake_device_name", config.device_name)
|
||||||
self.assertEqual(["!abcdefgh:matrix.example.com"], config.allowed_rooms)
|
self.assertEqual(["!abcdefgh:matrix.example.com"], config.allowed_rooms)
|
||||||
self.assertEqual({"🤫", "😶", "🤐"}, config.allowed_reactions)
|
self.assertEqual({"🤫", "😶", "🤐", "🤗"}, config.allowed_reactions)
|
||||||
|
self.assertEqual({"🤗"}, config.insult_reactions)
|
||||||
|
|
||||||
self.assertIsNone(config.address)
|
self.assertIsNone(config.address)
|
||||||
self.assertIsNone(config.port)
|
self.assertIsNone(config.port)
|
||||||
|
@ -156,8 +155,6 @@ class ConfigTestCase(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual("data/templates", config.template_dir)
|
self.assertEqual("data/templates", config.template_dir)
|
||||||
|
|
||||||
self.assertEqual("!alert ", config.command_prefix)
|
|
||||||
|
|
||||||
def test_read_config_raise_config_error(self) -> None:
|
def test_read_config_raise_config_error(self) -> None:
|
||||||
with self.assertRaises(ParseConfigError):
|
with self.assertRaises(ParseConfigError):
|
||||||
Config("")
|
Config("")
|
||||||
|
|
|
@ -62,7 +62,6 @@ class MatrixClientPoolTestCase(unittest.IsolatedAsyncioTestCase):
|
||||||
self.fake_account_config_2.token_file = "account2.token.secret"
|
self.fake_account_config_2.token_file = "account2.token.secret"
|
||||||
self.fake_config = Mock(spec=Config)
|
self.fake_config = Mock(spec=Config)
|
||||||
self.fake_config.store_dir = "/dev/null"
|
self.fake_config.store_dir = "/dev/null"
|
||||||
self.fake_config.command_prefix = "!alert"
|
|
||||||
self.fake_config.accounts = [
|
self.fake_config.accounts = [
|
||||||
self.fake_account_config_1,
|
self.fake_account_config_1,
|
||||||
self.fake_account_config_2,
|
self.fake_account_config_2,
|
||||||
|
|
Loading…
Reference in a new issue