2016-06-20 13:33:53 +01:00
|
|
|
from datetime import datetime, timedelta
|
2019-01-16 17:32:19 +00:00
|
|
|
from unittest.mock import call
|
2017-06-07 16:31:51 +01:00
|
|
|
|
2018-11-15 17:24:37 +00:00
|
|
|
import pytest
|
2019-12-03 10:26:59 +00:00
|
|
|
from collections import namedtuple
|
2016-09-07 15:36:59 +01:00
|
|
|
from freezegun import freeze_time
|
2019-11-05 16:47:00 +00:00
|
|
|
from mock import mock
|
2017-06-07 16:31:51 +01:00
|
|
|
|
2016-06-20 13:33:53 +01:00
|
|
|
from app.celery import scheduled_tasks
|
2017-01-27 12:30:56 +00:00
|
|
|
from app.celery.scheduled_tasks import (
|
2017-10-16 12:32:44 +01:00
|
|
|
check_job_status,
|
2017-06-02 14:28:52 +01:00
|
|
|
delete_invitations,
|
2017-01-27 12:30:56 +00:00
|
|
|
delete_verify_codes,
|
|
|
|
|
run_scheduled_jobs,
|
2017-06-02 14:28:52 +01:00
|
|
|
send_scheduled_notifications,
|
2019-06-11 13:16:34 +01:00
|
|
|
replay_created_notifications,
|
|
|
|
|
check_precompiled_letter_state,
|
2019-06-11 15:13:06 +01:00
|
|
|
check_templated_letter_state,
|
2019-11-13 17:01:03 +00:00
|
|
|
check_for_missing_rows_in_completed_jobs,
|
2019-11-29 21:24:17 +00:00
|
|
|
check_for_services_with_high_failure_rates_or_sending_to_tv_numbers,
|
2019-11-13 17:01:03 +00:00
|
|
|
switch_current_sms_provider_on_slow_delivery,
|
2017-11-09 14:13:42 +00:00
|
|
|
)
|
2017-08-22 15:49:56 +01:00
|
|
|
from app.config import QueueNames, TaskNames
|
2016-08-24 17:03:56 +01:00
|
|
|
from app.dao.jobs_dao import dao_get_job_by_id
|
2017-05-22 15:07:16 +01:00
|
|
|
from app.dao.notifications_dao import dao_get_scheduled_notifications
|
2019-11-14 10:52:24 +00:00
|
|
|
from app.dao.provider_details_dao import get_provider_details_by_identifier
|
2017-06-06 16:02:01 +01:00
|
|
|
from app.models import (
|
2017-09-26 12:03:06 +01:00
|
|
|
JOB_STATUS_IN_PROGRESS,
|
2018-03-09 16:34:47 +00:00
|
|
|
JOB_STATUS_ERROR,
|
2019-01-16 17:32:19 +00:00
|
|
|
JOB_STATUS_FINISHED,
|
2019-06-11 13:16:34 +01:00
|
|
|
NOTIFICATION_DELIVERED,
|
|
|
|
|
NOTIFICATION_PENDING_VIRUS_CHECK,
|
2017-11-10 13:49:20 +00:00
|
|
|
)
|
2018-01-23 10:13:56 +00:00
|
|
|
from app.v2.errors import JobIncompleteError
|
2019-11-05 16:47:00 +00:00
|
|
|
from tests.app import load_example_csv
|
2019-01-16 17:32:19 +00:00
|
|
|
|
2018-11-19 17:09:27 +00:00
|
|
|
from tests.app.db import (
|
|
|
|
|
create_notification,
|
|
|
|
|
create_template,
|
|
|
|
|
create_job,
|
2017-06-12 15:55:42 +01:00
|
|
|
)
|
2016-06-20 13:33:53 +01:00
|
|
|
|
|
|
|
|
|
2018-12-05 14:40:07 +00:00
|
|
|
def _create_slow_delivery_notification(template, provider='mmg'):
|
2017-02-13 15:46:06 +00:00
|
|
|
now = datetime.utcnow()
|
|
|
|
|
five_minutes_from_now = now + timedelta(minutes=5)
|
2017-02-24 13:41:32 +00:00
|
|
|
|
|
|
|
|
create_notification(
|
2017-02-13 15:46:06 +00:00
|
|
|
template=template,
|
|
|
|
|
status='delivered',
|
|
|
|
|
sent_by=provider,
|
2018-12-05 14:40:07 +00:00
|
|
|
updated_at=five_minutes_from_now,
|
|
|
|
|
sent_at=now,
|
2017-02-13 15:46:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2019-06-17 13:52:36 +01:00
|
|
|
def test_should_call_delete_codes_on_delete_verify_codes_task(notify_db_session, mocker):
|
2016-06-20 13:33:53 +01:00
|
|
|
mocker.patch('app.celery.scheduled_tasks.delete_codes_older_created_more_than_a_day_ago')
|
|
|
|
|
delete_verify_codes()
|
|
|
|
|
assert scheduled_tasks.delete_codes_older_created_more_than_a_day_ago.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
2019-11-20 17:23:39 +00:00
|
|
|
def test_should_call_delete_invotations_on_delete_invitations_task(notify_db_session, mocker):
|
2016-06-20 13:33:53 +01:00
|
|
|
mocker.patch('app.celery.scheduled_tasks.delete_invitations_created_more_than_two_days_ago')
|
|
|
|
|
delete_invitations()
|
|
|
|
|
assert scheduled_tasks.delete_invitations_created_more_than_two_days_ago.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
2019-10-30 10:51:07 +00:00
|
|
|
def test_should_update_scheduled_jobs_and_put_on_queue(mocker, sample_template):
|
2016-08-24 17:03:56 +01:00
|
|
|
mocked = mocker.patch('app.celery.tasks.process_job.apply_async')
|
|
|
|
|
|
|
|
|
|
one_minute_in_the_past = datetime.utcnow() - timedelta(minutes=1)
|
2019-10-30 10:51:07 +00:00
|
|
|
job = create_job(sample_template, job_status='scheduled', scheduled_for=one_minute_in_the_past)
|
2016-08-24 17:03:56 +01:00
|
|
|
|
|
|
|
|
run_scheduled_jobs()
|
|
|
|
|
|
|
|
|
|
updated_job = dao_get_job_by_id(job.id)
|
|
|
|
|
assert updated_job.job_status == 'pending'
|
2017-05-25 10:51:49 +01:00
|
|
|
mocked.assert_called_with([str(job.id)], queue="job-tasks")
|
2016-08-24 17:03:56 +01:00
|
|
|
|
|
|
|
|
|
2019-10-30 10:51:07 +00:00
|
|
|
def test_should_update_all_scheduled_jobs_and_put_on_queue(sample_template, mocker):
|
2016-08-24 17:03:56 +01:00
|
|
|
mocked = mocker.patch('app.celery.tasks.process_job.apply_async')
|
|
|
|
|
|
|
|
|
|
one_minute_in_the_past = datetime.utcnow() - timedelta(minutes=1)
|
|
|
|
|
ten_minutes_in_the_past = datetime.utcnow() - timedelta(minutes=10)
|
|
|
|
|
twenty_minutes_in_the_past = datetime.utcnow() - timedelta(minutes=20)
|
2019-10-30 10:51:07 +00:00
|
|
|
job_1 = create_job(sample_template, job_status='scheduled', scheduled_for=one_minute_in_the_past)
|
|
|
|
|
job_2 = create_job(sample_template, job_status='scheduled', scheduled_for=ten_minutes_in_the_past)
|
|
|
|
|
job_3 = create_job(sample_template, job_status='scheduled', scheduled_for=twenty_minutes_in_the_past)
|
2016-08-24 17:03:56 +01:00
|
|
|
|
|
|
|
|
run_scheduled_jobs()
|
|
|
|
|
|
|
|
|
|
assert dao_get_job_by_id(job_1.id).job_status == 'pending'
|
|
|
|
|
assert dao_get_job_by_id(job_2.id).job_status == 'pending'
|
|
|
|
|
assert dao_get_job_by_id(job_2.id).job_status == 'pending'
|
|
|
|
|
|
|
|
|
|
mocked.assert_has_calls([
|
2017-05-25 10:51:49 +01:00
|
|
|
call([str(job_3.id)], queue="job-tasks"),
|
|
|
|
|
call([str(job_2.id)], queue="job-tasks"),
|
|
|
|
|
call([str(job_1.id)], queue="job-tasks")
|
2016-08-24 17:03:56 +01:00
|
|
|
])
|
2016-09-07 15:36:59 +01:00
|
|
|
|
|
|
|
|
|
2019-11-13 17:01:03 +00:00
|
|
|
@freeze_time('2017-05-01 14:00:00')
|
|
|
|
|
def test_switch_current_sms_provider_on_slow_delivery_switches_when_one_provider_is_slow(
|
|
|
|
|
mocker,
|
|
|
|
|
restore_provider_details,
|
2017-02-13 15:46:06 +00:00
|
|
|
):
|
2019-11-13 17:01:03 +00:00
|
|
|
is_slow_dict = {'mmg': False, 'firetext': True}
|
|
|
|
|
mock_is_slow = mocker.patch('app.celery.scheduled_tasks.is_delivery_slow_for_providers', return_value=is_slow_dict)
|
|
|
|
|
mock_reduce = mocker.patch('app.celery.scheduled_tasks.dao_reduce_sms_provider_priority')
|
|
|
|
|
# updated_at times are older than the 10 minute window
|
|
|
|
|
get_provider_details_by_identifier('mmg').updated_at = datetime(2017, 5, 1, 13, 49)
|
|
|
|
|
get_provider_details_by_identifier('firetext').updated_at = None
|
|
|
|
|
|
|
|
|
|
switch_current_sms_provider_on_slow_delivery()
|
|
|
|
|
|
|
|
|
|
mock_is_slow.assert_called_once_with(
|
|
|
|
|
threshold=0.3,
|
|
|
|
|
created_at=datetime(2017, 5, 1, 13, 50),
|
|
|
|
|
delivery_time=timedelta(minutes=4)
|
|
|
|
|
)
|
2019-11-20 17:23:39 +00:00
|
|
|
mock_reduce.assert_called_once_with('firetext', time_threshold=timedelta(minutes=10))
|
2019-11-13 17:01:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@freeze_time('2017-05-01 14:00:00')
|
|
|
|
|
@pytest.mark.parametrize('is_slow_dict', [
|
|
|
|
|
{'mmg': False, 'firetext': False},
|
|
|
|
|
{'mmg': True, 'firetext': True},
|
|
|
|
|
])
|
|
|
|
|
def test_switch_current_sms_provider_on_slow_delivery_does_nothing_if_no_need(
|
|
|
|
|
mocker,
|
|
|
|
|
restore_provider_details,
|
|
|
|
|
is_slow_dict
|
|
|
|
|
):
|
|
|
|
|
mocker.patch('app.celery.scheduled_tasks.is_delivery_slow_for_providers', return_value=is_slow_dict)
|
|
|
|
|
mock_reduce = mocker.patch('app.celery.scheduled_tasks.dao_reduce_sms_provider_priority')
|
|
|
|
|
get_provider_details_by_identifier('mmg').updated_at = datetime(2017, 5, 1, 13, 51)
|
|
|
|
|
|
|
|
|
|
switch_current_sms_provider_on_slow_delivery()
|
|
|
|
|
|
|
|
|
|
assert mock_reduce.called is False
|
2017-05-11 15:22:57 +01:00
|
|
|
|
|
|
|
|
|
2017-05-16 13:47:22 +01:00
|
|
|
@freeze_time("2017-05-01 14:00:00")
|
2017-05-25 11:41:07 +01:00
|
|
|
def test_should_send_all_scheduled_notifications_to_deliver_queue(sample_template, mocker):
|
2017-05-16 13:47:22 +01:00
|
|
|
mocked = mocker.patch('app.celery.provider_tasks.deliver_sms')
|
2017-05-25 11:41:07 +01:00
|
|
|
message_to_deliver = create_notification(template=sample_template, scheduled_for="2017-05-01 13:15")
|
|
|
|
|
create_notification(template=sample_template, scheduled_for="2017-05-01 10:15", status='delivered')
|
|
|
|
|
create_notification(template=sample_template)
|
|
|
|
|
create_notification(template=sample_template, scheduled_for="2017-05-01 14:15")
|
2017-05-16 13:47:22 +01:00
|
|
|
|
2017-05-22 15:07:16 +01:00
|
|
|
scheduled_notifications = dao_get_scheduled_notifications()
|
|
|
|
|
assert len(scheduled_notifications) == 1
|
|
|
|
|
|
2017-05-16 13:47:22 +01:00
|
|
|
send_scheduled_notifications()
|
|
|
|
|
|
2017-07-20 16:17:04 +01:00
|
|
|
mocked.apply_async.assert_called_once_with([str(message_to_deliver.id)], queue='send-sms-tasks')
|
2017-05-22 15:07:16 +01:00
|
|
|
scheduled_notifications = dao_get_scheduled_notifications()
|
|
|
|
|
assert not scheduled_notifications
|
2017-05-22 14:05:57 +01:00
|
|
|
|
|
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
def test_check_job_status_task_raises_job_incomplete_error(mocker, sample_template):
|
|
|
|
|
mock_celery = mocker.patch('app.celery.tasks.notify_celery.send_task')
|
2017-10-12 16:21:08 +01:00
|
|
|
job = create_job(template=sample_template, notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS)
|
|
|
|
|
create_notification(template=sample_template, job=job)
|
|
|
|
|
with pytest.raises(expected_exception=JobIncompleteError) as e:
|
|
|
|
|
check_job_status()
|
|
|
|
|
assert e.value.message == "Job(s) ['{}'] have not completed.".format(str(job.id))
|
|
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
mock_celery.assert_called_once_with(
|
|
|
|
|
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
|
|
|
|
args=([str(job.id)],),
|
|
|
|
|
queue=QueueNames.JOBS
|
|
|
|
|
)
|
|
|
|
|
|
2017-10-12 16:21:08 +01:00
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
def test_check_job_status_task_raises_job_incomplete_error_when_scheduled_job_is_not_complete(mocker, sample_template):
|
|
|
|
|
mock_celery = mocker.patch('app.celery.tasks.notify_celery.send_task')
|
2017-10-12 16:21:08 +01:00
|
|
|
job = create_job(template=sample_template, notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS)
|
|
|
|
|
with pytest.raises(expected_exception=JobIncompleteError) as e:
|
|
|
|
|
check_job_status()
|
|
|
|
|
assert e.value.message == "Job(s) ['{}'] have not completed.".format(str(job.id))
|
|
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
mock_celery.assert_called_once_with(
|
|
|
|
|
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
|
|
|
|
args=([str(job.id)],),
|
|
|
|
|
queue=QueueNames.JOBS
|
|
|
|
|
)
|
|
|
|
|
|
2017-10-12 16:21:08 +01:00
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
def test_check_job_status_task_raises_job_incomplete_error_for_multiple_jobs(mocker, sample_template):
|
|
|
|
|
mock_celery = mocker.patch('app.celery.tasks.notify_celery.send_task')
|
2017-10-12 16:21:08 +01:00
|
|
|
job = create_job(template=sample_template, notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS)
|
|
|
|
|
job_2 = create_job(template=sample_template, notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS)
|
|
|
|
|
with pytest.raises(expected_exception=JobIncompleteError) as e:
|
|
|
|
|
check_job_status()
|
|
|
|
|
assert str(job.id) in e.value.message
|
|
|
|
|
assert str(job_2.id) in e.value.message
|
|
|
|
|
|
2017-10-13 16:46:17 +01:00
|
|
|
mock_celery.assert_called_once_with(
|
|
|
|
|
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
2017-10-18 09:50:39 +01:00
|
|
|
args=([str(job.id), str(job_2.id)],),
|
2017-10-13 16:46:17 +01:00
|
|
|
queue=QueueNames.JOBS
|
|
|
|
|
)
|
2017-11-09 10:32:39 +00:00
|
|
|
|
|
|
|
|
|
2018-03-09 16:30:50 +00:00
|
|
|
def test_check_job_status_task_only_sends_old_tasks(mocker, sample_template):
|
|
|
|
|
mock_celery = mocker.patch('app.celery.tasks.notify_celery.send_task')
|
|
|
|
|
job = create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS
|
|
|
|
|
)
|
|
|
|
|
job_2 = create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=29),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS
|
|
|
|
|
)
|
|
|
|
|
with pytest.raises(expected_exception=JobIncompleteError) as e:
|
|
|
|
|
check_job_status()
|
|
|
|
|
assert str(job.id) in e.value.message
|
|
|
|
|
assert str(job_2.id) not in e.value.message
|
|
|
|
|
|
|
|
|
|
# job 2 not in celery task
|
|
|
|
|
mock_celery.assert_called_once_with(
|
|
|
|
|
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
|
|
|
|
args=([str(job.id)],),
|
|
|
|
|
queue=QueueNames.JOBS
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2018-03-09 16:34:47 +00:00
|
|
|
def test_check_job_status_task_sets_jobs_to_error(mocker, sample_template):
|
|
|
|
|
mock_celery = mocker.patch('app.celery.tasks.notify_celery.send_task')
|
|
|
|
|
job = create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS
|
|
|
|
|
)
|
|
|
|
|
job_2 = create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=29),
|
|
|
|
|
job_status=JOB_STATUS_IN_PROGRESS
|
|
|
|
|
)
|
|
|
|
|
with pytest.raises(expected_exception=JobIncompleteError) as e:
|
|
|
|
|
check_job_status()
|
|
|
|
|
assert str(job.id) in e.value.message
|
|
|
|
|
assert str(job_2.id) not in e.value.message
|
|
|
|
|
|
|
|
|
|
# job 2 not in celery task
|
|
|
|
|
mock_celery.assert_called_once_with(
|
|
|
|
|
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
|
|
|
|
args=([str(job.id)],),
|
|
|
|
|
queue=QueueNames.JOBS
|
|
|
|
|
)
|
|
|
|
|
assert job.job_status == JOB_STATUS_ERROR
|
|
|
|
|
assert job_2.job_status == JOB_STATUS_IN_PROGRESS
|
|
|
|
|
|
|
|
|
|
|
2018-03-23 15:38:35 +00:00
|
|
|
def test_replay_created_notifications(notify_db_session, sample_service, mocker):
|
|
|
|
|
email_delivery_queue = mocker.patch('app.celery.provider_tasks.deliver_email.apply_async')
|
|
|
|
|
sms_delivery_queue = mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async')
|
|
|
|
|
|
|
|
|
|
sms_template = create_template(service=sample_service, template_type='sms')
|
|
|
|
|
email_template = create_template(service=sample_service, template_type='email')
|
2019-11-21 15:51:27 +00:00
|
|
|
older_than = (60 * 60) + (60 * 15) # 1 hour 15 minutes
|
2018-03-23 15:38:35 +00:00
|
|
|
# notifications expected to be resent
|
|
|
|
|
old_sms = create_notification(template=sms_template, created_at=datetime.utcnow() - timedelta(seconds=older_than),
|
|
|
|
|
status='created')
|
|
|
|
|
old_email = create_notification(template=email_template,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(seconds=older_than),
|
|
|
|
|
status='created')
|
|
|
|
|
# notifications that are not to be resent
|
|
|
|
|
create_notification(template=sms_template, created_at=datetime.utcnow() - timedelta(seconds=older_than),
|
|
|
|
|
status='sending')
|
|
|
|
|
create_notification(template=email_template, created_at=datetime.utcnow() - timedelta(seconds=older_than),
|
|
|
|
|
status='delivered')
|
|
|
|
|
create_notification(template=sms_template, created_at=datetime.utcnow(),
|
|
|
|
|
status='created')
|
|
|
|
|
create_notification(template=email_template, created_at=datetime.utcnow(),
|
|
|
|
|
status='created')
|
|
|
|
|
|
|
|
|
|
replay_created_notifications()
|
|
|
|
|
email_delivery_queue.assert_called_once_with([str(old_email.id)],
|
|
|
|
|
queue='send-email-tasks')
|
|
|
|
|
sms_delivery_queue.assert_called_once_with([str(old_sms.id)],
|
|
|
|
|
queue="send-sms-tasks")
|
2019-01-14 17:22:41 +00:00
|
|
|
|
|
|
|
|
|
2019-11-19 16:04:21 +00:00
|
|
|
def test_replay_created_notifications_create_letters_pdf_tasks_for_letters_not_ready_to_send(
|
2019-11-13 16:39:59 +00:00
|
|
|
sample_letter_template, mocker
|
|
|
|
|
):
|
2019-11-19 16:04:21 +00:00
|
|
|
mock_task = mocker.patch('app.celery.scheduled_tasks.create_letters_pdf.apply_async')
|
2019-11-13 16:39:59 +00:00
|
|
|
create_notification(template=sample_letter_template, billable_units=0,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=4))
|
|
|
|
|
|
2019-11-21 15:51:27 +00:00
|
|
|
create_notification(template=sample_letter_template, billable_units=0,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(minutes=20))
|
2019-11-13 16:39:59 +00:00
|
|
|
notification_1 = create_notification(template=sample_letter_template, billable_units=0,
|
2019-11-21 15:51:27 +00:00
|
|
|
created_at=datetime.utcnow() - timedelta(hours=1, minutes=20))
|
2019-11-13 16:39:59 +00:00
|
|
|
notification_2 = create_notification(template=sample_letter_template, billable_units=0,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=5))
|
|
|
|
|
|
|
|
|
|
replay_created_notifications()
|
|
|
|
|
|
2019-11-19 16:04:21 +00:00
|
|
|
calls = [call([notification_1.id], queue=QueueNames.LETTERS),
|
|
|
|
|
call([notification_2.id], queue=QueueNames.LETTERS),
|
|
|
|
|
]
|
|
|
|
|
mock_task.assert_has_calls(calls, any_order=True)
|
2019-11-13 16:39:59 +00:00
|
|
|
|
|
|
|
|
|
2019-01-14 17:22:41 +00:00
|
|
|
def test_check_job_status_task_does_not_raise_error(sample_template):
|
|
|
|
|
create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(hours=2),
|
|
|
|
|
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_FINISHED)
|
|
|
|
|
create_job(
|
|
|
|
|
template=sample_template,
|
|
|
|
|
notification_count=3,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
|
|
|
|
job_status=JOB_STATUS_FINISHED)
|
|
|
|
|
|
|
|
|
|
check_job_status()
|
2019-06-11 13:16:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@freeze_time("2019-05-30 14:00:00")
|
|
|
|
|
def test_check_precompiled_letter_state(mocker, sample_letter_template):
|
|
|
|
|
mock_logger = mocker.patch('app.celery.tasks.current_app.logger.exception')
|
2019-06-17 13:52:36 +01:00
|
|
|
mock_create_ticket = mocker.patch('app.celery.nightly_tasks.zendesk_client.create_ticket')
|
2019-06-11 13:16:34 +01:00
|
|
|
|
|
|
|
|
create_notification(template=sample_letter_template,
|
|
|
|
|
status=NOTIFICATION_PENDING_VIRUS_CHECK,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(seconds=5400))
|
|
|
|
|
create_notification(template=sample_letter_template,
|
|
|
|
|
status=NOTIFICATION_DELIVERED,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(seconds=6000))
|
|
|
|
|
noti_1 = create_notification(template=sample_letter_template,
|
|
|
|
|
status=NOTIFICATION_PENDING_VIRUS_CHECK,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(seconds=5401))
|
|
|
|
|
noti_2 = create_notification(template=sample_letter_template,
|
|
|
|
|
status=NOTIFICATION_PENDING_VIRUS_CHECK,
|
|
|
|
|
created_at=datetime.utcnow() - timedelta(seconds=70000))
|
|
|
|
|
|
|
|
|
|
check_precompiled_letter_state()
|
|
|
|
|
|
2019-06-17 13:52:36 +01:00
|
|
|
message = "2 precompiled letters have been pending-virus-check for over 90 minutes. " \
|
|
|
|
|
"Notifications: ['{}', '{}']".format(noti_2.id, noti_1.id)
|
|
|
|
|
|
|
|
|
|
mock_logger.assert_called_once_with(message)
|
|
|
|
|
mock_create_ticket.assert_called_with(
|
|
|
|
|
message=message,
|
|
|
|
|
subject='[test] Letters still pending virus check',
|
|
|
|
|
ticket_type='incident'
|
2019-06-11 13:16:34 +01:00
|
|
|
)
|
2019-06-11 15:13:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@freeze_time("2019-05-30 14:00:00")
|
|
|
|
|
def test_check_templated_letter_state_during_bst(mocker, sample_letter_template):
|
|
|
|
|
mock_logger = mocker.patch('app.celery.tasks.current_app.logger.exception')
|
2019-06-17 13:52:36 +01:00
|
|
|
mock_create_ticket = mocker.patch('app.celery.nightly_tasks.zendesk_client.create_ticket')
|
2019-06-11 15:13:06 +01:00
|
|
|
|
2019-11-13 16:39:59 +00:00
|
|
|
noti_1 = create_notification(template=sample_letter_template, created_at=datetime(2019, 5, 1, 12, 0))
|
|
|
|
|
noti_2 = create_notification(template=sample_letter_template, created_at=datetime(2019, 5, 29, 16, 29))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 5, 29, 16, 30))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 5, 29, 17, 29))
|
|
|
|
|
create_notification(template=sample_letter_template, status='delivered', created_at=datetime(2019, 5, 28, 10, 0))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 5, 30, 10, 0))
|
2019-06-11 15:13:06 +01:00
|
|
|
|
|
|
|
|
check_templated_letter_state()
|
|
|
|
|
|
2019-06-17 13:52:36 +01:00
|
|
|
message = "2 letters were created before 17.30 yesterday and still have 'created' status. " \
|
|
|
|
|
"Notifications: ['{}', '{}']".format(noti_1.id, noti_2.id)
|
|
|
|
|
|
|
|
|
|
mock_logger.assert_called_once_with(message)
|
|
|
|
|
mock_create_ticket.assert_called_with(
|
|
|
|
|
message=message,
|
|
|
|
|
subject="[test] Letters still in 'created' status",
|
|
|
|
|
ticket_type='incident'
|
2019-06-11 15:13:06 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@freeze_time("2019-01-30 14:00:00")
|
|
|
|
|
def test_check_templated_letter_state_during_utc(mocker, sample_letter_template):
|
|
|
|
|
mock_logger = mocker.patch('app.celery.tasks.current_app.logger.exception')
|
2019-11-13 16:39:59 +00:00
|
|
|
mock_create_ticket = mocker.patch('app.celery.scheduled_tasks.zendesk_client.create_ticket')
|
|
|
|
|
|
|
|
|
|
noti_1 = create_notification(template=sample_letter_template, created_at=datetime(2018, 12, 1, 12, 0))
|
|
|
|
|
noti_2 = create_notification(template=sample_letter_template, created_at=datetime(2019, 1, 29, 17, 29))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 1, 29, 17, 30))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 1, 29, 18, 29))
|
|
|
|
|
create_notification(template=sample_letter_template, status='delivered', created_at=datetime(2019, 1, 29, 10, 0))
|
|
|
|
|
create_notification(template=sample_letter_template, created_at=datetime(2019, 1, 30, 10, 0))
|
2019-06-11 15:13:06 +01:00
|
|
|
|
|
|
|
|
check_templated_letter_state()
|
|
|
|
|
|
2019-06-17 13:52:36 +01:00
|
|
|
message = "2 letters were created before 17.30 yesterday and still have 'created' status. " \
|
|
|
|
|
"Notifications: ['{}', '{}']".format(noti_1.id, noti_2.id)
|
|
|
|
|
|
|
|
|
|
mock_logger.assert_called_once_with(message)
|
|
|
|
|
mock_create_ticket.assert_called_with(
|
|
|
|
|
message=message,
|
|
|
|
|
subject="[test] Letters still in 'created' status",
|
|
|
|
|
ticket_type='incident'
|
2019-06-11 15:13:06 +01:00
|
|
|
)
|
2019-11-05 16:47:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_check_for_missing_rows_in_completed_jobs(mocker, sample_email_template):
|
2019-11-15 15:32:16 +00:00
|
|
|
mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
|
|
|
|
return_value=(load_example_csv('multiple_email'), {"sender_id": None}))
|
2019-11-05 16:47:00 +00:00
|
|
|
mocker.patch('app.encryption.encrypt', return_value="something_encrypted")
|
|
|
|
|
process_row = mocker.patch('app.celery.scheduled_tasks.process_row')
|
|
|
|
|
|
|
|
|
|
job = create_job(template=sample_email_template,
|
|
|
|
|
notification_count=5,
|
|
|
|
|
job_status=JOB_STATUS_FINISHED,
|
|
|
|
|
processing_finished=datetime.utcnow() - timedelta(minutes=11))
|
|
|
|
|
for i in range(0, 4):
|
|
|
|
|
create_notification(job=job, job_row_number=i)
|
|
|
|
|
|
|
|
|
|
check_for_missing_rows_in_completed_jobs()
|
|
|
|
|
|
|
|
|
|
process_row.assert_called_once_with(
|
2019-11-15 15:32:16 +00:00
|
|
|
mock.ANY, mock.ANY, job, job.service, sender_id=None
|
2019-11-05 16:47:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_check_for_missing_rows_in_completed_jobs_calls_save_email(mocker, sample_email_template):
|
2019-11-15 15:32:16 +00:00
|
|
|
mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
|
|
|
|
return_value=(load_example_csv('multiple_email'), {'sender_id': None}))
|
2019-11-05 16:47:00 +00:00
|
|
|
save_email_task = mocker.patch('app.celery.tasks.save_email.apply_async')
|
|
|
|
|
mocker.patch('app.encryption.encrypt', return_value="something_encrypted")
|
|
|
|
|
mocker.patch('app.celery.tasks.create_uuid', return_value='uuid')
|
|
|
|
|
|
|
|
|
|
job = create_job(template=sample_email_template,
|
|
|
|
|
notification_count=5,
|
|
|
|
|
job_status=JOB_STATUS_FINISHED,
|
|
|
|
|
processing_finished=datetime.utcnow() - timedelta(minutes=11))
|
|
|
|
|
for i in range(0, 4):
|
|
|
|
|
create_notification(job=job, job_row_number=i)
|
|
|
|
|
|
|
|
|
|
check_for_missing_rows_in_completed_jobs()
|
|
|
|
|
save_email_task.assert_called_once_with(
|
|
|
|
|
(
|
|
|
|
|
str(job.service_id),
|
|
|
|
|
"uuid",
|
|
|
|
|
"something_encrypted",
|
|
|
|
|
),
|
|
|
|
|
{},
|
|
|
|
|
queue="database-tasks"
|
|
|
|
|
)
|
2019-11-15 15:32:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_check_for_missing_rows_in_completed_jobs_uses_sender_id(mocker, sample_email_template, fake_uuid):
|
|
|
|
|
mocker.patch('app.celery.tasks.s3.get_job_and_metadata_from_s3',
|
|
|
|
|
return_value=(load_example_csv('multiple_email'), {'sender_id': fake_uuid}))
|
|
|
|
|
mock_process_row = mocker.patch('app.celery.scheduled_tasks.process_row')
|
|
|
|
|
|
|
|
|
|
job = create_job(template=sample_email_template,
|
|
|
|
|
notification_count=5,
|
|
|
|
|
job_status=JOB_STATUS_FINISHED,
|
|
|
|
|
processing_finished=datetime.utcnow() - timedelta(minutes=11))
|
|
|
|
|
for i in range(0, 4):
|
|
|
|
|
create_notification(job=job, job_row_number=i)
|
|
|
|
|
|
|
|
|
|
check_for_missing_rows_in_completed_jobs()
|
|
|
|
|
mock_process_row.assert_called_once_with(
|
|
|
|
|
mock.ANY, mock.ANY, job, job.service, sender_id=fake_uuid
|
|
|
|
|
)
|
2019-11-29 21:24:17 +00:00
|
|
|
|
|
|
|
|
|
2019-12-03 10:26:59 +00:00
|
|
|
MockServicesSendingToTVNumbers = namedtuple(
|
|
|
|
|
'ServicesSendingToTVNumbers',
|
|
|
|
|
[
|
|
|
|
|
'service_id',
|
|
|
|
|
'service_name',
|
|
|
|
|
'notification_count',
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("failure_rates, sms_to_tv_numbers, expected_message", [
|
2019-11-29 21:24:17 +00:00
|
|
|
[
|
2019-12-03 16:18:07 +00:00
|
|
|
[{"id": "123", "permanent_failure_rate": 0.3}],
|
2019-12-03 10:26:59 +00:00
|
|
|
[],
|
2019-11-29 21:24:17 +00:00
|
|
|
"1 service(s) have had high permanent-failure rates for sms messages in last "
|
2019-12-03 10:26:59 +00:00
|
|
|
"24 hours:\nservice id: 123 failure rate: 0.3,\n"
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
[],
|
|
|
|
|
[MockServicesSendingToTVNumbers("123", "Service 1", 300)],
|
|
|
|
|
"1 service(s) have sent over 100 sms messages to tv numbers in last 24 hours:\n"
|
|
|
|
|
"service id: 123, count of sms to tv numbers: 300,\n"
|
2019-11-29 21:24:17 +00:00
|
|
|
]
|
|
|
|
|
])
|
|
|
|
|
def test_check_for_services_with_high_failure_rates_or_sending_to_tv_numbers(
|
2019-12-03 10:26:59 +00:00
|
|
|
mocker, notify_db_session, failure_rates, sms_to_tv_numbers, expected_message
|
2019-11-29 21:24:17 +00:00
|
|
|
):
|
|
|
|
|
mock_logger = mocker.patch('app.celery.tasks.current_app.logger.exception')
|
|
|
|
|
mock_create_ticket = mocker.patch('app.celery.scheduled_tasks.zendesk_client.create_ticket')
|
|
|
|
|
mock_failure_rates = mocker.patch(
|
|
|
|
|
'app.celery.scheduled_tasks.get_services_with_high_failure_rates', return_value=failure_rates
|
|
|
|
|
)
|
2019-12-03 10:26:59 +00:00
|
|
|
mock_sms_to_tv_numbers = mocker.patch(
|
|
|
|
|
'app.celery.scheduled_tasks.dao_find_services_sending_to_tv_numbers', return_value=sms_to_tv_numbers
|
|
|
|
|
)
|
2019-11-29 21:24:17 +00:00
|
|
|
|
2019-12-03 16:18:07 +00:00
|
|
|
zendesk_actions = "\nThings to do: contact service? revoke their key?"
|
|
|
|
|
|
2019-11-29 21:24:17 +00:00
|
|
|
check_for_services_with_high_failure_rates_or_sending_to_tv_numbers()
|
|
|
|
|
|
|
|
|
|
assert mock_failure_rates.called
|
2019-12-03 10:26:59 +00:00
|
|
|
assert mock_sms_to_tv_numbers.called
|
2019-11-29 21:24:17 +00:00
|
|
|
mock_logger.assert_called_once_with(expected_message)
|
|
|
|
|
mock_create_ticket.assert_called_with(
|
2019-12-03 16:18:07 +00:00
|
|
|
message=expected_message + zendesk_actions,
|
2019-11-29 21:24:17 +00:00
|
|
|
subject="[test] High failure rates for sms spotted for services",
|
|
|
|
|
ticket_type='incident'
|
|
|
|
|
)
|