From 2896ed27f26b648b1c7e8d8f17a5cf0037ad619a Mon Sep 17 00:00:00 2001 From: Imdad Ahad Date: Tue, 17 Jan 2017 15:38:54 +0000 Subject: [PATCH] Add dao methods to retrieve providers, switch, toggle along with tests --- app/dao/provider_details_dao.py | 82 ++++++++++++++++++++- tests/app/conftest.py | 34 +++++++-- tests/app/dao/test_provider_details_dao.py | 84 ++++++++++++++++++++-- 3 files changed, 190 insertions(+), 10 deletions(-) diff --git a/app/dao/provider_details_dao.py b/app/dao/provider_details_dao.py index 9d559ee0b..ed04f6754 100644 --- a/app/dao/provider_details_dao.py +++ b/app/dao/provider_details_dao.py @@ -1,19 +1,99 @@ from datetime import datetime +from flask import current_app from sqlalchemy import asc + from app.dao.dao_utils import transactional from app.models import ProviderDetails, ProviderDetailsHistory from app import db def get_provider_details(): - return ProviderDetails.query.order_by(asc(ProviderDetails.priority), asc(ProviderDetails.notification_type)).all() + providers = ProviderDetails.query.order_by(asc(ProviderDetails.priority), asc(ProviderDetails.notification_type)).all() + return providers def get_provider_details_by_id(provider_details_id): return ProviderDetails.query.get(provider_details_id) +def get_provider_details_by_identifier(identifier): + return ProviderDetails.query.filter_by(identifier=identifier).one() + + +def get_alternative_sms_provider(identifier): + alternate_provider = None + if identifier == 'firetext': + alternate_provider = 'mmg' + elif identifier == 'mmg': + alternate_provider = 'firetext' + + return ProviderDetails.query.filter_by(identifier=alternate_provider).one() + + +def get_current_provider(notification_type): + return ProviderDetails.query.filter_by( + notification_type=notification_type + ).order_by( + asc(ProviderDetails.priority) + ).first() + + +@transactional +def dao_toggle_sms_provider(): + current_provider = get_current_provider('sms') + alternate_provider = get_alternative_sms_provider(current_provider.identifier) + + dao_switch_sms_provider_to_provider_with_identifier(alternate_provider.identifier) + + +@transactional +def dao_switch_sms_provider_to_provider_with_identifier(identifier): + # Do nothing if the provider is already primary or set as inactive + current_provider = get_current_provider('sms') + if current_provider.identifier == identifier: + current_app.logger.warning('Provider {} is already activated'.format(current_provider.display_name)) + return current_provider + + new_provider = get_provider_details_by_identifier(identifier) + if not new_provider.active: + current_app.logger.warning('Cancelling switch from {} to {} as {} is inactive'.format( + current_provider.identifier, + new_provider.identifier, + new_provider.identifier + )) + return current_provider + + # Swap priority to change primary provider + if new_provider.priority > current_provider.priority: + new_provider.priority, current_provider.priority = current_provider.priority, new_provider.priority + _print_provider_switch_logs(current_provider, new_provider) + db.session.add_all([current_provider, new_provider]) + + # Incease other provider priority if equal + elif new_provider.priority == current_provider.priority: + current_provider.priority += 10 + _print_provider_switch_logs(current_provider, new_provider) + db.session.add(current_provider) + + +def _print_provider_switch_logs(current_provider, new_provider): + current_app.logger.warning('Switching provider from {} to {}'.format( + current_provider.identifier, + new_provider.identifier + )) + + current_app.logger.warning('Provider {} now updated with priority of {}'.format( + current_provider.identifier, + current_provider.priority + )) + + current_app.logger.warning('Provider {} now updated with priority of {}'.format( + new_provider.identifier, + new_provider.priority + )) + + def get_provider_details_by_notification_type(notification_type): return ProviderDetails.query.filter_by( notification_type=notification_type diff --git a/tests/app/conftest.py b/tests/app/conftest.py index ea702ecd4..876d4519b 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -1,9 +1,10 @@ +import requests_mock +import pytest import uuid from datetime import (datetime, date, timedelta) +from sqlalchemy import asc from sqlalchemy.orm.session import make_transient -import requests_mock -import pytest from flask import current_app from app import db @@ -34,7 +35,11 @@ from app.dao.notifications_dao import dao_create_notification from app.dao.invited_user_dao import save_invited_user from app.dao.provider_rates_dao import create_provider_rates from app.clients.sms.firetext import FiretextClient - +from app.dao.provider_details_dao import ( + dao_update_provider_details, + get_provider_details_by_identifier, + get_alternative_sms_provider +) from tests.app.db import create_user @@ -628,6 +633,27 @@ def fake_uuid(): return "6ce466d0-fd6a-11e5-82f5-e0accb9d11a6" +@pytest.fixture(scope='function') +def current_sms_provider(): + return ProviderDetails.query.filter_by( + notification_type='sms' + ).order_by( + asc(ProviderDetails.priority) + ).first() + + +@pytest.fixture(scope='function') +def set_primary_sms_provider(identifier='mmg'): + primary_provider = get_provider_details_by_identifier(identifier) + secondary_provider = get_alternative_sms_provider(identifier) + + primary_provider.priority = 10 + secondary_provider.priority = 20 + + dao_update_provider_details(primary_provider) + dao_update_provider_details(secondary_provider) + + @pytest.fixture(scope='function') def ses_provider(): return ProviderDetails.query.filter_by(identifier='ses').one() @@ -635,7 +661,7 @@ def ses_provider(): @pytest.fixture(scope='function') def firetext_provider(): - return ProviderDetails.query.filter_by(identifier='mmg').one() + return ProviderDetails.query.filter_by(identifier='firetext').one() @pytest.fixture(scope='function') diff --git a/tests/app/dao/test_provider_details_dao.py b/tests/app/dao/test_provider_details_dao.py index 1bb2d8c09..09f34a7c2 100644 --- a/tests/app/dao/test_provider_details_dao.py +++ b/tests/app/dao/test_provider_details_dao.py @@ -1,3 +1,5 @@ +import pytest + from datetime import datetime from freezegun import freeze_time @@ -5,10 +7,15 @@ from freezegun import freeze_time from app.models import ProviderDetails, ProviderDetailsHistory from app import clients from app.dao.provider_details_dao import ( + get_alternative_sms_provider, + get_current_provider, get_provider_details, get_provider_details_by_notification_type, + dao_switch_sms_provider_to_provider_with_identifier, + dao_toggle_sms_provider, dao_update_provider_details ) +from tests.app.conftest import set_primary_sms_provider def test_can_get_all_providers(restore_provider_details): @@ -21,15 +28,13 @@ def test_can_get_sms_providers(restore_provider_details): assert all('sms' == prov.notification_type for prov in sms_providers) -def test_can_get_sms_providers_in_order(restore_provider_details): +def test_can_get_sms_providers_in_order_of_priority(restore_provider_details): providers = get_provider_details_by_notification_type('sms') - assert providers[0].identifier == "mmg" - assert providers[1].identifier == "firetext" - assert providers[2].identifier == "loadtesting" + assert providers[0].priority < providers[1].priority < providers[2].priority -def test_can_get_email_providers_in_order(restore_provider_details): +def test_can_get_email_providers_in_order_of_priority(restore_provider_details): providers = get_provider_details_by_notification_type('email') assert providers[0].identifier == "ses" @@ -78,3 +83,72 @@ def test_update_adds_history(restore_provider_details): assert not ses_history[1].active assert ses_history[1].version == 2 assert ses_history[1].updated_at == datetime(2000, 1, 1, 0, 0, 0) + + +def test_update_sms_provider_to_inactive_sets_inactive(restore_provider_details): + set_primary_sms_provider('mmg') + primary_provider = get_current_provider('sms') + primary_provider.active = False + + dao_update_provider_details(primary_provider) + + assert not primary_provider.active + + +def test_get_current_sms_provider_returns_correct_provider(restore_provider_details): + set_primary_sms_provider('mmg') + + provider = get_current_provider('sms') + + assert provider.identifier == 'mmg' + + +@pytest.mark.parametrize('provider_identifier', ['firetext', 'mmg']) +def test_get_alternative_sms_provider_returns_expected_provider(notify_db, provider_identifier): + provider = get_alternative_sms_provider(provider_identifier) + assert provider.identifier != provider + + +def test_switch_sms_provider_to_current_provider_does_not_switch( + notify_db, + notify_db_session, + restore_provider_details, + current_sms_provider, + mocker +): + dao_switch_sms_provider_to_provider_with_identifier(current_sms_provider.identifier) + new_provider = get_current_provider('sms') + + assert current_sms_provider.id == new_provider.id + assert current_sms_provider.identifier == new_provider.identifier + + +def test_switch_sms_provider_to_inactive_provider_does_not_switch( + notify_db, + notify_db_session, + restore_provider_details, + current_sms_provider, + mocker +): + alternative_sms_provider = get_alternative_sms_provider(current_sms_provider.identifier) + alternative_sms_provider.active = False + dao_update_provider_details(alternative_sms_provider) + + dao_switch_sms_provider_to_provider_with_identifier(alternative_sms_provider.identifier) + new_provider = get_current_provider('sms') + + assert new_provider.id == current_sms_provider.id + assert new_provider.identifier == current_sms_provider.identifier + + +def test_toggle_sms_provider_switches_provider( + notify_db, + notify_db_session, + restore_provider_details, + current_sms_provider, + mocker +): + dao_toggle_sms_provider() + new_provider = get_current_provider('sms') + + assert new_provider.identifier != current_sms_provider.identifier