From 85fd7c3869ee63bd2a7cc6e26f497d930ec85ae9 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Thu, 12 Apr 2018 14:47:56 +0100 Subject: [PATCH] add new tests for template statistics --- app/template_statistics/rest.py | 4 +- app/utils.py | 4 +- tests/app/template_statistics/test_rest.py | 185 +++++++++++++++++++-- 3 files changed, 172 insertions(+), 21 deletions(-) diff --git a/app/template_statistics/rest.py b/app/template_statistics/rest.py index c95db139e..7e9297cff 100644 --- a/app/template_statistics/rest.py +++ b/app/template_statistics/rest.py @@ -67,7 +67,7 @@ def get_template_statistics_for_last_n_days(service_id, limit_days): if not stats: # key didn't exist (or redis was down) - lets populate from DB. stats = { - row.id: row.count for row in dao_get_template_usage(service_id, day=day) + str(row.id): row.count for row in dao_get_template_usage(service_id, day=day) } template_stats_by_id += Counter(stats) @@ -76,7 +76,7 @@ def get_template_statistics_for_last_n_days(service_id, limit_days): template_details = dao_get_multiple_template_details(template_stats_by_id.keys()) return [ { - 'count': template_stats_by_id[template.id], + 'count': template_stats_by_id[str(template.id)], 'template_id': str(template.id), 'template_name': template.name, 'template_type': template.template_type, diff --git a/app/utils.py b/app/utils.py index fe74292ca..5da1e6b27 100644 --- a/app/utils.py +++ b/app/utils.py @@ -104,8 +104,8 @@ def days_ago(number_of_days): def last_n_days(limit_days): """ - Returns the last n dates, oldest first. Takes care of daylight savings (but returns a date, be careful how you manipulate it later! Don't - directly use the date for comparing to UTC datetimes!). Includes today. + Returns the last n dates, oldest first. Takes care of daylight savings (but returns a date, be careful how you + manipulate it later! Don't directly use the date for comparing to UTC datetimes!). Includes today. """ return [ datetime.combine( diff --git a/tests/app/template_statistics/test_rest.py b/tests/app/template_statistics/test_rest.py index c52773889..cfedd8e9e 100644 --- a/tests/app/template_statistics/test_rest.py +++ b/tests/app/template_statistics/test_rest.py @@ -1,10 +1,14 @@ -from datetime import datetime, timedelta import uuid +from datetime import datetime +from unittest.mock import Mock, call, ANY import pytest from freezegun import freeze_time -from tests.app.conftest import sample_notification +from tests.app.db import ( + create_notification, + create_template, +) # get_template_statistics_for_service_by_day @@ -34,24 +38,174 @@ def test_get_template_statistics_for_service_by_day_returns_template_info(admin_ limit_days=1 ) - assert len(json_resp) == 1 + assert len(json_resp['data']) == 1 assert json_resp['data'][0]['count'] == 1 assert json_resp['data'][0]['template_id'] == str(sample_notification.template_id) assert json_resp['data'][0]['template_name'] == 'Template Name' assert json_resp['data'][0]['template_type'] == 'sms' + assert json_resp['data'][0]['is_precompiled_letter'] is False -def test_get_template_statistics_for_service_by_day_gets_out_of_redis_if_available(admin_request, mocker): - assert False +@freeze_time('2018-01-01 12:00:00') +def test_get_template_statistics_for_service_by_day_gets_out_of_redis_if_available( + admin_request, + mocker, + sample_template +): + mock_redis = mocker.patch('app.template_statistics.rest.redis_store') + mock_redis.get_all_from_hash.return_value = { + str(sample_template.id): 3 + } + + json_resp = admin_request.get( + 'template_statistics.get_template_statistics_for_service_by_day', + service_id=sample_template.service_id, + limit_days=1 + ) + + assert len(json_resp['data']) == 1 + assert json_resp['data'][0]['count'] == 3 + assert json_resp['data'][0]['template_id'] == str(sample_template.id) + mock_redis.get_all_from_hash.assert_called_once_with( + "service-{}-template-usage-{}".format(sample_template.service_id, '2018-01-01') + ) -def test_get_template_statistics_for_service_by_day_goes_to_db_if_not_in_redis(admin_request, mocker): - assert False +@freeze_time('2018-01-02 12:00:00') +def test_get_template_statistics_for_service_by_day_goes_to_db_if_not_in_redis( + admin_request, + mocker, + sample_template +): + mock_redis = mocker.patch('app.template_statistics.rest.redis_store') + + # first time it is called redis returns data, second time returns none + mock_redis.get_all_from_hash.side_effect = [ + {str(sample_template.id): 2}, + None + ] + mock_dao = mocker.patch( + 'app.template_statistics.rest.dao_get_template_usage', + return_value=[ + Mock(id=sample_template.id, count=3) + ] + ) + + json_resp = admin_request.get( + 'template_statistics.get_template_statistics_for_service_by_day', + service_id=sample_template.service_id, + limit_days=2 + ) + + assert len(json_resp['data']) == 1 + assert json_resp['data'][0]['count'] == 5 + assert json_resp['data'][0]['template_id'] == str(sample_template.id) + # first redis call + assert mock_redis.mock_calls == [ + call.get_all_from_hash( + "service-{}-template-usage-{}".format(sample_template.service_id, '2018-01-01') + ), + call.get_all_from_hash( + "service-{}-template-usage-{}".format(sample_template.service_id, '2018-01-02') + ) + ] + # dao only called for 2nd, since redis returned values for first call + mock_dao.assert_called_once_with( + str(sample_template.service_id), day=datetime(2018, 1, 2) + ) -def test_get_template_statistics_for_service_by_day_gets_stats_for_correct_days(admin_request, mocker): - assert False +def test_get_template_statistics_for_service_by_day_combines_templates_correctly( + admin_request, + mocker, + sample_service +): + t1 = create_template(sample_service, template_name='1') + t2 = create_template(sample_service, template_name='2') + t3 = create_template(sample_service, template_name='3') # noqa + mock_redis = mocker.patch('app.template_statistics.rest.redis_store') + + # first time it is called redis returns data, second time returns none + mock_redis.get_all_from_hash.side_effect = [ + {str(t1.id): 2}, + None, + {str(t1.id): 1, str(t2.id): 4}, + ] + mock_dao = mocker.patch( + 'app.template_statistics.rest.dao_get_template_usage', + return_value=[ + Mock(id=t1.id, count=8) + ] + ) + + json_resp = admin_request.get( + 'template_statistics.get_template_statistics_for_service_by_day', + service_id=sample_service.id, + limit_days=3 + ) + + assert len(json_resp['data']) == 2 + assert json_resp['data'][0]['template_id'] == str(t1.id) + assert json_resp['data'][0]['count'] == 11 + assert json_resp['data'][1]['template_id'] == str(t2.id) + assert json_resp['data'][1]['count'] == 4 + + assert mock_redis.get_all_from_hash.call_count == 3 + # dao only called for 2nd day + assert mock_dao.call_count == 1 + + +@freeze_time('2018-03-28 00:00:00') +def test_get_template_statistics_for_service_by_day_gets_stats_for_correct_days( + admin_request, + mocker, + sample_template +): + mock_redis = mocker.patch('app.template_statistics.rest.redis_store') + + # first time it is called redis returns data, second time returns none + mock_redis.get_all_from_hash.side_effect = [ + {str(sample_template.id): 1}, + None, + {str(sample_template.id): 1}, + {str(sample_template.id): 1}, + {str(sample_template.id): 1}, + None, + None, + ] + mock_dao = mocker.patch( + 'app.template_statistics.rest.dao_get_template_usage', + return_value=[ + Mock(id=sample_template.id, count=2) + ] + ) + + json_resp = admin_request.get( + 'template_statistics.get_template_statistics_for_service_by_day', + service_id=sample_template.service_id, + limit_days=7 + ) + + assert len(json_resp['data']) == 1 + assert json_resp['data'][0]['count'] == 10 + assert json_resp['data'][0]['template_id'] == str(sample_template.id) + + assert mock_redis.get_all_from_hash.call_count == 7 + + assert '2018-03-22' in mock_redis.get_all_from_hash.mock_calls[0][1][0] + assert '2018-03-23' in mock_redis.get_all_from_hash.mock_calls[1][1][0] + assert '2018-03-24' in mock_redis.get_all_from_hash.mock_calls[2][1][0] + assert '2018-03-25' in mock_redis.get_all_from_hash.mock_calls[3][1][0] + assert '2018-03-26' in mock_redis.get_all_from_hash.mock_calls[4][1][0] + assert '2018-03-27' in mock_redis.get_all_from_hash.mock_calls[5][1][0] + assert '2018-03-28' in mock_redis.get_all_from_hash.mock_calls[6][1][0] + + mock_dao.mock_calls == [ + call(ANY, day=datetime(2018, 3, 23)), + call(ANY, day=datetime(2018, 3, 27)), + call(ANY, day=datetime(2018, 3, 28)) + ] def test_get_template_statistics_for_service_by_day_returns_empty_list_if_no_templates( @@ -62,7 +216,7 @@ def test_get_template_statistics_for_service_by_day_returns_empty_list_if_no_tem json_resp = admin_request.get( 'template_statistics.get_template_statistics_for_service_by_day', service_id=sample_service.id, - limit_days=1 + limit_days=7 ) assert len(json_resp['data']) == 0 @@ -70,13 +224,10 @@ def test_get_template_statistics_for_service_by_day_returns_empty_list_if_no_tem # get_template_statistics_for_template -def test_get_template_statistics_for_template_returns_last_notification( - notify_db, - notify_db_session, - admin_request): - sample_notification(notify_db, notify_db_session) - sample_notification(notify_db, notify_db_session) - notification_3 = sample_notification(notify_db, notify_db_session) +def test_get_template_statistics_for_template_returns_last_notification(admin_request, sample_template): + create_notification(sample_template) + create_notification(sample_template) + notification_3 = create_notification(sample_template) json_resp = admin_request.get( 'template_statistics.get_template_statistics_for_template_id',