def test_create_nightly_billing_update_when_record_exists( notify_db, notify_db_session, sample_service, sample_template, mocker): mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=datetime.now() - timedelta(days=1), service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by(FactBilling.aet_date).all() assert len(records) == 1 assert records[0].aet_date == date(2018, 1, 14) # run again, make sure create_nightly_billing updates with no error create_nightly_billing() assert len(records) == 1
def test_create_nightly_billing_letter(notify_db, notify_db_session, sample_service, sample_letter_template, mocker): yesterday = datetime.now() - timedelta(days=1) mocker.patch('app.dao.fact_billing_dao.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_letter_template, status='delivered', sent_by='dvla', international=False, rate_multiplier=2.0, billable_units=2, ) records = FactBilling.query.all() assert len(records) == 0 # Celery expects the arguments to be a string or primitive type. yesterday_str = datetime.strftime(yesterday, "%Y-%m-%d") create_nightly_billing(yesterday_str) records = FactBilling.query.order_by('rate_multiplier').all() assert len(records) == 1 record = records[0] assert record.notification_type == LETTER_TYPE assert record.bst_date == datetime.date(yesterday) assert record.rate == Decimal(2.1) assert record.billable_units == 2 assert record.rate_multiplier == 2.0
def test_create_nightly_billing_letter( notify_db, notify_db_session, sample_service, sample_letter_template, mocker): yesterday = datetime.utcnow() - timedelta(days=1) mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_letter_template, status='delivered', sent_by='dvla', international=False, rate_multiplier=2.0, billable_units=2, ) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by('rate_multiplier').all() assert len(records) == 1 record = records[0] assert record.notification_type == LETTER_TYPE assert record.aet_date == datetime.date(convert_utc_to_aet(yesterday)) assert record.rate == Decimal(2.1) assert record.billable_units == 2 assert record.rate_multiplier == 2.0
def test_create_nightly_billing_null_sent_by_sms(notify_db, notify_db_session, sample_service, sample_template, mocker): yesterday = datetime.utcnow() - timedelta(days=1) mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.all() assert len(records) == 1 record = records[0] assert record.aet_date == datetime.date(convert_utc_to_aet(yesterday)) assert record.rate == Decimal(1.33) assert record.billable_units == 1 assert record.rate_multiplier == 1 assert record.provider == 'unknown'
def test_template_usage_should_ignore_test_keys( notify_db, notify_db_session, sample_team_api_key, sample_test_api_key ): sms = sample_template(notify_db, notify_db_session) one_minute_ago = datetime.utcnow() - timedelta(minutes=1) two_minutes_ago = datetime.utcnow() - timedelta(minutes=2) team_key = sample_notification( notify_db, notify_db_session, created_at=two_minutes_ago, template=sms, api_key_id=sample_team_api_key.id, key_type=KEY_TYPE_TEAM) sample_notification( notify_db, notify_db_session, created_at=one_minute_ago, template=sms, api_key_id=sample_test_api_key.id, key_type=KEY_TYPE_TEST) results = dao_get_last_template_usage(sms.id) assert results.id == team_key.id
def test_create_nightly_billing_consolidate_from_3_days_delta( notify_db, notify_db_session, sample_service, sample_template, mocker): mocker.patch('app.dao.fact_billing_dao.get_rate', side_effect=mocker_get_rate) # create records from 11th to 15th for i in range(0, 11): sample_notification( notify_db, notify_db_session, created_at=datetime.now() - timedelta(days=i), service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) notification = Notification.query.order_by(Notification.created_at).all() assert datetime.date(notification[0].created_at) == date(2018, 1, 5) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by(FactBilling.bst_date).all() assert len(records) == 10 assert records[0].bst_date == date(2018, 1, 5) assert records[-1].bst_date == date(2018, 1, 14)
def test_update_status_of_notifications_after_timeout(notify_api, notify_db, notify_db_session, sample_service, sample_template, mmg_provider): with notify_api.test_request_context(): not1 = sample_notification( notify_db, notify_db_session, service=sample_service, template=sample_template, status='sending', created_at=datetime.utcnow() - timedelta( seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) not2 = sample_notification( notify_db, notify_db_session, service=sample_service, template=sample_template, status='created', created_at=datetime.utcnow() - timedelta( seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) not3 = sample_notification( notify_db, notify_db_session, service=sample_service, template=sample_template, status='pending', created_at=datetime.utcnow() - timedelta( seconds=current_app.config.get('SENDING_NOTIFICATIONS_TIMEOUT_PERIOD') + 10)) timeout_notifications() assert not1.status == 'temporary-failure' assert not2.status == 'technical-failure' assert not3.status == 'temporary-failure'
def test_should_not_delete_failed_notifications_before_seven_days(notify_db, notify_db_session): should_delete = datetime.utcnow() - timedelta(days=8) do_not_delete = datetime.utcnow() - timedelta(days=7) sample_notification(notify_db, notify_db_session, created_at=should_delete, status="failed", to_field="should_delete") sample_notification(notify_db, notify_db_session, created_at=do_not_delete, status="failed", to_field="do_not_delete") assert len(Notification.query.all()) == 2 delete_notifications_created_more_than_a_week_ago('failed') assert len(Notification.query.all()) == 1 assert Notification.query.first().to == 'do_not_delete'
def test_create_nightly_billing_sms_rate_multiplier( notify_db, notify_db_session, sample_service, sample_template, mocker, second_rate, records_num, billable_units, multiplier): yesterday = datetime.utcnow() - timedelta(days=1) mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) # These are sms notifications sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by='mmg', international=False, rate_multiplier=1.0, billable_units=1, ) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by='mmg', international=False, rate_multiplier=second_rate, billable_units=1, ) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by('rate_multiplier').all() assert len(records) == records_num for i, record in enumerate(records): assert record.aet_date == datetime.date(convert_utc_to_aet(yesterday)) assert record.rate == Decimal(1.33) assert record.billable_units == billable_units assert record.rate_multiplier == multiplier[i]
def test_get_all_notifications_for_job(notify_db, notify_db_session, sample_job): for i in range(0, 5): try: sample_notification(notify_db, notify_db_session, service=sample_job.service, template=sample_job.template, job=sample_job) except IntegrityError: pass notifications_from_db = get_notifications_for_job(sample_job.service.id, sample_job.id).items assert len(notifications_from_db) == 5
def test_create_nightly_billing_use_aet( notify_db, notify_db_session, sample_service, sample_template, mocker): mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=datetime(2018, 10, 6, 14, 30), # 07/10/2018 00:30:00 AEDT service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) sample_notification( notify_db, notify_db_session, created_at=datetime(2018, 10, 7, 13, 30), # 08/10/2018 00:30:00 AEDT service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) notifications = Notification.query.order_by(Notification.created_at).all() assert len(notifications) == 2 records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by(FactBilling.aet_date).all() assert len(records) == 2 # The first record's aet_date is 06/10/2018. This is because the current # time is 2018-10-09T13:30:00 UTC, and 3 days earlier than that is # 2018-10-06T13:30:00 UTC which is 06/10/2018 23:30:00 AEST. This falls # outside of daylight savings time and so the aet_date is the 6th, not the # 7th. assert records[0].aet_date == date(2018, 10, 6) assert records[-1].aet_date == date(2018, 10, 8)
def test_get_notifications_with_a_team_api_key_type( notify_db, notify_db_session, sample_service, sample_job, sample_api_key, sample_team_api_key, sample_test_api_key ): sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), job=sample_job ) sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), api_key_id=sample_api_key.id, key_type=sample_api_key.key_type ) sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), api_key_id=sample_team_api_key.id, key_type=sample_team_api_key.key_type ) sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), api_key_id=sample_test_api_key.id, key_type=sample_test_api_key.key_type ) # only those created with team API key, no jobs all_notifications = get_notifications_for_service(sample_service.id, limit_days=1, key_type=KEY_TYPE_TEAM).items assert len(all_notifications) == 1 # only those created with team API key, no jobs, even when requested all_notifications = get_notifications_for_service(sample_service.id, limit_days=1, include_jobs=True, key_type=KEY_TYPE_TEAM).items assert len(all_notifications) == 1
def test_get_template_statistics_for_service(notify_db, notify_db_session, notify_api, sample_service): sms = sample_template(notify_db, notify_db_session, service=sample_service) email = sample_email_template(notify_db, notify_db_session, service=sample_service) today = datetime.now() sample_notification(notify_db, notify_db_session, created_at=today, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, created_at=today, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, created_at=today, service=sample_service, template=email) sample_notification(notify_db, notify_db_session, created_at=today, service=sample_service, template=email) with notify_api.test_request_context(): with notify_api.test_client() as client: auth_header = create_authorization_header() response = client.get( '/service/{}/template-statistics'.format(sample_service.id), headers=[('Content-Type', 'application/json'), auth_header] ) assert response.status_code == 200 json_resp = json.loads(response.get_data(as_text=True)) assert len(json_resp['data']) == 2 assert json_resp['data'][0]['count'] == 2 assert json_resp['data'][0]['template_id'] == str(email.id) assert json_resp['data'][0]['template_name'] == email.name assert json_resp['data'][0]['template_type'] == email.template_type assert json_resp['data'][1]['count'] == 2 assert json_resp['data'][1]['template_id'] == str(sms.id) assert json_resp['data'][1]['template_name'] == sms.name assert json_resp['data'][1]['template_type'] == sms.template_type
def test_create_nightly_billing_different_sent_by(notify_db, notify_db_session, sample_service, sample_template, sample_email_template, mocker): yesterday = datetime.now() - timedelta(days=1) mocker.patch('app.dao.fact_billing_dao.get_rate', side_effect=mocker_get_rate) # These are sms notifications sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by='mmg', international=False, rate_multiplier=1.0, billable_units=1, ) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by='firetext', international=False, rate_multiplier=1.0, billable_units=1, ) records = FactBilling.query.all() assert len(records) == 0 # Celery expects the arguments to be a string or primitive type. yesterday_str = datetime.strftime(yesterday, "%Y-%m-%d") create_nightly_billing(yesterday_str) records = FactBilling.query.order_by('rate_multiplier').all() assert len(records) == 2 for i, record in enumerate(records): assert record.bst_date == datetime.date(yesterday) assert record.rate == Decimal(1.33) assert record.billable_units == 1 assert record.rate_multiplier == 1.0
def test_create_nightly_billing_different_templates( notify_db, notify_db_session, sample_service, sample_template, sample_email_template, mocker): yesterday = datetime.utcnow() - timedelta(days=1) mocker.patch('app.celery.reporting_tasks.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by='twilio', international=False, rate_multiplier=1.0, billable_units=1, ) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_email_template, status='delivered', sent_by='ses', international=False, rate_multiplier=0, billable_units=0, ) records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by('rate_multiplier').all() assert len(records) == 2 multiplier = [0, 1] billable_units = [0, 1] rate = [0, Decimal(1.33)] for i, record in enumerate(records): assert record.aet_date == datetime.date(convert_utc_to_aet(yesterday)) assert record.rate == rate[i] assert record.billable_units == billable_units[i] assert record.rate_multiplier == multiplier[i]
def test_should_send_personalised_template_to_correct_email_provider_and_persist( notify_db, notify_db_session, sample_email_template_with_placeholders, mocker ): db_notification = sample_notification( notify_db=notify_db, notify_db_session=notify_db_session, template=sample_email_template_with_placeholders, to_field="*****@*****.**", personalisation={'name': 'Jo'} ) mocker.patch('app.aws_ses_client.send_email', return_value='reference') mocker.patch('app.aws_ses_client.get_name', return_value="ses") send_to_providers.send_email_to_provider( db_notification ) app.aws_ses_client.send_email.assert_called_once_with( '"Sample service" <*****@*****.**>', '*****@*****.**', 'Jo', body='Hello Jo\nThis is an email from GOV.\u200bUK', html_body=ANY, reply_to_address=None ) assert '<!DOCTYPE html' in app.aws_ses_client.send_email.call_args[1]['html_body'] notification = Notification.query.filter_by(id=db_notification.id).one() assert notification.status == 'sending' assert notification.sent_at <= datetime.utcnow() assert notification.sent_by == 'ses' assert notification.personalisation == {"name": "Jo"}
def test_should_not_process_email_job_if_would_exceed_send_limits_inc_today(notify_db, notify_db_session, mocker): service = sample_service(notify_db, notify_db_session, limit=1) template = sample_email_template(notify_db, notify_db_session, service=service) job = sample_job(notify_db, notify_db_session, service=service, template=template) sample_notification(notify_db, notify_db_session, service=service, job=job) mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('email')) mocker.patch('app.celery.tasks.send_email.apply_async') process_job(job.id) job = jobs_dao.dao_get_job_by_id(job.id) assert job.job_status == 'sending limits exceeded' assert s3.get_job_from_s3.called is False assert tasks.send_email.apply_async.called is False
def test_should_send_sms_sender_from_service_if_present( notify_db, notify_db_session, sample_service, sample_template, mocker): db_notification = sample_notification(notify_db, notify_db_session, template=sample_template, to_field="+447234123123", status='created') sample_service.sms_sender = 'elevenchars' notify_db.session.add(sample_service) notify_db.session.commit() mocker.patch('app.mmg_client.send_sms') mocker.patch('app.mmg_client.get_name', return_value="mmg") send_to_providers.send_sms_to_provider( db_notification ) mmg_client.send_sms.assert_called_once_with( to=format_phone_number(validate_phone_number("+447234123123")), content="This is a template:\nwith a newline", reference=str(db_notification.id), sender=sample_service.sms_sender )
def test_should_send_personalised_template_to_correct_sms_provider_and_persist( notify_db, notify_db_session, sample_template_with_placeholders, mocker ): db_notification = sample_notification(notify_db, notify_db_session, template=sample_template_with_placeholders, to_field="+447234123123", personalisation={"name": "Jo"}, status='created') mocker.patch('app.mmg_client.send_sms') mocker.patch('app.mmg_client.get_name', return_value="mmg") send_to_providers.send_sms_to_provider( db_notification ) mmg_client.send_sms.assert_called_once_with( to=format_phone_number(validate_phone_number("+447234123123")), content="Sample service: Hello Jo\nYour thing is due soon", reference=str(db_notification.id), sender=None ) notification = Notification.query.filter_by(id=db_notification.id).one() assert notification.status == 'sending' assert notification.sent_at <= datetime.utcnow() assert notification.sent_by == 'mmg' assert notification.billable_units == 1 assert notification.personalisation == {"name": "Jo"}
def test_should_not_update_status_by_reference_if_not_sending_and_does_not_update_job(notify_db, notify_db_session): job = sample_job(notify_db, notify_db_session) notification = sample_notification(notify_db, notify_db_session, status='delivered', reference='reference', job=job) assert Notification.query.get(notification.id).status == 'delivered' assert not update_notification_status_by_reference('reference', 'failed') assert Notification.query.get(notification.id).status == 'delivered' assert job == Job.query.get(notification.job_id)
def test_dao_timeout_notifications_only_updates_for_older_notifications(notify_db, notify_db_session): with freeze_time(datetime.utcnow() + timedelta(minutes=10)): created = sample_notification(notify_db, notify_db_session, status='created') sending = sample_notification(notify_db, notify_db_session, status='sending') pending = sample_notification(notify_db, notify_db_session, status='pending') delivered = sample_notification(notify_db, notify_db_session, status='delivered') assert Notification.query.get(created.id).status == 'created' assert Notification.query.get(sending.id).status == 'sending' assert Notification.query.get(pending.id).status == 'pending' assert Notification.query.get(delivered.id).status == 'delivered' updated = dao_timeout_notifications(1) assert NotificationHistory.query.get(created.id).status == 'created' assert NotificationHistory.query.get(sending.id).status == 'sending' assert NotificationHistory.query.get(pending.id).status == 'pending' assert NotificationHistory.query.get(delivered.id).status == 'delivered' assert updated == 0
def test_should_return_notifications_excluding_jobs_by_default(notify_db, notify_db_session, sample_service): assert len(Notification.query.all()) == 0 job = sample_job(notify_db, notify_db_session) with_job = sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), status="delivered", job=job ) without_job = sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), status="delivered" ) all_notifications = Notification.query.all() assert len(all_notifications) == 2 all_notifications = get_notifications_for_service(sample_service.id).items assert len(all_notifications) == 1 assert all_notifications[0].id == without_job.id
def test_get_template_statistics_by_id_returns_last_notification( notify_db, notify_db_session, client): sample_notification(notify_db, notify_db_session) sample_notification(notify_db, notify_db_session) notification_3 = sample_notification(notify_db, notify_db_session) auth_header = create_authorization_header() response = client.get( '/service/{}/template-statistics/{}'.format( notification_3.service_id, notification_3.template_id), headers=[('Content-Type', 'application/json'), auth_header], ) assert response.status_code == 200 json_resp = json.loads(response.get_data(as_text=True))['data'] assert json_resp['id'] == str(notification_3.id)
def test_should_by_able_to_get_template_count_from_notifications_history(notify_db, notify_db_session, sample_service): sms = sample_template(notify_db, notify_db_session) email = sample_email_template(notify_db, notify_db_session) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, service=sample_service, template=email) sample_notification(notify_db, notify_db_session, service=sample_service, template=email) results = dao_get_template_usage(sample_service.id) assert results[0].name == 'Email Template Name' assert results[0].template_type == 'email' assert results[0].count == 2 assert results[1].name == 'Template Name' assert results[1].template_type == 'sms' assert results[1].count == 3
def test_should_limit_notifications_return_by_day_limit_plus_one(notify_db, notify_db_session, sample_service): assert len(Notification.query.all()) == 0 # create one notification a day between 1st and 9th for i in range(1, 11): past_date = '2016-01-{0:02d}'.format(i) with freeze_time(past_date): sample_notification(notify_db, notify_db_session, created_at=datetime.utcnow(), status="failed") all_notifications = Notification.query.all() assert len(all_notifications) == 10 all_notifications = get_notifications_for_service(sample_service.id, limit_days=10).items assert len(all_notifications) == 10 all_notifications = get_notifications_for_service(sample_service.id, limit_days=1).items assert len(all_notifications) == 2
def test_should_delete_notifications_after_seven_days(notify_db, notify_db_session): assert len(Notification.query.all()) == 0 # create one notification a day between 1st and 10th from 11:00 to 19:00 for i in range(1, 11): past_date = '2016-01-{0:02d} {0:02d}:00:00.000000'.format(i) with freeze_time(past_date): sample_notification(notify_db, notify_db_session, created_at=datetime.utcnow(), status="failed") all_notifications = Notification.query.all() assert len(all_notifications) == 10 # Records from before 3rd should be deleted delete_notifications_created_more_than_a_week_ago('failed') remaining_notifications = Notification.query.all() assert len(remaining_notifications) == 8 for notification in remaining_notifications: assert notification.created_at.date() >= date(2016, 1, 3)
def test_create_nightly_billing_use_BST(notify_db, notify_db_session, sample_service, sample_template, mocker): mocker.patch('app.dao.fact_billing_dao.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=datetime(2018, 3, 25, 12, 0), service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) sample_notification( notify_db, notify_db_session, created_at=datetime(2018, 3, 25, 23, 5), service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) notifications = Notification.query.order_by(Notification.created_at).all() assert len(notifications) == 2 records = FactBilling.query.all() assert len(records) == 0 create_nightly_billing() records = FactBilling.query.order_by(FactBilling.bst_date).all() assert len(records) == 2 assert records[0].bst_date == date(2018, 3, 25) assert records[-1].bst_date == date(2018, 3, 26)
def test_should_not_process_sms_job_if_would_exceed_send_limits_inc_today(notify_db, notify_db_session, mocker): service = sample_service(notify_db, notify_db_session, limit=1) job = sample_job(notify_db, notify_db_session, service=service) sample_notification(notify_db, notify_db_session, service=service, job=job) mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('sms')) mocker.patch('app.celery.tasks.send_sms.apply_async') mocker.patch('app.encryption.encrypt', return_value="something_encrypted") mocker.patch('app.celery.tasks.create_uuid', return_value="uuid") process_job(job.id) job = jobs_dao.dao_get_job_by_id(job.id) assert job.job_status == 'sending limits exceeded' assert s3.get_job_from_s3.called is False assert tasks.send_sms.apply_async.called is False
def test_should_be_able_to_get_template_usage_history(notify_db, notify_db_session, sample_service): with freeze_time('2000-01-01 12:00:00'): sms = sample_template(notify_db, notify_db_session) notification = sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) results = dao_get_last_template_usage(sms.id) assert results.template.name == 'Template Name' assert results.template.template_type == 'sms' assert results.created_at == datetime(year=2000, month=1, day=1, hour=12, minute=0, second=0) assert results.template_id == sms.id assert results.id == notification.id
def test_get_template_statistics_by_id_returns_last_notification( notify_db, notify_db_session, notify_api, sample_service): template = create_sample_template( notify_db, notify_db_session, template_name='Sample Template 1', service=sample_service ) notification_1 = sample_notification( notify_db, notify_db_session, service=sample_service, template=template) notification_2 = sample_notification( notify_db, notify_db_session, service=sample_service, template=template) notification_3 = sample_notification( notify_db, notify_db_session, service=sample_service, template=template) with notify_api.test_request_context(): with notify_api.test_client() as client: auth_header = create_authorization_header() response = client.get( '/service/{}/template-statistics/{}'.format(sample_service.id, template.id), headers=[('Content-Type', 'application/json'), auth_header], ) assert response.status_code == 200 json_resp = json.loads(response.get_data(as_text=True))['data'] assert json_resp['id'] == str(notification_3.id)
def test_dao_timeout_notifications(notify_db, notify_db_session, ): with freeze_time(datetime.utcnow() - timedelta(minutes=2)): created = sample_notification(notify_db, notify_db_session, status='created') sending = sample_notification(notify_db, notify_db_session, status='sending') pending = sample_notification(notify_db, notify_db_session, status='pending') delivered = sample_notification(notify_db, notify_db_session, status='delivered') assert Notification.query.get(created.id).status == 'created' assert Notification.query.get(sending.id).status == 'sending' assert Notification.query.get(pending.id).status == 'pending' assert Notification.query.get(delivered.id).status == 'delivered' updated = dao_timeout_notifications(1) assert Notification.query.get(created.id).status == 'technical-failure' assert Notification.query.get(sending.id).status == 'temporary-failure' assert Notification.query.get(pending.id).status == 'temporary-failure' assert Notification.query.get(delivered.id).status == 'delivered' assert NotificationHistory.query.get(created.id).status == 'technical-failure' assert NotificationHistory.query.get(sending.id).status == 'temporary-failure' assert NotificationHistory.query.get(pending.id).status == 'temporary-failure' assert NotificationHistory.query.get(delivered.id).status == 'delivered' assert updated == 3
def test_get_notification_billable_unit_count_per_month(notify_db, notify_db_session, sample_service): for year, month, day in ( (2017, 1, 15), # ↓ 2016 financial year (2016, 8, 1), (2016, 7, 15), (2016, 4, 15), (2016, 4, 15), (2016, 4, 1), # ↓ 2015 financial year (2016, 3, 31), (2016, 1, 15) ): sample_notification( notify_db, notify_db_session, service=sample_service, created_at=datetime( year, month, day, 0, 0, 0, 0 ) - timedelta(hours=1, seconds=1) # one second before midnight ) for financial_year, months in ( ( 2017, [] ), ( 2016, [('April', 2), ('July', 2), ('January', 1)] ), ( 2015, [('January', 1), ('March', 2)] ), ( 2014, [] ) ): assert get_notification_billable_unit_count_per_month( sample_service.id, financial_year ) == months
def test_get_all_notifications_for_job_by_status(notify_db, notify_db_session, sample_job): notifications = partial(get_notifications_for_job, sample_job.service.id, sample_job.id) for status in NOTIFICATION_STATUS_TYPES: sample_notification( notify_db, notify_db_session, service=sample_job.service, template=sample_job.template, job=sample_job, status=status ) assert len(notifications().items) == len(NOTIFICATION_STATUS_TYPES) for status in NOTIFICATION_STATUS_TYPES: if status == 'failed': assert len(notifications(filter_dict={'status': status}).items) == len(NOTIFICATION_STATUS_TYPES_FAILED) else: assert len(notifications(filter_dict={'status': status}).items) == 1 assert len(notifications(filter_dict={'status': NOTIFICATION_STATUS_TYPES[:3]}).items) == 3
def test_should_not_delete_notification_history(notify_db, notify_db_session): with freeze_time('2016-01-01 12:00'): notification = sample_notification(notify_db, notify_db_session, created_at=datetime.utcnow(), status="failed") notification_id = notification.id assert Notification.query.count() == 1 assert NotificationHistory.query.count() == 1 delete_notifications_created_more_than_a_week_ago('failed') assert Notification.query.count() == 0 assert NotificationHistory.query.count() == 1 assert NotificationHistory.query.one().id == notification_id
def test_get_notifications_by_reference(notify_db, notify_db_session, sample_service): client_reference = 'some-client-ref' assert len(Notification.query.all()) == 0 sample_notification(notify_db, notify_db_session, client_reference=client_reference) sample_notification(notify_db, notify_db_session, client_reference=client_reference) sample_notification(notify_db, notify_db_session, client_reference='other-ref') all_notifications = get_notifications_for_service(sample_service.id, client_reference=client_reference).items assert len(all_notifications) == 2
def test_should_be_able_to_get_all_template_usage_history_order_by_notification_created_at( notify_db, notify_db_session, sample_service): sms = sample_template(notify_db, notify_db_session) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) most_recent = sample_notification(notify_db, notify_db_session, service=sample_service, template=sms) results = dao_get_last_template_usage(sms.id) assert results.id == most_recent.id
def test_create_nightly_billing_null_sent_by_sms(notify_db, notify_db_session, sample_service, sample_template, mocker): yesterday = datetime.now() - timedelta(days=1) mocker.patch('app.dao.fact_billing_dao.get_rate', side_effect=mocker_get_rate) sample_notification( notify_db, notify_db_session, created_at=yesterday, service=sample_service, template=sample_template, status='delivered', sent_by=None, international=False, rate_multiplier=1.0, billable_units=1, ) records = FactBilling.query.all() assert len(records) == 0 # Celery expects the arguments to be a string or primitive type. yesterday_str = datetime.strftime(yesterday, "%Y-%m-%d") create_nightly_billing(yesterday_str) records = FactBilling.query.all() assert len(records) == 1 record = records[0] assert record.bst_date == datetime.date(yesterday) assert record.rate == Decimal(1.33) assert record.billable_units == 1 assert record.rate_multiplier == 1 assert record.provider == 'unknown'
def test_should_not_update_status_one_notification_status_is_delivered(notify_db, notify_db_session, sample_email_template, ses_provider): notification = sample_notification(notify_db=notify_db, notify_db_session=notify_db_session, template=sample_email_template, status='sending') assert Notification.query.get(notification.id).status == "sending" notification.reference = 'reference' dao_update_notification(notification) update_notification_status_by_reference('reference', 'delivered') assert Notification.query.get(notification.id).status == 'delivered' update_notification_status_by_reference('reference', 'failed') assert Notification.query.get(notification.id).status == 'delivered'
def test_get_delivery_status_with_undelivered_notification(notify_api, notify_db, notify_db_session): notification = sample_notification(notify_db=notify_db, notify_db_session=notify_db_session, status='sending') more_than_five_mins_ago = datetime.utcnow() - timedelta(minutes=10) notification.created_at = more_than_five_mins_ago notify_db.session.add(notification) notify_db.session.commit() with notify_api.test_request_context(): with notify_api.test_client() as client: path = '/_delivery_status' response = client.get(path) assert response.status_code == 500 resp_json = json.loads(response.get_data(as_text=True)) assert resp_json['status'] == 'error' assert resp_json['message'] == '1 notifications in sending state over 5 minutes'
def test_should_not_send_to_provider_when_status_is_not_created(notify_db, notify_db_session, sample_service, mocker): notification = sample_notification(notify_db=notify_db, notify_db_session=notify_db_session, service=sample_service, status='sending') mocker.patch('app.mmg_client.send_sms') mocker.patch('app.mmg_client.get_name', return_value="mmg") mocker.patch('app.celery.research_mode_tasks.send_sms_response.apply_async') send_to_providers.send_sms_to_provider( notification ) app.mmg_client.send_sms.assert_not_called() app.celery.research_mode_tasks.send_sms_response.apply_async.assert_not_called()
def test_should_return_notifications_including_jobs(notify_db, notify_db_session, sample_service): assert len(Notification.query.all()) == 0 job = sample_job(notify_db, notify_db_session) with_job = sample_notification( notify_db, notify_db_session, created_at=datetime.utcnow(), status="delivered", job=job ) all_notifications = Notification.query.all() assert len(all_notifications) == 1 all_notifications = get_notifications_for_service(sample_service.id).items assert len(all_notifications) == 0 all_notifications = get_notifications_for_service(sample_service.id, limit_days=1, include_jobs=True).items assert len(all_notifications) == 1 assert all_notifications[0].id == with_job.id
def test_send_email_to_provider_should_call_research_mode_task_response_task_if_research_mode( notify_db, notify_db_session, sample_service, sample_email_template, ses_provider, mocker, research_mode, key_type): notification = sample_notification(notify_db=notify_db, notify_db_session=notify_db_session, template=sample_email_template, to_field="*****@*****.**", key_type=key_type ) reference = uuid.uuid4() mocker.patch('app.uuid.uuid4', return_value=reference) mocker.patch('app.aws_ses_client.send_email') mocker.patch('app.aws_ses_client.get_name', return_value="ses") mocker.patch('app.celery.research_mode_tasks.send_email_response.apply_async') if research_mode: sample_service.research_mode = True notify_db.session.add(sample_service) notify_db.session.commit() send_to_providers.send_email_to_provider( notification ) assert not app.aws_ses_client.send_email.called send_to_providers.send_email_response.apply_async.assert_called_once_with( ('ses', str(reference), '*****@*****.**'), queue="research-mode" ) persisted_notification = Notification.query.filter_by(id=notification.id).one() assert persisted_notification.to == '*****@*****.**' assert persisted_notification.template_id == sample_email_template.id assert persisted_notification.status == 'sending' assert persisted_notification.sent_at <= datetime.utcnow() assert persisted_notification.created_at <= datetime.utcnow() assert persisted_notification.sent_by == 'ses' assert persisted_notification.reference == str(reference) assert persisted_notification.billable_units == 0
def set_up_notifications(notify_db, notify_db_session): sms = create_sample_template(notify_db, notify_db_session) email = sample_email_template(notify_db, notify_db_session) today = datetime.now() a_week_ago = datetime.now() - timedelta(days=7) a_month_ago = datetime.now() - timedelta(days=30) sample_notification(notify_db, notify_db_session, created_at=a_month_ago, template=sms) sample_notification(notify_db, notify_db_session, created_at=a_month_ago, template=email) email.name = 'Updated Email Template Name' dao_update_template(email) sms.name = 'Updated SMS Template Name' dao_update_template(sms) sample_notification(notify_db, notify_db_session, created_at=a_week_ago, template=sms) sample_notification(notify_db, notify_db_session, created_at=a_week_ago, template=email) email.name = 'New Email Template Name' dao_update_template(email) sms.name = 'New SMS Template Name' dao_update_template(sms) sample_notification(notify_db, notify_db_session, created_at=today, template=sms) sample_notification(notify_db, notify_db_session, created_at=today, template=email) return email, sms