diff --git a/app/dao/services_dao.py b/app/dao/services_dao.py index c1d2c4672..031c10939 100644 --- a/app/dao/services_dao.py +++ b/app/dao/services_dao.py @@ -192,7 +192,6 @@ def dao_fetch_todays_stats_for_all_services(): ).select_from( Service ).join( - # don't want to create a relationship in case we accidentally lazily load it, so manually define the join term Notification ).filter( func.date(Notification.created_at) == date.today() diff --git a/app/service/rest.py b/app/service/rest.py index 14ee99616..1ba277957 100644 --- a/app/service/rest.py +++ b/app/service/rest.py @@ -55,7 +55,7 @@ def get_services(): if user_id: services = dao_fetch_all_services_by_user(user_id) elif request.args.get('detailed') == 'True': - return get_detailed_services() + return jsonify(data=get_detailed_services()) else: services = dao_fetch_all_services() data = service_schema.dump(services, many=True).data @@ -65,7 +65,8 @@ def get_services(): @service_blueprint.route('/', methods=['GET']) def get_service_by_id(service_id): if request.args.get('detailed') == 'True': - return get_detailed_service(service_id, today_only=request.args.get('today_only') == 'True') + data = get_detailed_service(service_id, today_only=request.args.get('today_only') == 'True') + return jsonify(data=data) else: fetched = dao_fetch_service_by_id(service_id) @@ -248,8 +249,7 @@ def get_detailed_service(service_id, today_only=False): service.statistics = statistics.format_statistics(stats) - data = detailed_service_schema.dump(service).data - return jsonify(data=data) + return detailed_service_schema.dump(service).data def get_detailed_services(): @@ -259,5 +259,4 @@ def get_detailed_services(): for service_id, rows in itertools.groupby(stats, lambda x: x.service_id): services[service_id].statistics = statistics.format_statistics(rows) - data = detailed_service_schema.dump(services, many=True).data - return jsonify(data=data) + return detailed_service_schema.dump(services.values(), many=True).data diff --git a/requirements_for_test.txt b/requirements_for_test.txt index f5db40330..1ea6f7a8d 100644 --- a/requirements_for_test.txt +++ b/requirements_for_test.txt @@ -6,6 +6,6 @@ pytest-cov==2.2.0 coveralls==1.1 mock==1.0.1 moto==0.4.19 -flex==5.6.0 +flex==5.7.0 freezegun==0.3.6 requests-mock==0.7.0 diff --git a/tests/app/service/test_rest.py b/tests/app/service/test_rest.py index 1d3612b01..4a64e86ac 100644 --- a/tests/app/service/test_rest.py +++ b/tests/app/service/test_rest.py @@ -1,3 +1,4 @@ +from datetime import datetime import json import uuid @@ -15,6 +16,7 @@ from tests.app.conftest import ( sample_user as create_sample_user, sample_notification as create_sample_notification ) +from app.service.rest import get_detailed_services def test_get_service_list(notify_api, service_factory): @@ -263,7 +265,7 @@ def test_should_not_create_service_with_missing_if_user_id_is_not_in_database(no json_resp = json.loads(resp.get_data(as_text=True)) assert resp.status_code == 404 assert json_resp['result'] == 'error' - assert 'No result found' == json_resp['message'] + assert json_resp['message'] == 'No result found' def test_should_not_create_service_if_missing_data(notify_api, sample_user): @@ -288,8 +290,6 @@ def test_should_not_create_service_if_missing_data(notify_api, sample_user): def test_should_not_create_service_with_duplicate_name(notify_api, - notify_db, - notify_db_session, sample_user, sample_service): with notify_api.test_request_context(): @@ -314,8 +314,6 @@ def test_should_not_create_service_with_duplicate_name(notify_api, def test_create_service_should_throw_duplicate_key_constraint_for_existing_email_from(notify_api, - notify_db, - notify_db_session, service_factory, sample_user): first_service = service_factory.get('First service', email_from='first.service') @@ -432,7 +430,7 @@ def test_update_service_research_mode_throws_validation_error(notify_api, sample headers=[('Content-Type', 'application/json'), auth_header] ) result = json.loads(resp.get_data(as_text=True)) - result['message']['research_mode'][0] == "Not a valid boolean." + assert result['message']['research_mode'][0] == "Not a valid boolean." assert resp.status_code == 400 @@ -505,7 +503,7 @@ def test_should_not_update_service_with_duplicate_email_from(notify_api, ) -def test_update_service_should_404_if_id_is_invalid(notify_api, notify_db, notify_db_session): +def test_update_service_should_404_if_id_is_invalid(notify_api): with notify_api.test_request_context(): with notify_api.test_client() as client: data = { @@ -524,7 +522,7 @@ def test_update_service_should_404_if_id_is_invalid(notify_api, notify_db, notif assert resp.status_code == 404 -def test_get_users_by_service(notify_api, notify_db, notify_db_session, sample_service): +def test_get_users_by_service(notify_api, sample_service): with notify_api.test_request_context(): with notify_api.test_client() as client: user_on_service = sample_service.users[0] @@ -544,8 +542,6 @@ def test_get_users_by_service(notify_api, notify_db, notify_db_session, sample_s def test_get_users_for_service_returns_empty_list_if_no_users_associated_with_service(notify_api, - notify_db, - notify_db_session, sample_service): with notify_api.test_request_context(): with notify_api.test_client() as client: @@ -1100,16 +1096,16 @@ def test_set_sms_sender_for_service_rejects_invalid_characters(notify_api, sampl @pytest.mark.parametrize('today_only,stats', [ - ('False', { - 'requested': 2, - 'delivered': 1, - 'failed': 0 - }), - ('True', { - 'requested': 1, - 'delivered': 0, - 'failed': 0 - }) + ('False', { + 'requested': 2, + 'delivered': 1, + 'failed': 0 + }), + ('True', { + 'requested': 1, + 'delivered': 0, + 'failed': 0 + }) ], ids=['seven_days', 'today'] ) def test_get_detailed_service(notify_db, notify_db_session, notify_api, sample_service, today_only, stats): @@ -1156,3 +1152,92 @@ def test_get_weekly_notification_stats(notify_api, notify_db, notify_db_session) } } } + + +def test_get_services_with_detailed_flag(notify_api, notify_db, notify_db_session): + notifications = [ + create_sample_notification(notify_db, notify_db_session), + create_sample_notification(notify_db, notify_db_session) + ] + with notify_api.test_request_context(), notify_api.test_client() as client: + resp = client.get( + '/service?detailed=True', + headers=[create_authorization_header()] + ) + + assert resp.status_code == 200 + data = json.loads(resp.get_data(as_text=True))['data'] + assert len(data) == 1 + assert data[0]['name'] == 'Sample service' + assert data[0]['id'] == str(notifications[0].service_id) + assert data[0]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 0, 'failed': 0, 'requested': 2} + } + + +def test_get_detailed_services_groups_by_service(notify_db, notify_db_session): + service_1 = create_sample_service(notify_db, notify_db_session, service_name="1", email_from='1') + service_2 = create_sample_service(notify_db, notify_db_session, service_name="2", email_from='2') + + create_sample_notification(notify_db, notify_db_session, service=service_1, status='created') + create_sample_notification(notify_db, notify_db_session, service=service_2, status='created') + create_sample_notification(notify_db, notify_db_session, service=service_1, status='delivered') + create_sample_notification(notify_db, notify_db_session, service=service_1, status='created') + + data = get_detailed_services() + data = sorted(data, key=lambda x: x['id']) + + assert len(data) == 2 + assert data[0]['id'] == str(service_1.id) + assert data[0]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 0, 'failed': 0, 'requested': 1} + } + assert data[1]['id'] == str(service_2.id) + assert data[1]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 1, 'failed': 0, 'requested': 2} + } + + +def test_get_detailed_services_groups_by_service(notify_db, notify_db_session): + service_1 = create_sample_service(notify_db, notify_db_session, service_name="1", email_from='1') + service_2 = create_sample_service(notify_db, notify_db_session, service_name="2", email_from='2') + + create_sample_notification(notify_db, notify_db_session, service=service_1, status='created') + create_sample_notification(notify_db, notify_db_session, service=service_2, status='created') + create_sample_notification(notify_db, notify_db_session, service=service_1, status='delivered') + create_sample_notification(notify_db, notify_db_session, service=service_1, status='created') + + data = get_detailed_services() + data = sorted(data, key=lambda x: x['name']) + + assert len(data) == 2 + assert data[0]['id'] == str(service_1.id) + assert data[0]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 1, 'failed': 0, 'requested': 3} + } + assert data[1]['id'] == str(service_2.id) + assert data[1]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 0, 'failed': 0, 'requested': 1} + } + + + +def test_get_detailed_services_only_includes_todays_notifications(notify_db, notify_db_session): + create_sample_notification(notify_db, notify_db_session, created_at=datetime(2015, 10, 9, 23, 59)) + create_sample_notification(notify_db, notify_db_session, created_at=datetime(2015, 10, 10, 0, 0)) + create_sample_notification(notify_db, notify_db_session, created_at=datetime(2015, 10, 10, 12, 0)) + + with freeze_time('2015-10-10T12:00:00'): + data = get_detailed_services() + data = sorted(data, key=lambda x: x['id']) + + assert len(data) == 1 + assert data[0]['statistics'] == { + 'email': {'delivered': 0, 'failed': 0, 'requested': 0}, + 'sms': {'delivered': 0, 'failed': 0, 'requested': 2} + }