mirror of
https://github.com/GSA/notifications-api.git
synced 2026-07-28 11:49:42 -04:00
Merge branch 'master' into schedule-api-notification
This commit is contained in:
11
tests/app/aws/test_s3.py
Normal file
11
tests/app/aws/test_s3.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from app.aws.s3 import get_s3_file
|
||||
|
||||
|
||||
def test_get_s3_file_makes_correct_call(sample_service, sample_job, mocker):
|
||||
get_s3_mock = mocker.patch('app.aws.s3.get_s3_object')
|
||||
get_s3_file('foo-bucket', 'bar-file.txt')
|
||||
|
||||
get_s3_mock.assert_called_with(
|
||||
'foo-bucket',
|
||||
'bar-file.txt'
|
||||
)
|
||||
@@ -12,15 +12,19 @@ from celery.exceptions import Retry
|
||||
from app import (encryption, DATETIME_FORMAT)
|
||||
from app.celery import provider_tasks
|
||||
from app.celery import tasks
|
||||
from app.celery.tasks import s3, build_dvla_file, create_dvla_file_contents, update_dvla_job_to_error
|
||||
from app.celery.tasks import (
|
||||
s3,
|
||||
build_dvla_file,
|
||||
create_dvla_file_contents,
|
||||
update_dvla_job_to_error,
|
||||
process_job,
|
||||
process_row,
|
||||
send_sms,
|
||||
send_email,
|
||||
persist_letter,
|
||||
get_template_class,
|
||||
update_job_to_sent_to_dvla
|
||||
update_job_to_sent_to_dvla,
|
||||
update_letter_notifications_statuses
|
||||
)
|
||||
from app.dao import jobs_dao, services_dao
|
||||
from app.models import (
|
||||
@@ -34,6 +38,7 @@ from app.models import (
|
||||
Job)
|
||||
|
||||
from tests.app import load_example_csv
|
||||
from tests.conftest import set_config
|
||||
from tests.app.conftest import (
|
||||
sample_service,
|
||||
sample_template,
|
||||
@@ -1071,3 +1076,37 @@ def test_update_dvla_job_to_error(sample_letter_template, sample_letter_job):
|
||||
assert not n.sent_by
|
||||
|
||||
assert 'error' == Job.query.filter_by(id=sample_letter_job.id).one().job_status
|
||||
|
||||
|
||||
def test_update_letter_notifications_statuses_raises_for_invalid_format(notify_api, mocker):
|
||||
invalid_file = 'ref-foo|Sent|1|Unsorted\nref-bar|Sent|2'
|
||||
mocker.patch('app.celery.tasks.s3.get_s3_file', return_value=invalid_file)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
update_letter_notifications_statuses(filename='foo.txt')
|
||||
|
||||
|
||||
def test_update_letter_notifications_statuses_calls_with_correct_bucket_location(notify_api, mocker):
|
||||
s3_mock = mocker.patch('app.celery.tasks.s3.get_s3_object')
|
||||
|
||||
with set_config(notify_api, 'NOTIFY_EMAIL_DOMAIN', 'foo.bar'):
|
||||
update_letter_notifications_statuses(filename='foo.txt')
|
||||
s3_mock.assert_called_with('{}-ftp'.format(current_app.config['NOTIFY_EMAIL_DOMAIN']), 'foo.txt')
|
||||
|
||||
|
||||
def test_update_letter_notifications_statuses_builds_updates_list(notify_api, mocker):
|
||||
valid_file = 'ref-foo|Sent|1|Unsorted\nref-bar|Sent|2|Sorted'
|
||||
mocker.patch('app.celery.tasks.s3.get_s3_file', return_value=valid_file)
|
||||
updates = update_letter_notifications_statuses(filename='foo.txt')
|
||||
|
||||
assert len(updates) == 2
|
||||
|
||||
assert updates[0].reference == 'ref-foo'
|
||||
assert updates[0].status == 'Sent'
|
||||
assert updates[0].page_count == '1'
|
||||
assert updates[0].cost_threshold == 'Unsorted'
|
||||
|
||||
assert updates[1].reference == 'ref-bar'
|
||||
assert updates[1].status == 'Sent'
|
||||
assert updates[1].page_count == '2'
|
||||
assert updates[1].cost_threshold == 'Sorted'
|
||||
|
||||
@@ -24,7 +24,8 @@ from app.dao.services_dao import (
|
||||
dao_fetch_todays_stats_for_all_services,
|
||||
fetch_stats_by_date_range_for_all_services,
|
||||
dao_suspend_service,
|
||||
dao_resume_service
|
||||
dao_resume_service,
|
||||
dao_fetch_active_users_for_service
|
||||
)
|
||||
from app.dao.users_dao import save_model_user
|
||||
from app.models import (
|
||||
@@ -49,6 +50,7 @@ from app.models import (
|
||||
KEY_TYPE_TEST
|
||||
)
|
||||
|
||||
from tests.app.db import create_user, create_service
|
||||
from tests.app.conftest import (
|
||||
sample_notification as create_notification,
|
||||
sample_notification_history as create_notification_history,
|
||||
@@ -783,3 +785,13 @@ def test_fetch_monthly_historical_template_stats_for_service_separates_templates
|
||||
assert len(result.get('2016-04').keys()) == 2
|
||||
assert str(template_one.id) in result.get('2016-04').keys()
|
||||
assert str(template_two.id) in result.get('2016-04').keys()
|
||||
|
||||
|
||||
def test_dao_fetch_active_users_for_service_returns_active_only(notify_db, notify_db_session):
|
||||
active_user = create_user(email='active@foo.com', state='active')
|
||||
pending_user = create_user(email='pending@foo.com', state='pending')
|
||||
service = create_service(user=active_user)
|
||||
dao_add_user_to_service(service, pending_user)
|
||||
users = dao_fetch_active_users_for_service(service.id)
|
||||
|
||||
assert len(users) == 1
|
||||
|
||||
@@ -9,13 +9,14 @@ from app.dao.templates_dao import dao_create_template
|
||||
from app.dao.services_dao import dao_create_service
|
||||
|
||||
|
||||
def create_user(mobile_number="+447700900986", email="notify@digital.cabinet-office.gov.uk"):
|
||||
def create_user(mobile_number="+447700900986", email="notify@digital.cabinet-office.gov.uk", state='active'):
|
||||
data = {
|
||||
'id': uuid.uuid4(),
|
||||
'name': 'Test User',
|
||||
'email_address': email,
|
||||
'password': 'password',
|
||||
'mobile_number': mobile_number,
|
||||
'state': 'active'
|
||||
'state': state
|
||||
}
|
||||
user = User.query.filter_by(email_address=email).first()
|
||||
if not user:
|
||||
@@ -24,11 +25,11 @@ def create_user(mobile_number="+447700900986", email="notify@digital.cabinet-off
|
||||
return user
|
||||
|
||||
|
||||
def create_service(user=None, service_name="Sample service", service_id=None):
|
||||
def create_service(user=None, service_name="Sample service", service_id=None, restricted=False):
|
||||
service = Service(
|
||||
name=service_name,
|
||||
message_limit=1000,
|
||||
restricted=False,
|
||||
restricted=restricted,
|
||||
email_from=service_name.lower().replace(' ', '.'),
|
||||
created_by=user or create_user()
|
||||
)
|
||||
|
||||
@@ -10,17 +10,65 @@ from app.dao.notifications_dao import (
|
||||
get_notification_by_id
|
||||
)
|
||||
from app.models import NotificationStatistics
|
||||
from tests.app.notifications.test_notifications_ses_callback import ses_confirmation_callback
|
||||
from tests.app.conftest import sample_notification as create_sample_notification
|
||||
|
||||
|
||||
def test_dvla_callback_should_not_need_auth(client):
|
||||
data = json.dumps({"somekey": "somevalue"})
|
||||
def test_dvla_callback_returns_400_with_invalid_request(client):
|
||||
data = json.dumps({"foo": "bar"})
|
||||
response = client.post(
|
||||
path='/notifications/letter/dvla',
|
||||
data=data,
|
||||
headers=[('Content-Type', 'application/json')])
|
||||
headers=[('Content-Type', 'application/json')]
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_dvla_callback_autoconfirms_subscription(client, mocker):
|
||||
autoconfirm_mock = mocker.patch('app.notifications.notifications_letter_callback.autoconfirm_subscription')
|
||||
|
||||
data = ses_confirmation_callback()
|
||||
response = client.post(
|
||||
path='/notifications/letter/dvla',
|
||||
data=data,
|
||||
headers=[('Content-Type', 'application/json')]
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert autoconfirm_mock.called
|
||||
|
||||
|
||||
def test_dvla_callback_autoconfirm_does_not_call_update_letter_notifications_task(client, mocker):
|
||||
autoconfirm_mock = mocker.patch('app.notifications.notifications_letter_callback.autoconfirm_subscription')
|
||||
update_task = \
|
||||
mocker.patch('app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async')
|
||||
|
||||
data = ses_confirmation_callback()
|
||||
response = client.post(
|
||||
path='/notifications/letter/dvla',
|
||||
data=data,
|
||||
headers=[('Content-Type', 'application/json')]
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert autoconfirm_mock.called
|
||||
assert not update_task.called
|
||||
|
||||
|
||||
def test_dvla_callback_calls_update_letter_notifications_task(client, mocker):
|
||||
update_task = \
|
||||
mocker.patch('app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async')
|
||||
data = _sample_sns_s3_callback()
|
||||
response = client.post(
|
||||
path='/notifications/letter/dvla',
|
||||
data=data,
|
||||
headers=[('Content-Type', 'application/json')]
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert update_task.called
|
||||
update_task.assert_called_with(['bar.txt'], queue='notify')
|
||||
|
||||
|
||||
def test_firetext_callback_should_not_need_auth(client, mocker):
|
||||
@@ -458,3 +506,46 @@ def test_firetext_callback_should_record_statsd(client, notify_db, notify_db_ses
|
||||
|
||||
def get_notification_stats(service_id):
|
||||
return NotificationStatistics.query.filter_by(service_id=service_id).one()
|
||||
|
||||
|
||||
def _sample_sns_s3_callback():
|
||||
return json.dumps({
|
||||
"SigningCertURL": "foo.pem",
|
||||
"UnsubscribeURL": "bar",
|
||||
"Signature": "some-signature",
|
||||
"Type": "Notification",
|
||||
"Timestamp": "2016-05-03T08:35:12.884Z",
|
||||
"SignatureVersion": "1",
|
||||
"MessageId": "6adbfe0a-d610-509a-9c47-af894e90d32d",
|
||||
"Subject": "Amazon S3 Notification",
|
||||
"TopicArn": "sample-topic-arn",
|
||||
"Message": {
|
||||
"Records": [{
|
||||
"eventVersion": "2.0",
|
||||
"eventSource": "aws:s3",
|
||||
"awsRegion": "eu-west-1",
|
||||
"eventTime": "2017-05-03T08:35:12.826Z",
|
||||
"eventName": "ObjectCreated:Put",
|
||||
"userIdentity": {"principalId": "some-p-id"},
|
||||
"requestParameters": {"sourceIPAddress": "8.8.8.8"},
|
||||
"responseElements": {"x-amz-request-id": "some-req-id", "x-amz-id-2": "some-amz-id"},
|
||||
"s3": {
|
||||
"s3SchemaVersion": "1.0",
|
||||
"configurationId": "some-config-id",
|
||||
"bucket": {
|
||||
"name": "some-bucket",
|
||||
"ownerIdentity": {"principalId": "some-p-id"},
|
||||
"arn": "some-bucket-arn"
|
||||
},
|
||||
"object": {
|
||||
"key": "bar.txt",
|
||||
"size": 200,
|
||||
"eTag": "some-etag",
|
||||
"versionId": "some-v-id",
|
||||
"sequencer": "some-seq"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1658,3 +1658,66 @@ def test_search_for_notification_by_to_field_return_multiple_matches(
|
||||
assert str(notification1.id) in [n["id"] for n in result["notifications"]]
|
||||
assert str(notification2.id) in [n["id"] for n in result["notifications"]]
|
||||
assert str(notification3.id) in [n["id"] for n in result["notifications"]]
|
||||
|
||||
|
||||
def test_update_service_calls_send_notification_as_service_becomes_live(notify_db, notify_db_session, client, mocker):
|
||||
send_notification_mock = mocker.patch('app.service.rest.send_notification_to_service_users')
|
||||
|
||||
restricted_service = create_service(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
restricted=True
|
||||
)
|
||||
|
||||
data = {
|
||||
"restricted": False
|
||||
}
|
||||
|
||||
auth_header = create_authorization_header()
|
||||
resp = client.post(
|
||||
'service/{}'.format(restricted_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[auth_header],
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert send_notification_mock.called
|
||||
|
||||
|
||||
def test_update_service_does_not_call_send_notification_for_live_service(sample_service, client, mocker):
|
||||
send_notification_mock = mocker.patch('app.service.rest.send_notification_to_service_users')
|
||||
|
||||
data = {
|
||||
"restricted": True
|
||||
}
|
||||
|
||||
auth_header = create_authorization_header()
|
||||
resp = client.post(
|
||||
'service/{}'.format(sample_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[auth_header],
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert not send_notification_mock.called
|
||||
|
||||
|
||||
def test_update_service_does_not_call_send_notification_when_restricted_not_changed(sample_service, client, mocker):
|
||||
send_notification_mock = mocker.patch('app.service.rest.send_notification_to_service_users')
|
||||
|
||||
data = {
|
||||
"name": 'Name of service'
|
||||
}
|
||||
|
||||
auth_header = create_authorization_header()
|
||||
resp = client.post(
|
||||
'service/{}'.format(sample_service.id),
|
||||
data=json.dumps(data),
|
||||
headers=[auth_header],
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
assert not send_notification_mock.called
|
||||
|
||||
113
tests/app/service/test_sender.py
Normal file
113
tests/app/service/test_sender.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import pytest
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from app.dao.services_dao import dao_add_user_to_service
|
||||
from app.models import Notification, EMAIL_TYPE, SMS_TYPE
|
||||
from app.service.sender import send_notification_to_service_users
|
||||
|
||||
from tests.app.conftest import (
|
||||
notify_service as create_notify_service,
|
||||
sample_service as create_sample_service
|
||||
)
|
||||
from tests.app.db import create_template, create_user
|
||||
|
||||
|
||||
@pytest.mark.parametrize('notification_type', [
|
||||
EMAIL_TYPE,
|
||||
SMS_TYPE
|
||||
])
|
||||
def test_send_notification_to_service_users_persists_notifications_correctly(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
notification_type,
|
||||
sample_user,
|
||||
mocker
|
||||
):
|
||||
mocker.patch('app.service.sender.send_notification_to_queue')
|
||||
|
||||
create_notify_service(notify_db, notify_db_session)
|
||||
service = create_sample_service(notify_db, notify_db_session, user=sample_user)
|
||||
template = create_template(service, template_type=notification_type)
|
||||
send_notification_to_service_users(service_id=service.id, template_id=template.id)
|
||||
to = sample_user.email_address if notification_type == EMAIL_TYPE else sample_user.mobile_number
|
||||
|
||||
notification = Notification.query.one()
|
||||
|
||||
assert Notification.query.count() == 1
|
||||
assert notification.to == to
|
||||
assert str(notification.service_id) == current_app.config['NOTIFY_SERVICE_ID']
|
||||
assert notification.template.id == template.id
|
||||
assert notification.template.template_type == notification_type
|
||||
assert notification.notification_type == notification_type
|
||||
|
||||
|
||||
def test_send_notification_to_service_users_sends_to_queue(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
sample_user,
|
||||
mocker
|
||||
):
|
||||
send_mock = mocker.patch('app.service.sender.send_notification_to_queue')
|
||||
|
||||
create_notify_service(notify_db, notify_db_session)
|
||||
service = create_sample_service(notify_db, notify_db_session, user=sample_user)
|
||||
template = create_template(service, template_type=EMAIL_TYPE)
|
||||
send_notification_to_service_users(service_id=service.id, template_id=template.id)
|
||||
|
||||
assert send_mock.called
|
||||
assert send_mock.call_count == 1
|
||||
|
||||
|
||||
def test_send_notification_to_service_users_includes_user_fields_in_personalisation(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
sample_user,
|
||||
mocker
|
||||
):
|
||||
persist_mock = mocker.patch('app.service.sender.persist_notification')
|
||||
mocker.patch('app.service.sender.send_notification_to_queue')
|
||||
|
||||
create_notify_service(notify_db, notify_db_session)
|
||||
service = create_sample_service(notify_db, notify_db_session, user=sample_user)
|
||||
template = create_template(service, template_type=EMAIL_TYPE)
|
||||
send_notification_to_service_users(
|
||||
service_id=service.id,
|
||||
template_id=template.id,
|
||||
include_user_fields=['name', 'email_address', 'state']
|
||||
)
|
||||
|
||||
persist_call = persist_mock.call_args_list[0][1]
|
||||
|
||||
assert len(persist_mock.call_args_list) == 1
|
||||
assert persist_call['personalisation'] == {
|
||||
'name': sample_user.name,
|
||||
'email_address': sample_user.email_address,
|
||||
'state': sample_user.state,
|
||||
}
|
||||
|
||||
|
||||
def test_send_notification_to_service_users_sends_to_active_users_only(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
mocker
|
||||
):
|
||||
mocker.patch('app.service.sender.send_notification_to_queue')
|
||||
|
||||
create_notify_service(notify_db, notify_db_session)
|
||||
|
||||
first_active_user = create_user(email='foo@bar.com', state='active')
|
||||
second_active_user = create_user(email='foo1@bar.com', state='active')
|
||||
pending_user = create_user(email='foo2@bar.com', state='pending')
|
||||
service = create_sample_service(notify_db, notify_db_session, user=first_active_user)
|
||||
dao_add_user_to_service(service, second_active_user)
|
||||
dao_add_user_to_service(service, pending_user)
|
||||
template = create_template(service, template_type=EMAIL_TYPE)
|
||||
|
||||
send_notification_to_service_users(service_id=service.id, template_id=template.id)
|
||||
notifications = Notification.query.all()
|
||||
|
||||
assert Notification.query.count() == 2
|
||||
|
||||
assert notifications[0].to == first_active_user.email_address
|
||||
assert notifications[1].to == second_active_user.email_address
|
||||
Reference in New Issue
Block a user