From 033a3e530bec6a1bd15da2319a14c83f74bc9e8b Mon Sep 17 00:00:00 2001 From: Martyn Inglis Date: Fri, 11 Nov 2016 17:19:27 +0000 Subject: [PATCH] Increment the redis cache on a successful API call. These means that the cache count is on Notifications in the database NOT notifications sent to providers. If the provider fails to accept the notification, it still counts. I think this is correct, as they have done the work to send it so we should count it, though there is an argument that we should count them on sending? --- app/notifications/rest.py | 3 +- app/notifications/validators.py | 2 - .../rest/test_send_notification.py | 109 ++++++++++++++++++ 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/app/notifications/rest.py b/app/notifications/rest.py index 66b069579..be4e77fc1 100644 --- a/app/notifications/rest.py +++ b/app/notifications/rest.py @@ -37,6 +37,7 @@ from app.schemas import ( from app.service.utils import service_allowed_to_send_to from app.utils import pagination_links from app import redis_store +from app.clients import redis notifications = Blueprint('notifications', __name__) @@ -245,7 +246,7 @@ def send_notification(notification_type): notification_id = create_uuid() if saved_notification is None else saved_notification.id notification.update({"template_version": template.version}) - + redis_store.inc(redis.cache_key(service.id)) return jsonify( data=get_notification_return_data( notification_id, diff --git a/app/notifications/validators.py b/app/notifications/validators.py index df0695142..129aee3f8 100644 --- a/app/notifications/validators.py +++ b/app/notifications/validators.py @@ -15,8 +15,6 @@ def check_service_message_limit(key_type, service): if not service_stats: service_stats = services_dao.fetch_todays_total_message_count(service.id) redis_store.set(cache_key, service_stats, ex=3600) - print(service_stats) - print(service.message_limit) if service_stats >= service.message_limit: raise TooManyRequestsError(service.message_limit) diff --git a/tests/app/notifications/rest/test_send_notification.py b/tests/app/notifications/rest/test_send_notification.py index b4af5282e..2b056fd8e 100644 --- a/tests/app/notifications/rest/test_send_notification.py +++ b/tests/app/notifications/rest/test_send_notification.py @@ -27,6 +27,115 @@ from app.models import Template from app.errors import InvalidRequest +@freeze_time("2016-01-01 11:09:00.061258") +def test_should_increment_redis_cache_on_successful_email( + notify_api, + sample_email_template, + mocker): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + mocked_email = mocker.patch('app.celery.provider_tasks.deliver_email.apply_async') + mocked_redis = mocker.patch('app.notifications.rest.redis_store.inc') + mocker.patch('app.encryption.encrypt', return_value="something_encrypted") + + data = { + 'to': 'ok@ok.com', + 'template': str(sample_email_template.id) + } + auth_header = create_authorization_header(service_id=sample_email_template.service_id) + + response = client.post( + path='/notifications/email', + data=json.dumps(data), + headers=[('Content-Type', 'application/json'), auth_header]) + + response_data = json.loads(response.data)['data'] + notification_id = response_data['notification']['id'] + + mocked_email.assert_called_once_with([notification_id], queue='send-email') + mocked_redis.assert_called_once_with(str(sample_email_template.service_id) + "-2016-01-01-count") + assert response.status_code == 201 + assert notification_id + assert response_data['subject'] == 'Email Subject' + assert response_data['body'] == sample_email_template.content + assert response_data['template_version'] == sample_email_template.version + + +@freeze_time("2016-01-01 11:09:00.061258") +def test_should_increment_redis_cache_on_successful_sms( + notify_api, + sample_template, + mocker): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + mocked_sms = mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async') + mocked_redis = mocker.patch('app.notifications.rest.redis_store.inc') + mocker.patch('app.encryption.encrypt', return_value="something_encrypted") + + data = { + 'to': '+447700900855', + 'template': str(sample_template.id) + } + auth_header = create_authorization_header(service_id=sample_template.service_id) + + response = client.post( + path='/notifications/sms', + data=json.dumps(data), + headers=[('Content-Type', 'application/json'), auth_header]) + + response_data = json.loads(response.data)['data'] + notification_id = response_data['notification']['id'] + + mocked_sms.assert_called_once_with([notification_id], queue='send-sms') + mocked_redis.assert_called_once_with(str(sample_template.service_id) + "-2016-01-01-count") + assert response.status_code == 201 + assert notification_id + assert 'subject' not in response_data + assert response_data['body'] == sample_template.content + assert response_data['template_version'] == sample_template.version + + +@pytest.mark.parametrize('template_type', ['sms', 'email']) +def test_should_not_increment_cache_on_failure( + notify_api, + sample_email_template, + sample_template, + fake_uuid, + mocker, + template_type): + with notify_api.test_request_context(), notify_api.test_client() as client: + mocked = mocker.patch( + 'app.celery.provider_tasks.deliver_{}.apply_async'.format(template_type), + side_effect=Exception("failed to talk to SQS") + ) + mocked_redis = mocker.patch('app.notifications.rest.redis_store.inc') + mocker.patch('app.dao.notifications_dao.create_uuid', return_value=fake_uuid) + template = sample_template if template_type == 'sms' else sample_email_template + to = sample_template.service.created_by.mobile_number if template_type == 'sms' \ + else sample_email_template.service.created_by.email_address + data = { + 'to': to, + 'template': template.id + } + api_key = ApiKey( + service=template.service, + name='team_key', + created_by=template.created_by, + key_type=KEY_TYPE_TEAM) + save_model_api_key(api_key) + auth_header = create_jwt_token(secret=api_key.unsigned_secret, client_id=str(api_key.service_id)) + + response = client.post( + path='/notifications/{}'.format(template_type), + data=json.dumps(data), + headers=[('Content-Type', 'application/json'), ('Authorization', 'Bearer {}'.format(auth_header))]) + + mocked.assert_called_once_with([fake_uuid], queue='send-{}'.format(template_type)) + + assert response.status_code == 500 + mocked_redis.assert_not_called() + + @pytest.mark.parametrize('template_type', ['sms', 'email']) def test_create_notification_should_reject_if_missing_required_fields(notify_api,