diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 183a373a9129738ebe52e475acfba68698aee622..0000000000000000000000000000000000000000 --- a/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Initialize Test Package.""" -# FIX for Poetry: https://github.com/python-poetry/poetry/issues/87 diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..723e32e0374bcf9da477ed0bab5a310e99377dc9 --- /dev/null +++ b/tests/unit/conftest.py @@ -0,0 +1,19 @@ +"""Package's fixtures.""" + +import pytest + +from notifications_routing.app import configure_logging +from notifications_routing.config import load_config + + +@pytest.fixture(scope="module") +def config(): + """Set up config.""" + config = load_config() + yield config + + +@pytest.fixture(scope="module") +def appctx(config): + """Set up app context.""" + configure_logging(config) diff --git a/tests/unit/test_router.py b/tests/unit/test_router.py index 52f52f437007bfd275fb24dbe2c3010ad033b184..ee688d3db4294e4a2f9bca0caa93d8748b17149e 100644 --- a/tests/unit/test_router.py +++ b/tests/unit/test_router.py @@ -2,12 +2,13 @@ import datetime from unittest import mock -from unittest.mock import MagicMock +from unittest.mock import ANY, MagicMock import pytest -from notifications_routing.data_source.postgres.postgres_data_source import User +from notifications_routing.data_source.postgres.postgres_data_source import Device, Preference, User from notifications_routing.exceptions import NotFoundDataSourceError +from notifications_routing.preferences import TargetPreference from notifications_routing.router import Router @@ -16,8 +17,12 @@ def router_mock(): """Private access record.""" with mock.patch.object(Router, "__init__", return_value=None): mock_router = Router() + mock_router.publisher = MagicMock() mock_router.data_source = MagicMock() mock_router.data_source.USERNAME = "username" + mock_router.data_source.EMAIL = "email" + mock_router.data_source.LAST_LOGIN = "last_login" + mock_router.data_source.USER_ID = "user_id" return mock_router @@ -91,6 +96,77 @@ def group_user_3(): return {"username": "testuser3", "email": "testuser3@cern.ch"} +@pytest.fixture(scope="function") +def message(): + """Message dict.""" + return { + "id": "d53a7d79-0c5e-4b72-9d6f-8492b7415340", + "channel_id": "c3ccc15b-298f-4dc7-877f-2c8970331caf", + "channel_name": "Test channel", + "channel_slug": "test-channel", + "priority": "NORMAL", + "created_timestamp": "2021-02-26T13:59:40.754Z", + "message_body": "test", + "summary": "test", + "link": None, + "img_url": None, + } + + +@pytest.fixture(scope="function") +def message_critical(): + """Message dict.""" + return { + "id": "d53a7d79-0c5e-4b72-9d6f-8492b7415340", + "channel_id": "c3ccc15b-298f-4dc7-877f-2c8970331caf", + "channel_name": "Test channel", + "channel_slug": "test-channel", + "priority": "CRITICAL", + "created_timestamp": "2021-02-26T13:59:40.754Z", + "message_body": "test", + "summary": "test", + "link": None, + "img_url": None, + } + + +@pytest.fixture(scope="function") +def preference(device): + """Preference object.""" + return Preference( + id="17fd2706-8baf-433b-82eb-8c7fada847da", + type="DAILY", + name="Daily preference", + userId="3eacfc35-42bd-49e8-9f2c-1e552c447ff3", + targetId="c3ccc15b-298f-4dc7-877f-2c8970331caf", + notificationPriority="NORMAL", + rangeStart=None, + rangeEnd=None, + scheduledTime=datetime.time(13, 0), + devices=[device], + ) + + +@pytest.fixture(scope="function") +def device(): + """Device object.""" + return Device( + id="d4e15d11-a56e-4568-9e9f-497110426a72", + name="testuser1@cern.ch", + userId="3eacfc35-42bd-49e8-9f2c-1e552c447ff3", + info="Default", + type="MAIL", + subType=None, + token=None, + ) + + +@pytest.fixture(scope="function") +def target_preference(preference): + """Target Preference object.""" + return TargetPreference(preference.type, preference.devices, preference.userId, preference.scheduledDay) + + def test_get_channel_users_one_group_without_no_system_users( router_mock, system_user_1, system_user_2, group_user_1, group_user_2 ): @@ -178,3 +254,92 @@ def test_get_channel_users_no_groups(router_mock, system_user_1, system_user_2): router_mock.data_source.get_group_users.assert_not_called() router_mock.data_source.get_system_user.assert_not_called() assert router_mock.get_channel_users("c3ccc15b-298f-4dc7-877f-2c8970331caf") == [system_user_1, system_user_2] + + +@mock.patch.object(Router, "get_channel_users") +def test_process_message_no_channel_users(mock_get_channel_users, appctx, router_mock, message): + """Test process message for channel without users.""" + mock_get_channel_users.return_value = [] + assert router_mock.process_message(message) is None + + +@mock.patch("notifications_routing.router.apply_default_preferences") +@mock.patch.object(Router, "get_channel_users") +def test_process_message_no_system_users( + mock_get_channel_users, mock_apply_default_preferences, appctx, router_mock, message, no_system_user_1 +): + """Test process message for non system users.""" + mock_get_channel_users.return_value = [no_system_user_1] + router_mock.process_message(message) + mock_apply_default_preferences.assert_called_once_with(ANY, message, "nosystemuser1@cern.ch") + + +@mock.patch("notifications_routing.router.apply_user_preferences") +@mock.patch("notifications_routing.router.apply_default_preferences") +@mock.patch.object(Router, "get_channel_users") +def test_process_message_system_user_mute_active( + mock_get_channel_users, + mock_apply_default_preferences, + mock_apply_user_preferences, + appctx, + router_mock, + message, + system_user_1, +): + """Test porcess message for system user with mute active.""" + mock_get_channel_users.return_value = [system_user_1] + router_mock.data_source.is_user_mute_active.return_value = True + router_mock.process_message(message) + assert not mock_apply_default_preferences.called + assert not mock_apply_user_preferences.called + + +@mock.patch("notifications_routing.router.apply_user_preferences") +@mock.patch.object(Router, "get_channel_users") +def test_process_message_system_user_with_preferences( + mock_get_channel_users, + mock_apply_user_preferences, + appctx, + router_mock, + message, + system_user_1, + preference, + target_preference, +): + """Test process message for system user with preferences.""" + mock_get_channel_users.return_value = [system_user_1] + router_mock.data_source.is_user_mute_active.return_value = False + router_mock.data_source.get_user_preferences.return_value = { + "email": "testuser1@cern.ch", + "preferences": [preference], + } + router_mock.data_source.get_delivery_methods_and_targets.return_value = {target_preference} + router_mock.process_message(message) + mock_apply_user_preferences.assert_called_once() + + +@mock.patch("notifications_routing.router.apply_all") +@mock.patch.object(Router, "get_channel_users") +def test_process_message_critical_message( + mock_get_channel_users, mock_apply_all, appctx, router_mock, message_critical, system_user_1, device +): + """Test process message for critical priority.""" + mock_get_channel_users.return_value = [system_user_1] + router_mock.data_source.get_user_devices.return_value = [device] + router_mock.process_message(message_critical) + mock_apply_all.assert_called_once_with(ANY, message_critical, "testuser1@cern.ch", [device]) + + +@mock.patch("notifications_routing.router.apply_default_preferences") +@mock.patch.object(Router, "get_channel_users") +def test_process_message_not_found_datasource_error( + mock_get_channel_users, mock_apply_default_preferences, appctx, router_mock, message, system_user_1 +): + """Test process message when resource is not found on db.""" + mock_get_channel_users.return_value = [system_user_1] + router_mock.data_source.is_user_mute_active.return_value = False + router_mock.data_source.get_user_preferences.side_effect = NotFoundDataSourceError( + User, id="3eacfc35-42bd-49e8-9f2c-1e552c447ff3" + ) + router_mock.process_message(message) + mock_apply_default_preferences.assert_called_once_with(ANY, message, "testuser1@cern.ch")