add more tests
This commit is contained in:
parent
27828ec3c7
commit
6ae3355f3c
9 changed files with 925 additions and 77 deletions
|
@ -5,7 +5,6 @@ import logging
|
|||
from diskcache import Cache
|
||||
from nio.client import AsyncClient
|
||||
from nio.events import (
|
||||
Event,
|
||||
InviteMemberEvent,
|
||||
KeyVerificationCancel,
|
||||
KeyVerificationKey,
|
||||
|
@ -470,10 +469,3 @@ class Callbacks:
|
|||
raise SendRetryError(
|
||||
f"{response_event.status_code} - {response_event.message}"
|
||||
)
|
||||
|
||||
async def debug(self, room: MatrixRoom, event: Event) -> None:
|
||||
logger.debug(
|
||||
f"Bot {self.matrix_client.user_id} | Room ID {room.room_id} | "
|
||||
f"Event ID {event.event_id} | Sender {event.sender} | "
|
||||
f"Received some event: {event.source}"
|
||||
)
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
[pytest]
|
||||
asyncio_mode=strict
|
||||
addopts=--cov=matrix_alertbot --cov-report=lcov:lcov.info --cov-report=term
|
||||
|
|
|
@ -50,7 +50,8 @@ test =
|
|||
flake8-comprehensions>=3.10.0
|
||||
isort>=5.10.1
|
||||
mypy>=0.961
|
||||
pytest>=7.1.2
|
||||
pytest>=7.4.0
|
||||
pytest-cov>=4.1.0
|
||||
pytest-asyncio>=0.18.3
|
||||
freezegun>=1.2.1
|
||||
types-PyYAML>=6.0.9
|
||||
|
|
|
@ -24,12 +24,6 @@ from matrix_alertbot.errors import (
|
|||
)
|
||||
|
||||
|
||||
async def update_silence_raise_silence_not_found(
|
||||
fingerprint: str, user: str, duration_seconds: int, *, force: bool = False
|
||||
) -> str:
|
||||
raise SilenceNotFoundError
|
||||
|
||||
|
||||
class FakeCache:
|
||||
def __init__(self, cache_dict: Optional[Dict] = None) -> None:
|
||||
if cache_dict is None:
|
||||
|
@ -533,14 +527,20 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
)
|
||||
self.assertEqual({"fingerprint1": ("silence2", 864000)}, fake_cache.cache)
|
||||
|
||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "create_silence")
|
||||
@patch.object(
|
||||
matrix_alertbot.alertmanager.AlertmanagerClient,
|
||||
"update_silence",
|
||||
side_effect=SilenceNotFoundError,
|
||||
)
|
||||
@patch.object(
|
||||
matrix_alertbot.alertmanager.AlertmanagerClient,
|
||||
"create_silence",
|
||||
return_value="silence1",
|
||||
)
|
||||
async def test_create_or_update_silence_with_duration_and_silence_not_found(
|
||||
self, fake_create_silence: Mock, fake_update_silence: Mock
|
||||
) -> None:
|
||||
fake_cache = Mock(spec=Cache)
|
||||
fake_update_silence.side_effect = update_silence_raise_silence_not_found
|
||||
fake_create_silence.return_value = "silence1"
|
||||
|
||||
alertmanager_client = AlertmanagerClient("http://localhost", fake_cache)
|
||||
async with aiotools.closing_async(alertmanager_client):
|
||||
|
@ -651,14 +651,20 @@ class AlertmanagerClientTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
)
|
||||
self.assertEqual({"fingerprint1": ("silence2", None)}, fake_cache.cache)
|
||||
|
||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "update_silence")
|
||||
@patch.object(matrix_alertbot.alertmanager.AlertmanagerClient, "create_silence")
|
||||
@patch.object(
|
||||
matrix_alertbot.alertmanager.AlertmanagerClient,
|
||||
"update_silence",
|
||||
side_effect=SilenceNotFoundError,
|
||||
)
|
||||
@patch.object(
|
||||
matrix_alertbot.alertmanager.AlertmanagerClient,
|
||||
"create_silence",
|
||||
return_value="silence1",
|
||||
)
|
||||
async def test_create_or_update_silence_without_duration_and_silence_not_found(
|
||||
self, fake_create_silence: Mock, fake_update_silence: Mock
|
||||
) -> None:
|
||||
fake_cache = Mock(spec=Cache)
|
||||
fake_update_silence.side_effect = update_silence_raise_silence_not_found
|
||||
fake_create_silence.return_value = "silence1"
|
||||
|
||||
alertmanager_client = AlertmanagerClient("http://localhost", fake_cache)
|
||||
async with aiotools.closing_async(alertmanager_client):
|
||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import unittest
|
||||
from typing import Dict
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
from unittest.mock import MagicMock, Mock, call, patch
|
||||
|
||||
import nio
|
||||
import nio.crypto
|
||||
|
@ -14,10 +14,6 @@ import matrix_alertbot.command
|
|||
import matrix_alertbot.matrix
|
||||
|
||||
|
||||
def key_verification_get_mac_raise_protocol_error():
|
||||
raise nio.LocalProtocolError
|
||||
|
||||
|
||||
class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
||||
def setUp(self) -> None:
|
||||
# Create a Callbacks object and give it some Mock'd objects to use
|
||||
|
@ -67,6 +63,42 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
# Check that we attempted to join the room
|
||||
self.fake_matrix_client.join.assert_called_once_with(self.fake_room.room_id)
|
||||
|
||||
async def test_invite_in_unauthorized_room(self) -> None:
|
||||
"""Tests the callback for InviteMemberEvents"""
|
||||
# Tests that the bot attempts to join a room after being invited to it
|
||||
fake_invite_event = Mock(spec=nio.InviteMemberEvent)
|
||||
fake_invite_event.sender = "@some_other_fake_user:example.com"
|
||||
|
||||
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
||||
|
||||
# Pretend that we received an invite event
|
||||
await self.callbacks.invite(self.fake_room, fake_invite_event)
|
||||
|
||||
# Check that we attempted to join the room
|
||||
self.fake_matrix_client.join.assert_not_called()
|
||||
|
||||
async def test_invite_raise_join_error(self) -> None:
|
||||
"""Tests the callback for InviteMemberEvents"""
|
||||
# Tests that the bot attempts to join a room after being invited to it
|
||||
fake_invite_event = Mock(spec=nio.InviteMemberEvent)
|
||||
fake_invite_event.sender = "@some_other_fake_user:example.com"
|
||||
|
||||
fake_join_error = Mock(spec=nio.JoinError)
|
||||
fake_join_error.message = "error message"
|
||||
self.fake_matrix_client.join.return_value = fake_join_error
|
||||
|
||||
# Pretend that we received an invite event
|
||||
await self.callbacks.invite(self.fake_room, fake_invite_event)
|
||||
|
||||
# Check that we attempted to join the room
|
||||
self.fake_matrix_client.join.assert_has_calls(
|
||||
[
|
||||
call("!abcdefg:example.com"),
|
||||
call("!abcdefg:example.com"),
|
||||
call("!abcdefg:example.com"),
|
||||
]
|
||||
)
|
||||
|
||||
@patch.object(matrix_alertbot.callback.CommandFactory, "create", autospec=True)
|
||||
async def test_message_without_prefix(self, fake_command_create: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText without any command prefix"""
|
||||
|
@ -82,6 +114,24 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
# Check that the command was not executed
|
||||
fake_command_create.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
||||
async def test_message_help_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText without any command prefix"""
|
||||
# Tests that the bot process messages in the room
|
||||
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 = "!alert help"
|
||||
fake_message_event.source = {"content": {}}
|
||||
|
||||
self.fake_matrix_client_pool.matrix_client = None
|
||||
|
||||
# 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_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.command, "HelpCommand", autospec=True)
|
||||
async def test_message_help_not_in_reply_with_prefix(
|
||||
self, fake_command: Mock
|
||||
|
@ -271,6 +321,72 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
)
|
||||
fake_command.return_value.process.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.command, "AckAlertCommand", autospec=True)
|
||||
async def test_message_raise_exception(
|
||||
self, fake_command: Mock, fake_logger
|
||||
) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
# 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 = "!alert ack"
|
||||
fake_message_event.source = {
|
||||
"content": {
|
||||
"m.relates_to": {"m.in_reply_to": {"event_id": "some alert event id"}}
|
||||
}
|
||||
}
|
||||
|
||||
fake_command.return_value.process.side_effect = (
|
||||
nio.exceptions.LocalProtocolError
|
||||
)
|
||||
|
||||
# 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()
|
||||
|
||||
fake_logger.exception.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||
async def test_reaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
# 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
|
||||
|
||||
self.fake_matrix_client_pool.matrix_client = None
|
||||
|
||||
# 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_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||
async def test_reaction_to_existing_alert(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
|
@ -365,6 +481,52 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
self.fake_room.room_id, fake_alert_event.event_id
|
||||
)
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||
async def test_reaction_raise_exception(
|
||||
self, fake_command: Mock, fake_logger: Mock
|
||||
) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
# 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
|
||||
|
||||
fake_command.return_value.process.side_effect = (
|
||||
nio.exceptions.LocalProtocolError
|
||||
)
|
||||
|
||||
# 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_logger.exception.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "AckAlertCommand", autospec=True)
|
||||
async def test_reaction_unknown(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
|
@ -429,6 +591,28 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
fake_command.assert_not_called()
|
||||
self.fake_matrix_client.room_get_event.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||
async def test_redaction_client_not_in_pool(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
# Tests that the bot process messages in the room that contain a command
|
||||
fake_alert_event_id = "some alert event id"
|
||||
|
||||
fake_redaction_event = Mock(spec=nio.RedactionEvent)
|
||||
fake_redaction_event.redacts = "some other event id"
|
||||
fake_redaction_event.event_id = "some event id"
|
||||
fake_redaction_event.sender = "@some_other_fake_user:example.com"
|
||||
|
||||
fake_cache_dict = {fake_redaction_event.redacts: fake_alert_event_id}
|
||||
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
|
||||
|
||||
self.fake_matrix_client_pool.matrix_client = None
|
||||
|
||||
# Pretend that we received a text message event
|
||||
await self.callbacks.redaction(self.fake_room, fake_redaction_event)
|
||||
|
||||
# Check that we attempted to execute the command
|
||||
fake_command.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||
async def test_redaction(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
|
@ -459,6 +643,45 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
)
|
||||
fake_command.return_value.process.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||
async def test_redaction_raise_exception(
|
||||
self, fake_command: Mock, fake_logger
|
||||
) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
# Tests that the bot process messages in the room that contain a command
|
||||
fake_alert_event_id = "some alert event id"
|
||||
|
||||
fake_redaction_event = Mock(spec=nio.RedactionEvent)
|
||||
fake_redaction_event.redacts = "some other event id"
|
||||
fake_redaction_event.event_id = "some event id"
|
||||
fake_redaction_event.sender = "@some_other_fake_user:example.com"
|
||||
|
||||
fake_cache_dict = {fake_redaction_event.redacts: fake_alert_event_id}
|
||||
self.fake_cache.__getitem__.side_effect = fake_cache_dict.__getitem__
|
||||
|
||||
fake_command.return_value.process.side_effect = (
|
||||
nio.exceptions.LocalProtocolError
|
||||
)
|
||||
|
||||
# Pretend that we received a text message event
|
||||
await self.callbacks.redaction(self.fake_room, fake_redaction_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_redaction_event.sender,
|
||||
fake_redaction_event.event_id,
|
||||
fake_redaction_event.redacts,
|
||||
)
|
||||
fake_command.return_value.process.assert_called_once()
|
||||
|
||||
fake_logger.exception.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "UnackAlertCommand", autospec=True)
|
||||
async def test_ignore_redaction_sent_by_bot_user(self, fake_command: Mock) -> None:
|
||||
"""Tests the callback for RoomMessageText with the command prefix"""
|
||||
|
@ -718,7 +941,7 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
fake_key_verification_event.transaction_id = fake_transaction_id
|
||||
|
||||
fake_sas = Mock()
|
||||
fake_sas.get_mac.side_effect = key_verification_get_mac_raise_protocol_error
|
||||
fake_sas.get_mac.side_effect = nio.exceptions.LocalProtocolError
|
||||
fake_transactions_dict = {fake_transaction_id: fake_sas}
|
||||
self.fake_matrix_client.key_verifications = fake_transactions_dict
|
||||
|
||||
|
@ -751,6 +974,81 @@ class CallbacksTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
fake_sas.get_mac.assert_called_once_with()
|
||||
self.fake_matrix_client.to_device.assert_called_once_with(fake_sas.get_mac())
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "logger", autospec=True)
|
||||
async def test_decryption_failure(self, fake_logger) -> None:
|
||||
fake_megolm_event = Mock(spec=nio.MegolmEvent)
|
||||
fake_megolm_event.sender = "@some_other_fake_user:example.com"
|
||||
fake_megolm_event.event_id = "some event id"
|
||||
|
||||
await self.callbacks.decryption_failure(self.fake_room, fake_megolm_event)
|
||||
|
||||
fake_logger.error.assert_called_once()
|
||||
|
||||
@patch.object(matrix_alertbot.callback, "logger", autospec=True)
|
||||
async def test_decryption_failure_in_unauthorized_room(self, fake_logger) -> None:
|
||||
fake_megolm_event = Mock(spec=nio.MegolmEvent)
|
||||
fake_megolm_event.sender = "@some_other_fake_user:example.com"
|
||||
fake_megolm_event.event_id = "some event id"
|
||||
|
||||
self.fake_room.room_id = "!unauthorizedroom@example.com"
|
||||
|
||||
await self.callbacks.decryption_failure(self.fake_room, fake_megolm_event)
|
||||
|
||||
fake_logger.error.assert_not_called()
|
||||
|
||||
async def test_unknown_message(self) -> None:
|
||||
fake_room_unknown_event = Mock(spec=nio.RoomMessageUnknown)
|
||||
fake_room_unknown_event.source = {
|
||||
"content": {
|
||||
"msgtype": "m.key.verification.request",
|
||||
"methods": ["m.sas.v1"],
|
||||
}
|
||||
}
|
||||
fake_room_unknown_event.event_id = "some event id"
|
||||
|
||||
await self.callbacks.unknown_message(self.fake_room, fake_room_unknown_event)
|
||||
|
||||
self.fake_matrix_client.room_send.assert_called_once_with(
|
||||
self.fake_room.room_id,
|
||||
"m.room.message",
|
||||
{
|
||||
"msgtype": "m.key.verification.ready",
|
||||
"methods": ["m.sas.v1"],
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.reference",
|
||||
"event_id": fake_room_unknown_event.event_id,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
async def test_unknown_message_with_msgtype_not_verification_request(self) -> None:
|
||||
fake_room_unknown_event = Mock(spec=nio.RoomMessageUnknown)
|
||||
fake_room_unknown_event.source = {
|
||||
"content": {
|
||||
"msgtype": "unknown",
|
||||
"methods": ["m.sas.v1"],
|
||||
}
|
||||
}
|
||||
fake_room_unknown_event.event_id = "some event id"
|
||||
|
||||
await self.callbacks.unknown_message(self.fake_room, fake_room_unknown_event)
|
||||
|
||||
self.fake_matrix_client.room_send.assert_not_called()
|
||||
|
||||
async def test_unknown_message_with_method_not_sas_v1(self) -> None:
|
||||
fake_room_unknown_event = Mock(spec=nio.RoomMessageUnknown)
|
||||
fake_room_unknown_event.source = {
|
||||
"content": {
|
||||
"msgtype": "m.key.verification.request",
|
||||
"methods": [],
|
||||
}
|
||||
}
|
||||
fake_room_unknown_event.event_id = "some event id"
|
||||
|
||||
await self.callbacks.unknown_message(self.fake_room, fake_room_unknown_event)
|
||||
|
||||
self.fake_matrix_client.room_send.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import unittest
|
||||
from typing import Any, Dict, Optional
|
||||
from unittest.mock import Mock
|
||||
|
||||
import nio
|
||||
|
@ -11,16 +10,6 @@ from matrix_alertbot.chat_functions import (
|
|||
)
|
||||
|
||||
|
||||
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
|
||||
|
@ -179,7 +168,7 @@ class ChatFunctionsTestCase(unittest.IsolatedAsyncioTestCase):
|
|||
|
||||
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.side_effect = send_room_raise_send_retry_error
|
||||
fake_matrix_client.room_send.side_effect = nio.exceptions.SendRetryError
|
||||
|
||||
fake_room_id = "!abcdefgh:example.com"
|
||||
fake_plaintext_body = "some plaintext message"
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from datetime import timedelta
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import yaml
|
||||
|
||||
import matrix_alertbot.config
|
||||
from matrix_alertbot.config import DEFAULT_REACTIONS, Config
|
||||
from matrix_alertbot.errors import (
|
||||
InvalidConfigError,
|
||||
|
@ -38,8 +40,15 @@ class ConfigTestCase(unittest.TestCase):
|
|||
@patch("os.path.isdir")
|
||||
@patch("os.path.exists")
|
||||
@patch("os.mkdir")
|
||||
@patch.object(matrix_alertbot.config, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.config, "logging", autospec=True)
|
||||
def test_read_minimal_config(
|
||||
self, fake_mkdir: Mock, fake_path_exists: Mock, fake_path_isdir: Mock
|
||||
self,
|
||||
fake_logging: Mock,
|
||||
fake_logger: Mock,
|
||||
fake_mkdir: Mock,
|
||||
fake_path_exists: Mock,
|
||||
fake_path_isdir: Mock,
|
||||
) -> None:
|
||||
fake_path_isdir.return_value = False
|
||||
fake_path_exists.return_value = False
|
||||
|
@ -51,6 +60,11 @@ class ConfigTestCase(unittest.TestCase):
|
|||
fake_path_exists.assert_called_once_with("data/store")
|
||||
fake_mkdir.assert_called_once_with("data/store")
|
||||
|
||||
fake_logger.setLevel.assert_called_once_with("INFO")
|
||||
fake_logger.addHandler.assert_called_once()
|
||||
fake_logging.StreamHandler.return_value.setLevel("INFO")
|
||||
fake_logging.StreamHandler.assert_called_once_with(sys.stdout)
|
||||
|
||||
self.assertEqual({"@fakes_user:matrix.example.com"}, config.user_ids)
|
||||
self.assertEqual(1, len(config.accounts))
|
||||
self.assertEqual("password", config.accounts[0].password)
|
||||
|
@ -82,8 +96,15 @@ class ConfigTestCase(unittest.TestCase):
|
|||
@patch("os.path.isdir")
|
||||
@patch("os.path.exists")
|
||||
@patch("os.mkdir")
|
||||
@patch.object(matrix_alertbot.config, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.config, "logging", autospec=True)
|
||||
def test_read_full_config(
|
||||
self, fake_mkdir: Mock, fake_path_exists: Mock, fake_path_isdir: Mock
|
||||
self,
|
||||
fake_logging: Mock,
|
||||
fake_logger: Mock,
|
||||
fake_mkdir: Mock,
|
||||
fake_path_exists: Mock,
|
||||
fake_path_isdir: Mock,
|
||||
) -> None:
|
||||
fake_path_isdir.return_value = False
|
||||
fake_path_exists.return_value = False
|
||||
|
@ -95,6 +116,11 @@ class ConfigTestCase(unittest.TestCase):
|
|||
fake_path_exists.assert_called_once_with("data/store")
|
||||
fake_mkdir.assert_called_once_with("data/store")
|
||||
|
||||
fake_logger.setLevel.assert_called_once_with("DEBUG")
|
||||
fake_logger.addHandler.assert_called_once()
|
||||
fake_logging.FileHandler.return_value.setLevel("DEBUG")
|
||||
fake_logging.FileHandler.assert_called_once_with("fake.log")
|
||||
|
||||
self.assertEqual(
|
||||
{"@fakes_user:matrix.example.com", "@other_user:matrix.domain.tld"},
|
||||
config.user_ids,
|
||||
|
@ -333,6 +359,60 @@ class ConfigTestCase(unittest.TestCase):
|
|||
with self.assertRaises(InvalidConfigError):
|
||||
config._parse_config_values()
|
||||
|
||||
@patch("os.path.isdir")
|
||||
@patch("os.path.exists")
|
||||
@patch("os.mkdir")
|
||||
@patch.object(matrix_alertbot.config, "logger")
|
||||
def test_parse_config_with_both_logging_disabled(
|
||||
self,
|
||||
fake_logger: Mock,
|
||||
fake_mkdir: Mock,
|
||||
fake_path_exists: Mock,
|
||||
fake_path_isdir: Mock,
|
||||
) -> None:
|
||||
fake_path_isdir.return_value = False
|
||||
fake_path_exists.return_value = False
|
||||
|
||||
config_path = os.path.join(CONFIG_RESOURCES_DIR, "config.full.yml")
|
||||
config = DummyConfig(config_path)
|
||||
config.config_dict["logging"]["file_logging"]["enabled"] = False
|
||||
config.config_dict["logging"]["console_logging"]["enabled"] = False
|
||||
|
||||
config._parse_config_values()
|
||||
|
||||
fake_logger.addHandler.assert_not_called()
|
||||
fake_logger.setLevel.assert_called_once_with("DEBUG")
|
||||
|
||||
@patch("os.path.isdir")
|
||||
@patch("os.path.exists")
|
||||
@patch("os.mkdir")
|
||||
@patch.object(matrix_alertbot.config, "logger", autospec=True)
|
||||
@patch.object(matrix_alertbot.config, "logging", autospec=True)
|
||||
def test_parse_config_with_level_logging_different(
|
||||
self,
|
||||
fake_logging: Mock,
|
||||
fake_logger: Mock,
|
||||
fake_mkdir: Mock,
|
||||
fake_path_exists: Mock,
|
||||
fake_path_isdir: Mock,
|
||||
) -> None:
|
||||
fake_path_isdir.return_value = False
|
||||
fake_path_exists.return_value = False
|
||||
|
||||
config_path = os.path.join(CONFIG_RESOURCES_DIR, "config.full.yml")
|
||||
config = DummyConfig(config_path)
|
||||
config.config_dict["logging"]["file_logging"]["enabled"] = True
|
||||
config.config_dict["logging"]["file_logging"]["level"] = "WARN"
|
||||
config.config_dict["logging"]["console_logging"]["enabled"] = True
|
||||
config.config_dict["logging"]["console_logging"]["level"] = "ERROR"
|
||||
|
||||
config._parse_config_values()
|
||||
|
||||
self.assertEqual(2, fake_logger.addHandler.call_count)
|
||||
fake_logger.setLevel.assert_called_once_with("DEBUG")
|
||||
fake_logging.FileHandler.return_value.setLevel.assert_called_with("WARN")
|
||||
fake_logging.StreamHandler.return_value.setLevel.assert_called_with("ERROR")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
302
tests/test_matrix.py
Normal file
302
tests/test_matrix.py
Normal file
|
@ -0,0 +1,302 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import unittest
|
||||
from unittest.mock import Mock, call, patch
|
||||
|
||||
import nio
|
||||
from diskcache import Cache
|
||||
|
||||
import matrix_alertbot
|
||||
import matrix_alertbot.matrix
|
||||
from matrix_alertbot.alertmanager import AlertmanagerClient
|
||||
from matrix_alertbot.config import AccountConfig, Config
|
||||
from matrix_alertbot.matrix import MatrixClientPool
|
||||
|
||||
|
||||
def mock_create_matrix_client(
|
||||
matrix_client_pool: MatrixClientPool,
|
||||
account: AccountConfig,
|
||||
alertmanager_client: AlertmanagerClient,
|
||||
cache: Cache,
|
||||
config: Config,
|
||||
) -> nio.AsyncClient:
|
||||
fake_matrix_client = Mock(spec=nio.AsyncClient)
|
||||
fake_matrix_client.logged_in = True
|
||||
return fake_matrix_client
|
||||
|
||||
|
||||
class FakeAsyncClientConfig:
|
||||
def __init__(
|
||||
self,
|
||||
max_limit_exceeded: int,
|
||||
max_timeouts: int,
|
||||
store_sync_tokens: bool,
|
||||
encryption_enabled: bool,
|
||||
) -> None:
|
||||
if encryption_enabled:
|
||||
raise ImportWarning()
|
||||
|
||||
self.max_limit_exceeded = max_limit_exceeded
|
||||
self.max_timeouts = max_timeouts
|
||||
self.store_sync_tokens = store_sync_tokens
|
||||
self.encryption_enabled = encryption_enabled
|
||||
|
||||
|
||||
class MatrixClientPoolTestCase(unittest.IsolatedAsyncioTestCase):
|
||||
async def asyncSetUp(self) -> None:
|
||||
random.seed(42)
|
||||
|
||||
self.fake_alertmanager_client = Mock(spec=AlertmanagerClient)
|
||||
self.fake_cache = Mock(spec=Cache)
|
||||
|
||||
self.fake_account_config_1 = Mock(spec=AccountConfig)
|
||||
self.fake_account_config_1.id = "@fake_user:matrix.example.com"
|
||||
self.fake_account_config_1.homeserver_url = "https://matrix.example.com"
|
||||
self.fake_account_config_1.device_id = "ABCDEFGH"
|
||||
self.fake_account_config_1.token_file = "account1.token.secret"
|
||||
self.fake_account_config_2 = Mock(spec=AccountConfig)
|
||||
self.fake_account_config_2.id = "@other_user:chat.example.com"
|
||||
self.fake_account_config_2.homeserver_url = "https://chat.example.com"
|
||||
self.fake_account_config_2.device_id = "IJKLMNOP"
|
||||
self.fake_account_config_2.token_file = "account2.token.secret"
|
||||
self.fake_config = Mock(spec=Config)
|
||||
self.fake_config.store_dir = "/dev/null"
|
||||
self.fake_config.command_prefix = "!alert"
|
||||
self.fake_config.accounts = [
|
||||
self.fake_account_config_1,
|
||||
self.fake_account_config_2,
|
||||
]
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool, "_create_matrix_client", autospec=True
|
||||
)
|
||||
async def test_init_matrix_client_pool(self, fake_create_matrix_client) -> None:
|
||||
fake_matrix_client = Mock(spec=nio.AsyncClient)
|
||||
fake_create_matrix_client.return_value = fake_matrix_client
|
||||
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
fake_create_matrix_client.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
matrix_client_pool,
|
||||
self.fake_account_config_1,
|
||||
self.fake_alertmanager_client,
|
||||
self.fake_cache,
|
||||
self.fake_config,
|
||||
),
|
||||
call(
|
||||
matrix_client_pool,
|
||||
self.fake_account_config_2,
|
||||
self.fake_alertmanager_client,
|
||||
self.fake_cache,
|
||||
self.fake_config,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(self.fake_account_config_1, matrix_client_pool.account)
|
||||
self.assertEqual(fake_matrix_client, matrix_client_pool.matrix_client)
|
||||
self.assertEqual(2, len(matrix_client_pool._accounts))
|
||||
self.assertEqual(2, len(matrix_client_pool._matrix_clients))
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool, "_create_matrix_client", autospec=True
|
||||
)
|
||||
async def test_close_matrix_client_pool(self, fake_create_matrix_client) -> None:
|
||||
fake_matrix_client = Mock(spec=nio.AsyncClient)
|
||||
fake_create_matrix_client.return_value = fake_matrix_client
|
||||
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
await matrix_client_pool.close()
|
||||
|
||||
fake_matrix_client.close.assert_has_calls([(call(), call())])
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool,
|
||||
"_create_matrix_client",
|
||||
autospec=True,
|
||||
side_effect=mock_create_matrix_client,
|
||||
)
|
||||
async def test_switch_active_client(self, fake_create_matrix_client) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
fake_matrix_client_1 = matrix_client_pool.matrix_client
|
||||
await matrix_client_pool.switch_active_client()
|
||||
fake_matrix_client_2 = matrix_client_pool.matrix_client
|
||||
|
||||
self.assertEqual(self.fake_account_config_2, matrix_client_pool.account)
|
||||
self.assertNotEqual(fake_matrix_client_2, fake_matrix_client_1)
|
||||
|
||||
await matrix_client_pool.switch_active_client()
|
||||
fake_matrix_client_3 = matrix_client_pool.matrix_client
|
||||
|
||||
self.assertEqual(self.fake_account_config_1, matrix_client_pool.account)
|
||||
self.assertEqual(fake_matrix_client_3, fake_matrix_client_1)
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool,
|
||||
"_create_matrix_client",
|
||||
autospec=True,
|
||||
side_effect=mock_create_matrix_client,
|
||||
)
|
||||
async def test_switch_active_client_with_whoami_raise_exception(
|
||||
self, fake_create_matrix_client
|
||||
) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
for fake_matrix_client in matrix_client_pool._matrix_clients.values():
|
||||
fake_matrix_client.whoami.side_effect = Exception
|
||||
|
||||
fake_matrix_client_1 = matrix_client_pool.matrix_client
|
||||
await matrix_client_pool.switch_active_client()
|
||||
fake_matrix_client_2 = matrix_client_pool.matrix_client
|
||||
|
||||
self.assertEqual(self.fake_account_config_1, matrix_client_pool.account)
|
||||
self.assertEqual(fake_matrix_client_2, fake_matrix_client_1)
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool,
|
||||
"_create_matrix_client",
|
||||
autospec=True,
|
||||
side_effect=mock_create_matrix_client,
|
||||
)
|
||||
async def test_switch_active_client_with_whoami_error(
|
||||
self, fake_create_matrix_client
|
||||
) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
for fake_matrix_client in matrix_client_pool._matrix_clients.values():
|
||||
fake_matrix_client.whoami.return_value = Mock(
|
||||
spec=nio.responses.WhoamiError
|
||||
)
|
||||
|
||||
fake_matrix_client_1 = matrix_client_pool.matrix_client
|
||||
await matrix_client_pool.switch_active_client()
|
||||
fake_matrix_client_2 = matrix_client_pool.matrix_client
|
||||
|
||||
self.assertEqual(self.fake_account_config_1, matrix_client_pool.account)
|
||||
self.assertEqual(fake_matrix_client_2, fake_matrix_client_1)
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix.MatrixClientPool,
|
||||
"_create_matrix_client",
|
||||
autospec=True,
|
||||
side_effect=mock_create_matrix_client,
|
||||
)
|
||||
async def test_switch_active_client_with_whoami_error_and_not_logged_in(
|
||||
self, fake_create_matrix_client
|
||||
) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
for fake_matrix_client in matrix_client_pool._matrix_clients.values():
|
||||
fake_matrix_client.whoami.return_value = Mock(
|
||||
spec=nio.responses.WhoamiError
|
||||
)
|
||||
fake_matrix_client.logged_in = False
|
||||
|
||||
fake_matrix_client_1 = matrix_client_pool.matrix_client
|
||||
await matrix_client_pool.switch_active_client()
|
||||
fake_matrix_client_2 = matrix_client_pool.matrix_client
|
||||
|
||||
self.assertEqual(self.fake_account_config_1, matrix_client_pool.account)
|
||||
self.assertEqual(fake_matrix_client_2, fake_matrix_client_1)
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix, "AsyncClientConfig", spec=nio.AsyncClientConfig
|
||||
)
|
||||
async def test_create_matrix_client(self, fake_async_client_config: Mock) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
matrix_client_1 = matrix_client_pool._matrix_clients[self.fake_account_config_1]
|
||||
self.assertEqual(self.fake_account_config_1.id, matrix_client_1.user)
|
||||
self.assertEqual(
|
||||
self.fake_account_config_1.device_id, matrix_client_1.device_id
|
||||
)
|
||||
self.assertEqual(
|
||||
self.fake_account_config_1.homeserver_url, matrix_client_1.homeserver
|
||||
)
|
||||
self.assertEqual(self.fake_config.store_dir, matrix_client_1.store_path)
|
||||
self.assertEqual(6, len(matrix_client_1.event_callbacks))
|
||||
self.assertEqual(4, len(matrix_client_1.to_device_callbacks))
|
||||
|
||||
fake_async_client_config.assert_has_calls(
|
||||
[
|
||||
call(
|
||||
max_limit_exceeded=5,
|
||||
max_timeouts=3,
|
||||
store_sync_tokens=True,
|
||||
encryption_enabled=True,
|
||||
),
|
||||
call(
|
||||
max_limit_exceeded=5,
|
||||
max_timeouts=3,
|
||||
store_sync_tokens=True,
|
||||
encryption_enabled=True,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@patch.object(
|
||||
matrix_alertbot.matrix,
|
||||
"AsyncClientConfig",
|
||||
spec=nio.AsyncClientConfig,
|
||||
side_effect=FakeAsyncClientConfig,
|
||||
)
|
||||
async def test_create_matrix_client_with_encryption_disabled(
|
||||
self, fake_async_client_config: Mock
|
||||
) -> None:
|
||||
matrix_client_pool = MatrixClientPool(
|
||||
alertmanager_client=self.fake_alertmanager_client,
|
||||
cache=self.fake_cache,
|
||||
config=self.fake_config,
|
||||
)
|
||||
|
||||
matrix_client_1 = matrix_client_pool._matrix_clients[self.fake_account_config_1]
|
||||
self.assertEqual(self.fake_account_config_1.id, matrix_client_1.user)
|
||||
self.assertEqual(
|
||||
self.fake_account_config_1.device_id, matrix_client_1.device_id
|
||||
)
|
||||
self.assertEqual(
|
||||
self.fake_account_config_1.homeserver_url, matrix_client_1.homeserver
|
||||
)
|
||||
self.assertEqual(self.fake_config.store_dir, matrix_client_1.store_path)
|
||||
self.assertEqual(6, len(matrix_client_1.event_callbacks))
|
||||
self.assertEqual(4, len(matrix_client_1.to_device_callbacks))
|
||||
self.assertEqual(5, matrix_client_1.config.max_limit_exceeded)
|
||||
self.assertEqual(3, matrix_client_1.config.max_timeouts)
|
||||
self.assertTrue(matrix_client_1.config.store_sync_tokens)
|
||||
self.assertFalse(matrix_client_1.config.encryption_enabled)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -4,27 +4,21 @@ from unittest.mock import Mock, call, patch
|
|||
|
||||
import aiohttp.test_utils
|
||||
import nio
|
||||
from aiohttp import web
|
||||
from aiohttp import web, web_request
|
||||
from diskcache import Cache
|
||||
from nio.exceptions import LocalProtocolError
|
||||
from nio.responses import RoomSendResponse
|
||||
|
||||
import matrix_alertbot.webhook
|
||||
from matrix_alertbot.alert import Alert, AlertRenderer
|
||||
from matrix_alertbot.alertmanager import AlertmanagerClient
|
||||
from matrix_alertbot.config import Config
|
||||
from matrix_alertbot.errors import (
|
||||
AlertmanagerError,
|
||||
MatrixClientError,
|
||||
SilenceExtendError,
|
||||
SilenceNotFoundError,
|
||||
)
|
||||
from matrix_alertbot.matrix import MatrixClientPool
|
||||
from matrix_alertbot.webhook import Webhook
|
||||
|
||||
|
||||
def send_text_to_room_raise_error(
|
||||
client: nio.AsyncClient, room_id: str, plaintext: str, html: str, notice: bool
|
||||
) -> RoomSendResponse:
|
||||
raise LocalProtocolError
|
||||
from matrix_alertbot.webhook import Webhook, create_alert
|
||||
|
||||
|
||||
def update_silence_raise_silence_not_found(fingerprint: str) -> str:
|
||||
|
@ -45,6 +39,7 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
self.fake_matrix_client_pool = Mock(spec=MatrixClientPool)
|
||||
self.fake_matrix_client_pool.matrix_client = self.fake_matrix_client
|
||||
self.fake_alertmanager_client = Mock(spec=AlertmanagerClient)
|
||||
self.fake_alert_renderer = Mock(spec=AlertRenderer)
|
||||
self.fake_cache = Mock(spec=Cache)
|
||||
|
||||
self.fake_room_id = "!abcdefg:example.com"
|
||||
|
@ -57,9 +52,16 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
self.fake_config.cache_expire_time = 0
|
||||
self.fake_config.template_dir = None
|
||||
|
||||
self.fake_alerts = {
|
||||
"alerts": [
|
||||
{
|
||||
self.fake_request = Mock(spec=web_request.Request)
|
||||
self.fake_request.app = {
|
||||
"alertmanager_client": self.fake_alertmanager_client,
|
||||
"alert_renderer": self.fake_alert_renderer,
|
||||
"matrix_client_pool": self.fake_matrix_client_pool,
|
||||
"cache": self.fake_cache,
|
||||
"config": self.fake_config,
|
||||
}
|
||||
|
||||
self.fake_alert_1 = {
|
||||
"fingerprint": "fingerprint1",
|
||||
"generatorURL": "http://example.com/alert1",
|
||||
"status": "firing",
|
||||
|
@ -69,8 +71,8 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
"job": "job1",
|
||||
},
|
||||
"annotations": {"description": "some description1"},
|
||||
},
|
||||
{
|
||||
}
|
||||
self.fake_alert_2 = {
|
||||
"fingerprint": "fingerprint2",
|
||||
"generatorURL": "http://example.com/alert2",
|
||||
"status": "resolved",
|
||||
|
@ -80,7 +82,11 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
"job": "job2",
|
||||
},
|
||||
"annotations": {"description": "some description2"},
|
||||
},
|
||||
}
|
||||
self.fake_alerts = {
|
||||
"alerts": [
|
||||
self.fake_alert_1,
|
||||
self.fake_alert_2,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -314,13 +320,14 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
self.fake_cache.set.assert_not_called()
|
||||
self.fake_cache.delete.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "logger", autospec=True)
|
||||
@patch.object(
|
||||
matrix_alertbot.webhook,
|
||||
"send_text_to_room",
|
||||
side_effect=send_text_to_room_raise_error,
|
||||
side_effect=nio.exceptions.LocalProtocolError("Local protocol error"),
|
||||
)
|
||||
async def test_post_alerts_raise_send_error(
|
||||
self, fake_send_text_to_room: Mock
|
||||
self, fake_send_text_to_room: Mock, fake_logger: Mock
|
||||
) -> None:
|
||||
self.fake_alertmanager_client.update_silence.side_effect = (
|
||||
update_silence_raise_silence_not_found
|
||||
|
@ -341,6 +348,178 @@ class WebhookApplicationTestCase(aiohttp.test_utils.AioHTTPTestCase):
|
|||
self.fake_cache.set.assert_not_called()
|
||||
self.fake_cache.delete.assert_called_once_with("fingerprint1")
|
||||
|
||||
fake_logger.error.assert_called_once_with(
|
||||
"Unable to send alert fingerprint1 to Matrix room !abcdefg:example.com: Local protocol error"
|
||||
)
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "logger", autospec=True)
|
||||
@patch.object(
|
||||
matrix_alertbot.webhook,
|
||||
"create_alert",
|
||||
side_effect=MatrixClientError("Matrix client error"),
|
||||
)
|
||||
async def test_post_alerts_raise_matrix_client_error(
|
||||
self, fake_create_alert: Mock, fake_logger: Mock
|
||||
) -> None:
|
||||
self.fake_alertmanager_client.update_silence.side_effect = (
|
||||
update_silence_raise_silence_not_found
|
||||
)
|
||||
|
||||
data = self.fake_alerts
|
||||
async with self.client.request(
|
||||
"POST", f"/alerts/{self.fake_room_id}", json=data
|
||||
) as response:
|
||||
self.assertEqual(500, response.status)
|
||||
error_msg = await response.text()
|
||||
|
||||
self.assertEqual(
|
||||
"An error occured when sending alert with fingerprint 'fingerprint1' to Matrix room.",
|
||||
error_msg,
|
||||
)
|
||||
fake_create_alert.assert_called_once()
|
||||
|
||||
fake_logger.error.assert_called_once_with(
|
||||
"Unable to send alert fingerprint1 to Matrix room !abcdefg:example.com: Matrix client error"
|
||||
)
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "logger", autospec=True)
|
||||
@patch.object(
|
||||
matrix_alertbot.webhook,
|
||||
"send_text_to_room",
|
||||
side_effect=Exception("Exception"),
|
||||
)
|
||||
async def test_post_alerts_raise_exception(
|
||||
self, fake_send_text_to_room: Mock, fake_logger: Mock
|
||||
) -> None:
|
||||
self.fake_alertmanager_client.update_silence.side_effect = (
|
||||
update_silence_raise_silence_not_found
|
||||
)
|
||||
|
||||
data = self.fake_alerts
|
||||
async with self.client.request(
|
||||
"POST", f"/alerts/{self.fake_room_id}", json=data
|
||||
) as response:
|
||||
self.assertEqual(500, response.status)
|
||||
error_msg = await response.text()
|
||||
|
||||
self.assertEqual(
|
||||
"An exception occured when sending alert with fingerprint 'fingerprint1' to Matrix room.",
|
||||
error_msg,
|
||||
)
|
||||
fake_send_text_to_room.assert_called_once()
|
||||
self.fake_cache.set.assert_not_called()
|
||||
self.fake_cache.delete.assert_called_once_with("fingerprint1")
|
||||
|
||||
fake_logger.error.assert_called_once_with(
|
||||
"Unable to send alert fingerprint1 to Matrix room !abcdefg:example.com: Exception"
|
||||
)
|
||||
|
||||
async def test_create_alert_update_silence(self) -> None:
|
||||
fake_alert = Mock(spec=Alert)
|
||||
fake_alert.firing = True
|
||||
fake_alert.fingerprint = "fingerprint"
|
||||
|
||||
await create_alert(fake_alert, self.fake_room_id, self.fake_request)
|
||||
|
||||
self.fake_alertmanager_client.update_silence.assert_called_once_with(
|
||||
fake_alert.fingerprint
|
||||
)
|
||||
self.fake_alert_renderer.render.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "send_text_to_room", autospec=True)
|
||||
async def test_create_alert_with_silence_not_found_error(
|
||||
self, fake_send_text_to_room: Mock
|
||||
) -> None:
|
||||
fake_alert = Mock(spec=Alert)
|
||||
fake_alert.firing = True
|
||||
fake_alert.fingerprint = "fingerprint"
|
||||
|
||||
self.fake_alertmanager_client.update_silence.side_effect = SilenceNotFoundError
|
||||
|
||||
await create_alert(fake_alert, self.fake_room_id, self.fake_request)
|
||||
|
||||
self.fake_alertmanager_client.update_silence.assert_called_once_with(
|
||||
fake_alert.fingerprint
|
||||
)
|
||||
self.fake_alert_renderer.render.assert_has_calls(
|
||||
[call(fake_alert, html=False), call(fake_alert, html=True)]
|
||||
)
|
||||
|
||||
fake_send_text_to_room.assert_called_once()
|
||||
|
||||
self.fake_cache.set.assert_called_once_with(
|
||||
fake_send_text_to_room.return_value.event_id,
|
||||
fake_alert.fingerprint,
|
||||
expire=self.fake_config.cache_expire_time,
|
||||
)
|
||||
self.fake_cache.delete.assert_called_once_with(fake_alert.fingerprint)
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "send_text_to_room", autospec=True)
|
||||
async def test_create_alert_with_silence_extend_error(
|
||||
self, fake_send_text_to_room: Mock
|
||||
) -> None:
|
||||
fake_alert = Mock(spec=Alert)
|
||||
fake_alert.firing = True
|
||||
fake_alert.fingerprint = "fingerprint"
|
||||
|
||||
self.fake_alertmanager_client.update_silence.side_effect = SilenceExtendError
|
||||
|
||||
await create_alert(fake_alert, self.fake_room_id, self.fake_request)
|
||||
|
||||
self.fake_alertmanager_client.update_silence.assert_called_once_with(
|
||||
fake_alert.fingerprint
|
||||
)
|
||||
self.fake_alert_renderer.render.assert_has_calls(
|
||||
[call(fake_alert, html=False), call(fake_alert, html=True)]
|
||||
)
|
||||
|
||||
fake_send_text_to_room.assert_called_once()
|
||||
|
||||
self.fake_cache.set.assert_called_once_with(
|
||||
fake_send_text_to_room.return_value.event_id,
|
||||
fake_alert.fingerprint,
|
||||
expire=self.fake_config.cache_expire_time,
|
||||
)
|
||||
self.fake_cache.delete.assert_not_called()
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "send_text_to_room", autospec=True)
|
||||
async def test_create_alert_not_firing(self, fake_send_text_to_room: Mock) -> None:
|
||||
fake_alert = Mock(spec=Alert)
|
||||
fake_alert.firing = False
|
||||
fake_alert.fingerprint = "fingerprint"
|
||||
|
||||
await create_alert(fake_alert, self.fake_room_id, self.fake_request)
|
||||
|
||||
self.fake_alertmanager_client.update_silence.assert_not_called()
|
||||
self.fake_alert_renderer.render.assert_has_calls(
|
||||
[call(fake_alert, html=False), call(fake_alert, html=True)]
|
||||
)
|
||||
|
||||
fake_send_text_to_room.assert_called_once()
|
||||
|
||||
self.fake_cache.set.assert_not_called()
|
||||
self.fake_cache.delete.assert_called_once_with(fake_alert.fingerprint)
|
||||
|
||||
@patch.object(matrix_alertbot.webhook, "send_text_to_room", autospec=True)
|
||||
async def test_create_alert_not_firing_raise_matrix_client_error(
|
||||
self, fake_send_text_to_room: Mock
|
||||
) -> None:
|
||||
fake_alert = Mock(spec=Alert)
|
||||
fake_alert.firing = False
|
||||
fake_alert.fingerprint = "fingerprint"
|
||||
|
||||
self.fake_matrix_client_pool.matrix_client = None
|
||||
|
||||
with self.assertRaises(MatrixClientError):
|
||||
await create_alert(fake_alert, self.fake_room_id, self.fake_request)
|
||||
|
||||
self.fake_alertmanager_client.update_silence.assert_not_called()
|
||||
self.fake_alert_renderer.render.assert_has_calls(
|
||||
[call(fake_alert, html=False), call(fake_alert, html=True)]
|
||||
)
|
||||
|
||||
fake_send_text_to_room.assert_not_called()
|
||||
|
||||
async def test_health(self) -> None:
|
||||
async with self.client.request("GET", "/health") as response:
|
||||
self.assertEqual(200, response.status)
|
||||
|
|
Loading…
Reference in a new issue