def test_fetch_stats_counts_should_ignore_team_key(notify_db_session): service = create_service() template = create_template(service=service) live_api_key = create_api_key(service=service, key_type=KEY_TYPE_NORMAL) team_api_key = create_api_key(service=service, key_type=KEY_TYPE_TEAM) test_api_key = create_api_key(service=service, key_type=KEY_TYPE_TEST) # two created email, one failed email, and one created sms create_notification(template=template, api_key=live_api_key, key_type=live_api_key.key_type) create_notification(template=template, api_key=test_api_key, key_type=test_api_key.key_type) create_notification(template=template, api_key=team_api_key, key_type=team_api_key.key_type) create_notification(template=template) stats = dao_fetch_stats_for_service(template.service_id, 7) assert len(stats) == 1 assert stats[0].notification_type == 'sms' assert stats[0].status == 'created' assert stats[0].count == 3
def test_dao_suspend_service_marks_service_as_inactive_and_expires_api_keys(notify_db_session): service = create_service() api_key = create_api_key(service=service) dao_suspend_service(service.id) service = Service.query.get(service.id) assert not service.active assert service.name == service.name api_key = ApiKey.query.get(api_key.id) assert api_key.expiry_date == datetime(2001, 1, 1, 23, 59, 00)
def test_get_api_key_ranked_by_notifications_created(notify_db_session): service = create_service(service_name='Service 1') api_key_1 = create_api_key(service, key_type=KEY_TYPE_NORMAL, key_name="Key 1") api_key_2 = create_api_key(service, key_type=KEY_TYPE_NORMAL, key_name="Key 2") template_email = create_template(service=service, template_type='email') template_sms = create_template(service=service, template_type='sms') email_sends = 1 sms_sends = 10 for x in range(email_sends): create_notification(template=template_email, api_key=api_key_1) for x in range(sms_sends): create_notification(template=template_sms, api_key=api_key_1) create_notification(template=template_sms, api_key=api_key_2) api_keys_ranked = get_api_key_ranked_by_notifications_created(2) assert len(api_keys_ranked) == 2 first_place = api_keys_ranked[0] second_place = api_keys_ranked[1] # check there are 9 fields/columns returned assert len(first_place) == 9 assert len(second_place) == 9 assert first_place[0] == api_key_1.name assert first_place[2] == service.name assert int(first_place[6]) == email_sends assert int(first_place[7]) == sms_sends assert int(first_place[8]) == sms_sends + email_sends assert second_place[0] == api_key_2.name assert second_place[2] == service.name assert int(second_place[6]) == 0 assert int(second_place[7]) == sms_sends assert int(second_place[8]) == sms_sends
def test_get_api_key_stats_no_sends(admin_request, notify_db, notify_db_session): service = create_service(service_name="Service 2") api_key = create_api_key(service) api_key_stats = admin_request.get("api_key.get_api_key_stats", api_key_id=api_key.id)["data"] assert api_key_stats["api_key_id"] == str(api_key.id) assert api_key_stats["email_sends"] == 0 assert api_key_stats["sms_sends"] == 0 assert api_key_stats["total_sends"] == 0 assert api_key_stats["last_send"] is None
def test_that_when_not_exceeded_rate_limit_request_succeeds( sample_service, mocker): with freeze_time("2016-01-01 12:00:00.000000"): mocker.patch('app.redis_store.exceeded_rate_limit', return_value=False) mocker.patch('app.notifications.validators.services_dao') sample_service.restricted = True api_key = create_api_key(sample_service) check_service_over_api_rate_limit(sample_service, api_key) assert app.redis_store.exceeded_rate_limit.called_with( "{}-{}".format(str(sample_service.id), api_key.key_type), 3000, 60)
def test_should_not_rate_limit_if_limiting_is_disabled(sample_service, mocker): with freeze_time("2016-01-01 12:00:00.000000"): current_app.config['API_RATE_LIMIT_ENABLED'] = False mocker.patch('app.redis_store.exceeded_rate_limit', return_value=False) mocker.patch('app.notifications.validators.services_dao') sample_service.restricted = True api_key = create_api_key(sample_service) check_service_over_api_rate_limit(sample_service, api_key) assert not app.redis_store.exceeded_rate_limit.called
def test_dao_resume_service_marks_service_as_active_and_api_keys_are_still_revoked(notify_db_session): service = create_service() api_key = create_api_key(service=service) dao_suspend_service(service.id) service = Service.query.get(service.id) assert not service.active dao_resume_service(service.id) assert Service.query.get(service.id).active api_key = ApiKey.query.get(api_key.id) assert api_key.expiry_date == datetime(2001, 1, 1, 23, 59, 00)
def test_post_sms_notification_returns_400_if_number_not_in_guest_list( notify_db_session, client, restricted ): service = create_service(restricted=restricted, service_permissions=[SMS_TYPE, INTERNATIONAL_SMS_TYPE]) template = create_template(service=service) create_api_key(service=service, key_type='team') data = { "phone_number": '+327700900855', "template_id": template.id, } auth_header = create_authorization_header(service_id=service.id, key_type='team') response = client.post( path='/v2/notifications/sms', data=json.dumps(data), headers=[('Content-Type', 'application/json'), auth_header]) assert response.status_code == 400 error_json = json.loads(response.get_data(as_text=True)) assert error_json['status_code'] == 400 assert error_json['errors'] == [ {"error": "BadRequestError", "message": 'Can’t send to this recipient using a team-only API key'} ]
def archived_service_with_deleted_stuff(client, sample_service): with freeze_time('2001-01-01'): template = create_template(sample_service, template_name='a') api_key = create_api_key(sample_service) expire_api_key(sample_service.id, api_key.id) template.archived = True dao_update_template(template) with freeze_time('2002-02-02'): auth_header = create_authorization_header() response = client.post('/service/{}/archive'.format(sample_service.id), headers=[auth_header]) assert response.status_code == 204 assert response.data == b'' return sample_service
def test_get_last_send_for_api_key(notify_db_session): service = create_service(service_name='First Service') api_key = create_api_key(service) template_email = create_template(service=service, template_type=EMAIL_TYPE) total_sends = 10 last_send = get_last_send_for_api_key(str(api_key.id)) assert last_send == [] for x in range(total_sends): create_notification(template=template_email, api_key=api_key) # the following lines test that a send has occurred within the last second last_send = get_last_send_for_api_key(str(api_key.id))[0][0] now = datetime.utcnow() time_delta = now - last_send assert abs(time_delta.total_seconds()) < 1
def sample_notification(notify_db_session): created_at = datetime.utcnow() service = create_service(check_if_service_exists=True) template = create_template(service=service) api_key = ApiKey.query.filter(ApiKey.service == template.service, ApiKey.key_type == KEY_TYPE_NORMAL).first() if not api_key: api_key = create_api_key(template.service, key_type=KEY_TYPE_NORMAL) notification_id = uuid.uuid4() to = '+447700900855' data = { 'id': notification_id, 'to': to, 'job_id': None, 'job': None, 'service_id': service.id, 'service': service, 'template_id': template.id, 'template_version': template.version, 'status': 'created', 'reference': None, 'created_at': created_at, 'sent_at': None, 'billable_units': 1, 'personalisation': None, 'notification_type': template.template_type, 'api_key': api_key, 'api_key_id': api_key and api_key.id, 'key_type': api_key.key_type, 'sent_by': None, 'updated_at': None, 'client_reference': None, 'rate_multiplier': 1.0, 'normalised_to': None, 'postage': None, } notification = Notification(**data) dao_create_notification(notification) return notification
def test_should_send_notification_to_whitelist_recipient( client, sample_service, notification_type, to, key_type, service_restricted, mocker ): sample_service.message_limit = 2 sample_service.restricted = service_restricted apply_async = mocker.patch('app.celery.provider_tasks.deliver_{}.apply_async'.format(notification_type)) template = create_template(sample_service, template_type=notification_type) if notification_type == SMS_TYPE: service_whitelist = create_service_whitelist(sample_service, mobile_number=to) elif notification_type == EMAIL_TYPE: service_whitelist = create_service_whitelist(sample_service, email_address=to) assert service_whitelist.service_id == sample_service.id assert to in [member.recipient for member in sample_service.whitelist] create_notification(template=template) data = { 'to': to, 'template': str(template.id) } sample_key = create_api_key(sample_service, key_type=key_type) auth_header = create_jwt_token(secret=sample_key.secret, client_id=str(sample_key.service_id)) response = client.post( path='/notifications/{}'.format(notification_type), data=json.dumps(data), headers=[('Content-Type', 'application/json'), ('Authorization', 'Bearer {}'.format(auth_header))]) json_resp = json.loads(response.get_data(as_text=True)) assert response.status_code == 201 assert json_resp['data']['notification']['id'] assert json_resp['data']['body'] == template.content assert json_resp['data']['template_version'] == template.version assert apply_async.called
def test_should_not_send_notification_to_non_whitelist_recipient_in_trial_mode( client, sample_service_whitelist, notification_type, to, key_type, mocker ): service = sample_service_whitelist.service service.restricted = True service.message_limit = 2 apply_async = mocker.patch('app.celery.provider_tasks.deliver_{}.apply_async'.format(notification_type)) template = create_template(service, template_type=notification_type) assert sample_service_whitelist.service_id == service.id assert to not in [member.recipient for member in service.whitelist] create_notification(template=template) data = { 'to': to, 'template': str(template.id) } api_key = create_api_key(service, key_type=key_type) auth_header = create_jwt_token(secret=api_key.secret, client_id=str(api_key.service_id)) response = client.post( path='/notifications/{}'.format(notification_type), data=json.dumps(data), headers=[('Content-Type', 'application/json'), ('Authorization', 'Bearer {}'.format(auth_header))]) expected_response_message = ( 'Can’t send to this recipient when service is in trial mode ' '– see https://www.notifications.service.gov.uk/trial-mode' ) if key_type == KEY_TYPE_NORMAL else ('Can’t send to this recipient using a team-only API key') json_resp = json.loads(response.get_data(as_text=True)) assert response.status_code == 400 assert json_resp['result'] == 'error' assert expected_response_message in json_resp['message']['to'] apply_async.assert_not_called()
def test_persist_notification_doesnt_touch_cache_for_old_keys_that_dont_exist(notify_db_session, mocker): service = create_service(restricted=True) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=None) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value=None) persist_notification( template_id=template.id, template_version=template.version, recipient='+447111111111', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref" ) mock_incr.assert_not_called()
def test_get_total_notifications_sent_for_api_key(notify_db_session): service = create_service(service_name='First Service') api_key = create_api_key(service) template_email = create_template(service=service, template_type=EMAIL_TYPE) template_sms = create_template(service=service, template_type=SMS_TYPE) total_sends = 10 api_key_stats_1 = get_total_notifications_sent_for_api_key(str(api_key.id)) assert api_key_stats_1 == [] for x in range(total_sends): create_notification(template=template_email, api_key=api_key) api_key_stats_2 = get_total_notifications_sent_for_api_key(str(api_key.id)) assert api_key_stats_2 == [(EMAIL_TYPE, total_sends), ] for x in range(total_sends): create_notification(template=template_sms, api_key=api_key) api_key_stats_3 = get_total_notifications_sent_for_api_key(str(api_key.id)) assert set(api_key_stats_3) == set([(EMAIL_TYPE, total_sends), (SMS_TYPE, total_sends)])
def sample_notification_history( notify_db, notify_db_session, sample_template, status="created", created_at=None, notification_type=None, key_type=KEY_TYPE_NORMAL, sent_at=None, api_key=None, ): if created_at is None: created_at = datetime.utcnow() if sent_at is None: sent_at = datetime.utcnow() if notification_type is None: notification_type = sample_template.template_type if not api_key: api_key = create_api_key(sample_template.service, key_type=key_type) notification_history = NotificationHistory( id=uuid.uuid4(), service=sample_template.service, template_id=sample_template.id, template_version=sample_template.version, status=status, created_at=created_at, notification_type=notification_type, key_type=key_type, api_key=api_key, api_key_id=api_key and api_key.id, sent_at=sent_at, ) notify_db.session.add(notification_history) notify_db.session.commit() return notification_history
def sample_notification_history(notify_db, notify_db_session, sample_template): created_at = datetime.utcnow() sent_at = datetime.utcnow() notification_type = sample_template.template_type api_key = create_api_key(sample_template.service, key_type=KEY_TYPE_NORMAL) notification_history = NotificationHistory( id=uuid.uuid4(), service=sample_template.service, template_id=sample_template.id, template_version=sample_template.version, status='created', created_at=created_at, notification_type=notification_type, key_type=KEY_TYPE_NORMAL, api_key=api_key, api_key_id=api_key and api_key.id, sent_at=sent_at) notify_db.session.add(notification_history) notify_db.session.commit() return notification_history
def test_get_api_key_stats_with_sends(admin_request, notify_db, notify_db_session): service = create_service(service_name="Service 1") api_key = create_api_key(service) template = create_template(service=service, template_type="email") total_sends = 10 for x in range(total_sends): create_notification(template=template, api_key=api_key) api_key_stats = admin_request.get("api_key.get_api_key_stats", api_key_id=api_key.id)["data"] assert api_key_stats["api_key_id"] == str(api_key.id) assert api_key_stats["email_sends"] == total_sends assert api_key_stats["sms_sends"] == 0 assert api_key_stats["total_sends"] == total_sends # the following lines test that a send has occurred within the last second last_send_dt = datetime.strptime(api_key_stats["last_send"], DATETIME_FORMAT) now = datetime.utcnow() time_delta = now - last_send_dt assert abs(time_delta.total_seconds()) < 1
def test_persist_notification_does_not_increments_cache_live_service( notify_db_session, mocker ): service = create_service(restricted=False) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value={template.id, 1}) persist_notification( template_id=template.id, template_version=template.version, recipient='+447111111122', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref2") assert not mock_incr.called
def test_persist_notification_increments_cache_if_key_exists_and_for_trial_service( notify_db_session, mocker ): service = create_service(restricted=True) template = create_template(service=service) api_key = create_api_key(service=service) mock_incr = mocker.patch('app.notifications.process_notifications.redis_store.incr') mocker.patch('app.notifications.process_notifications.redis_store.get', return_value=1) mocker.patch('app.notifications.process_notifications.redis_store.get_all_from_hash', return_value={template.id, 1}) persist_notification( template_id=template.id, template_version=template.version, recipient='+447111111122', service=template.service, personalisation={}, notification_type='sms', api_key_id=api_key.id, key_type=api_key.key_type, reference="ref2") mock_incr.assert_called_once_with(str(service.id) + "-2016-01-01-count", )
def sample_team_api_key(sample_api_key): service = create_service(check_if_service_exists=True) return create_api_key(service, key_type=KEY_TYPE_TEAM)
def sample_notification( notify_db, notify_db_session, service=None, template=None, job=None, job_row_number=None, to_field=None, status="created", provider_response=None, reference=None, created_at=None, sent_at=None, billable_units=1, personalisation=None, api_key=None, key_type=KEY_TYPE_NORMAL, sent_by=None, international=False, client_reference=None, rate_multiplier=1.0, scheduled_for=None, normalised_to=None, postage=None, ): if created_at is None: created_at = datetime.utcnow() if service is None: service = create_service(check_if_service_exists=True) if template is None: template = create_template(service=service) if job is None and api_key is None: # we didn't specify in test - lets create it api_key = ApiKey.query.filter(ApiKey.service == template.service, ApiKey.key_type == key_type).first() if not api_key: api_key = create_api_key(template.service, key_type=key_type) notification_id = uuid.uuid4() if to_field: to = to_field else: to = "+16502532222" data = { "id": notification_id, "to": to, "job_id": job.id if job else None, "job": job, "service_id": service.id, "service": service, "template_id": template.id, "template_version": template.version, "status": status, "provider_response": provider_response, "reference": reference, "created_at": created_at, "sent_at": sent_at, "billable_units": billable_units, "personalisation": personalisation, "notification_type": template.template_type, "api_key": api_key, "api_key_id": api_key and api_key.id, "key_type": api_key.key_type if api_key else key_type, "sent_by": sent_by, "updated_at": created_at if status in NOTIFICATION_STATUS_TYPES_COMPLETED else None, "client_reference": client_reference, "rate_multiplier": rate_multiplier, "normalised_to": normalised_to, "postage": postage, } if job_row_number is not None: data["job_row_number"] = job_row_number notification = Notification(**data) dao_create_notification(notification) if scheduled_for: scheduled_notification = ScheduledNotification( id=uuid.uuid4(), notification_id=notification.id, scheduled_for=datetime.strptime(scheduled_for, "%Y-%m-%d %H:%M"), ) if status != "created": scheduled_notification.pending = False db.session.add(scheduled_notification) db.session.commit() return notification
def sample_notification( notify_db, notify_db_session, service=None, template=None, job=None, job_row_number=None, to_field=None, status='created', reference=None, created_at=None, sent_at=None, billable_units=1, personalisation=None, api_key=None, key_type=KEY_TYPE_NORMAL, sent_by=None, international=False, client_reference=None, rate_multiplier=1.0, scheduled_for=None, normalised_to=None, postage=None, ): if created_at is None: created_at = datetime.utcnow() if service is None: service = create_service(check_if_service_exists=True) if template is None: template = create_template(service=service) if job is None and api_key is None: # we didn't specify in test - lets create it api_key = ApiKey.query.filter(ApiKey.service == template.service, ApiKey.key_type == key_type).first() if not api_key: api_key = create_api_key(template.service, key_type=key_type) notification_id = uuid.uuid4() if to_field: to = to_field else: to = '+16502532222' data = { 'id': notification_id, 'to': to, 'job_id': job.id if job else None, 'job': job, 'service_id': service.id, 'service': service, 'template_id': template.id, 'template_version': template.version, 'status': status, 'reference': reference, 'created_at': created_at, 'sent_at': sent_at, 'billable_units': billable_units, 'personalisation': personalisation, 'notification_type': template.template_type, 'api_key': api_key, 'api_key_id': api_key and api_key.id, 'key_type': api_key.key_type if api_key else key_type, 'sent_by': sent_by, 'updated_at': created_at if status in NOTIFICATION_STATUS_TYPES_COMPLETED else None, 'client_reference': client_reference, 'rate_multiplier': rate_multiplier, 'normalised_to': normalised_to, 'postage': postage, } if job_row_number is not None: data['job_row_number'] = job_row_number notification = Notification(**data) dao_create_notification(notification) if scheduled_for: scheduled_notification = ScheduledNotification( id=uuid.uuid4(), notification_id=notification.id, scheduled_for=datetime.strptime(scheduled_for, "%Y-%m-%d %H:%M")) if status != 'created': scheduled_notification.pending = False db.session.add(scheduled_notification) db.session.commit() return notification