add tests for chat functions

This commit is contained in:
HgO 2022-08-08 12:38:09 +02:00
parent 6fd687cc90
commit 264687a62d
6 changed files with 176 additions and 18 deletions

View file

@ -5,11 +5,13 @@ from nio import (
AsyncClient, AsyncClient,
InviteMemberEvent, InviteMemberEvent,
JoinError, JoinError,
LocalProtocolError,
MatrixRoom, MatrixRoom,
MegolmEvent, MegolmEvent,
RedactionEvent, RedactionEvent,
RoomGetEventError, RoomGetEventError,
RoomMessageText, RoomMessageText,
SendRetryError,
UnknownEvent, UnknownEvent,
) )
@ -104,7 +106,10 @@ class Callbacks:
logging.error(f"Cannot process command '{cmd}': {e}") logging.error(f"Cannot process command '{cmd}': {e}")
return return
await command.process() try:
await command.process()
except (SendRetryError, LocalProtocolError) as e:
logger.exception(f"Unable to send message to {room.room_id}", exc_info=e)
async def invite(self, room: MatrixRoom, event: InviteMemberEvent) -> None: async def invite(self, room: MatrixRoom, event: InviteMemberEvent) -> None:
"""Callback for when an invite is received. Join the room specified in the invite. """Callback for when an invite is received. Join the room specified in the invite.
@ -204,7 +209,10 @@ class Callbacks:
alert_event_id, alert_event_id,
) )
await command.process() try:
await command.process()
except (SendRetryError, LocalProtocolError) as e:
logger.exception(f"Unable to send message to {room.room_id}", exc_info=e)
async def redaction(self, room: MatrixRoom, event: RedactionEvent) -> None: async def redaction(self, room: MatrixRoom, event: RedactionEvent) -> None:
# Ignore events from unauthorized room # Ignore events from unauthorized room
@ -227,7 +235,10 @@ class Callbacks:
event.event_id, event.event_id,
event.redacts, event.redacts,
) )
await command.process() try:
await command.process()
except (SendRetryError, LocalProtocolError) as e:
logger.exception(f"Unable to send message to {room.room_id}", exc_info=e)
async def decryption_failure(self, room: MatrixRoom, event: MegolmEvent) -> None: async def decryption_failure(self, room: MatrixRoom, event: MegolmEvent) -> None:
"""Callback for when an event fails to decrypt. Inform the user. """Callback for when an event fails to decrypt. Inform the user.

View file

@ -1,7 +1,7 @@
import logging import logging
from typing import Dict, Optional, TypedDict, Union from typing import Dict, Optional, TypedDict, Union
from nio import AsyncClient, ErrorResponse, Response, RoomSendResponse, SendRetryError from nio import AsyncClient, ErrorResponse, Response, RoomSendResponse
from typing_extensions import NotRequired from typing_extensions import NotRequired
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -20,7 +20,7 @@ ContentEventDict = TypedDict(
async def send_text_to_room( async def send_text_to_room(
client: AsyncClient, matrix_client: AsyncClient,
room_id: str, room_id: str,
plaintext: str, plaintext: str,
html: str = None, html: str = None,
@ -62,15 +62,12 @@ async def send_text_to_room(
if reply_to_event_id: if reply_to_event_id:
content["m.relates_to"] = {"m.in_reply_to": {"event_id": reply_to_event_id}} content["m.relates_to"] = {"m.in_reply_to": {"event_id": reply_to_event_id}}
try: return await matrix_client.room_send(
return await client.room_send( room_id,
room_id, "m.room.message",
"m.room.message", content,
content, ignore_unverified_devices=True,
ignore_unverified_devices=True, )
)
except SendRetryError:
logger.exception(f"Unable to send message response to {room_id}")
def make_pill(user_id: str, displayname: str = None) -> str: def make_pill(user_id: str, displayname: str = None) -> str:

View file

@ -135,7 +135,7 @@ class AckAlertCommand(BaseAlertCommand):
alert_fingerprint, alert_fingerprint,
self.room.user_name(self.sender), self.room.user_name(self.sender),
duration_seconds, duration_seconds,
force=True force=True,
) )
except AlertNotFoundError as e: except AlertNotFoundError as e:
logger.warning(f"Unable to create silence: {e}") logger.warning(f"Unable to create silence: {e}")

View file

@ -7,7 +7,7 @@ from aiohttp import ClientError, web, web_request
from aiohttp_prometheus_exporter.handler import metrics from aiohttp_prometheus_exporter.handler import metrics
from aiohttp_prometheus_exporter.middleware import prometheus_middleware_factory from aiohttp_prometheus_exporter.middleware import prometheus_middleware_factory
from diskcache import Cache from diskcache import Cache
from nio import AsyncClient, LocalProtocolError from nio import AsyncClient, LocalProtocolError, SendRetryError
from matrix_alertbot.alert import Alert, AlertRenderer from matrix_alertbot.alert import Alert, AlertRenderer
from matrix_alertbot.alertmanager import AlertmanagerClient from matrix_alertbot.alertmanager import AlertmanagerClient
@ -80,7 +80,7 @@ async def create_alerts(request: web_request.Request) -> web.Response:
status=500, status=500,
body=f"An error occured with Alertmanager when handling alert with fingerprint {alert.fingerprint}.", body=f"An error occured with Alertmanager when handling alert with fingerprint {alert.fingerprint}.",
) )
except (LocalProtocolError, ClientError) as e: except (SendRetryError, LocalProtocolError, ClientError) as e:
logger.error( logger.error(
f"Unable to send alert {alert.fingerprint} to Matrix room: {e}" f"Unable to send alert {alert.fingerprint} to Matrix room: {e}"
) )

View file

@ -0,0 +1,150 @@
import unittest
from typing import Any, Dict, Optional
from unittest.mock import Mock
import nio
from matrix_alertbot.chat_functions import send_text_to_room, strip_fallback
from tests.utils import make_awaitable
async def send_room_raise_send_retry_error(
room_id: str,
message_type: str,
content: Dict[Any, Any],
tx_id: Optional[str] = None,
ignore_unverified_devices: bool = False,
) -> nio.RoomSendResponse:
raise nio.SendRetryError
class ChatFunctionsTestCase(unittest.IsolatedAsyncioTestCase):
def setUp(self) -> None:
pass
def test_strip_fallback(self) -> None:
fake_body = "> some message\n\nsome reply"
message = strip_fallback(fake_body)
self.assertEqual("some reply", message)
fake_body = "some message"
message = strip_fallback(fake_body)
self.assertEqual(fake_body, message)
async def test_send_text_to_room_as_notice(self) -> None:
fake_response = Mock(spec=nio.RoomSendResponse)
fake_matrix_client = Mock(spec=nio.AsyncClient)
fake_matrix_client.room_send = Mock(return_value=make_awaitable(fake_response))
fake_room_id = "!abcdefgh:example.com"
fake_plaintext_body = "some plaintext message"
fake_html_body = "some html message"
response = await send_text_to_room(
fake_matrix_client, fake_room_id, fake_plaintext_body, fake_html_body
)
fake_matrix_client.room_send.assert_called_once_with(
fake_room_id,
"m.room.message",
{
"msgtype": "m.notice",
"format": "org.matrix.custom.html",
"body": fake_plaintext_body,
"formatted_body": fake_html_body,
},
ignore_unverified_devices=True,
)
self.assertEqual(fake_response, response)
async def test_send_text_to_room_as_message(self) -> None:
fake_response = Mock(spec=nio.RoomSendResponse)
fake_matrix_client = Mock(spec=nio.AsyncClient)
fake_matrix_client.room_send = Mock(return_value=make_awaitable(fake_response))
fake_room_id = "!abcdefgh:example.com"
fake_plaintext_body = "some plaintext message"
fake_html_body = "some html message"
response = await send_text_to_room(
fake_matrix_client,
fake_room_id,
fake_plaintext_body,
fake_html_body,
notice=False,
)
fake_matrix_client.room_send.assert_called_once_with(
fake_room_id,
"m.room.message",
{
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"body": fake_plaintext_body,
"formatted_body": fake_html_body,
},
ignore_unverified_devices=True,
)
self.assertEqual(fake_response, response)
async def test_send_text_to_room_in_reply_to_event(self) -> None:
fake_response = Mock(spec=nio.RoomSendResponse)
fake_matrix_client = Mock(spec=nio.AsyncClient)
fake_matrix_client.room_send = Mock(return_value=make_awaitable(fake_response))
fake_room_id = "!abcdefgh:example.com"
fake_plaintext_body = "some plaintext message"
fake_html_body = "some html message"
fake_event_id = "some event id"
response = await send_text_to_room(
fake_matrix_client,
fake_room_id,
fake_plaintext_body,
fake_html_body,
reply_to_event_id=fake_event_id,
)
fake_matrix_client.room_send.assert_called_once_with(
fake_room_id,
"m.room.message",
{
"msgtype": "m.notice",
"format": "org.matrix.custom.html",
"body": fake_plaintext_body,
"formatted_body": fake_html_body,
"m.relates_to": {"m.in_reply_to": {"event_id": fake_event_id}},
},
ignore_unverified_devices=True,
)
self.assertEqual(fake_response, response)
async def test_send_text_to_room_raise_send_retry_error(self) -> None:
fake_matrix_client = Mock(spec=nio.AsyncClient)
fake_matrix_client.room_send = Mock(
side_effect=send_room_raise_send_retry_error
)
fake_room_id = "!abcdefgh:example.com"
fake_plaintext_body = "some plaintext message"
fake_html_body = "some html message"
with self.assertRaises(nio.SendRetryError):
await send_text_to_room(
fake_matrix_client,
fake_room_id,
fake_plaintext_body,
fake_html_body,
)
fake_matrix_client.room_send.assert_called_once_with(
fake_room_id,
"m.room.message",
{
"msgtype": "m.notice",
"format": "org.matrix.custom.html",
"body": fake_plaintext_body,
"formatted_body": fake_html_body,
},
ignore_unverified_devices=True,
)
if __name__ == "__main__":
unittest.main()

View file

@ -22,7 +22,7 @@ from matrix_alertbot.webhook import Webhook
def send_text_to_room_raise_error( def send_text_to_room_raise_error(
client: nio.AsyncClient, room_id: str, plaintext: str, html: str, notice: bool client: nio.AsyncClient, room_id: str, plaintext: str, html: str, notice: bool
) -> RoomSendResponse: ) -> RoomSendResponse:
raise LocalProtocolError() raise LocalProtocolError
def update_silence_raise_silence_not_found(fingerprint: str) -> str: def update_silence_raise_silence_not_found(fingerprint: str) -> str: