mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-14 23:07:49 -04:00
Merge pull request #1313 from alphagov/rc_process_missing_rows_in_csv
Process Incomplete Jobs, if a job have been discovered to be incomplete.
This commit is contained in:
@@ -9,6 +9,7 @@ from freezegun import freeze_time
|
||||
|
||||
from app.celery import scheduled_tasks
|
||||
from app.celery.scheduled_tasks import (
|
||||
check_job_status,
|
||||
delete_dvla_response_files_older_than_seven_days,
|
||||
delete_email_notifications_older_than_seven_days,
|
||||
delete_inbound_sms_older_than_seven_days,
|
||||
@@ -22,14 +23,15 @@ from app.celery.scheduled_tasks import (
|
||||
run_scheduled_jobs,
|
||||
run_letter_jobs,
|
||||
run_letter_api_notifications,
|
||||
populate_monthly_billing,
|
||||
s3,
|
||||
send_daily_performance_platform_stats,
|
||||
send_scheduled_notifications,
|
||||
send_total_sent_notifications_to_performance_platform,
|
||||
switch_current_sms_provider_on_slow_delivery,
|
||||
timeout_job_statistics,
|
||||
timeout_notifications,
|
||||
populate_monthly_billing,
|
||||
send_total_sent_notifications_to_performance_platform, check_job_status)
|
||||
timeout_notifications
|
||||
)
|
||||
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
||||
from app.config import QueueNames, TaskNames
|
||||
from app.dao.jobs_dao import dao_get_job_by_id
|
||||
@@ -47,7 +49,8 @@ from app.models import (
|
||||
NOTIFICATION_PENDING,
|
||||
NOTIFICATION_CREATED,
|
||||
KEY_TYPE_TEST,
|
||||
MonthlyBilling, JOB_STATUS_FINISHED)
|
||||
MonthlyBilling
|
||||
)
|
||||
from app.utils import get_london_midnight_in_utc
|
||||
from app.v2.errors import JobIncompleteError
|
||||
from tests.app.db import create_notification, create_service, create_template, create_job, create_rate
|
||||
@@ -773,7 +776,8 @@ def test_run_letter_api_notifications_does_nothing_if_no_created_notifications(
|
||||
assert test_api_key_notification.status == NOTIFICATION_CREATED
|
||||
|
||||
|
||||
def test_check_job_status_task_raises_job_incomplete_error(sample_template):
|
||||
def test_check_job_status_task_raises_job_incomplete_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(minutes=31),
|
||||
processing_started=datetime.utcnow() - timedelta(minutes=31),
|
||||
@@ -783,8 +787,15 @@ def test_check_job_status_task_raises_job_incomplete_error(sample_template):
|
||||
check_job_status()
|
||||
assert e.value.message == "Job(s) ['{}'] have not completed.".format(str(job.id))
|
||||
|
||||
mock_celery.assert_called_once_with(
|
||||
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
||||
args=([str(job.id)],),
|
||||
queue=QueueNames.JOBS
|
||||
)
|
||||
|
||||
def test_check_job_status_task_raises_job_incomplete_error_when_scheduled_job_is_not_complete(sample_template):
|
||||
|
||||
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')
|
||||
job = create_job(template=sample_template, notification_count=3,
|
||||
created_at=datetime.utcnow() - timedelta(hours=2),
|
||||
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
||||
@@ -794,8 +805,15 @@ def test_check_job_status_task_raises_job_incomplete_error_when_scheduled_job_is
|
||||
check_job_status()
|
||||
assert e.value.message == "Job(s) ['{}'] have not completed.".format(str(job.id))
|
||||
|
||||
mock_celery.assert_called_once_with(
|
||||
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
||||
args=([str(job.id)],),
|
||||
queue=QueueNames.JOBS
|
||||
)
|
||||
|
||||
def test_check_job_status_task_raises_job_incomplete_error_for_multiple_jobs(sample_template):
|
||||
|
||||
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')
|
||||
job = create_job(template=sample_template, notification_count=3,
|
||||
created_at=datetime.utcnow() - timedelta(hours=2),
|
||||
scheduled_for=datetime.utcnow() - timedelta(minutes=31),
|
||||
@@ -811,15 +829,8 @@ def test_check_job_status_task_raises_job_incomplete_error_for_multiple_jobs(sam
|
||||
assert str(job.id) in e.value.message
|
||||
assert str(job_2.id) in e.value.message
|
||||
|
||||
|
||||
def test_check_job_status_task_does_not_raise_error(sample_template):
|
||||
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_FINISHED)
|
||||
job_2 = 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()
|
||||
mock_celery.assert_called_once_with(
|
||||
name=TaskNames.PROCESS_INCOMPLETE_JOBS,
|
||||
args=([str(job_2.id), str(job.id)],),
|
||||
queue=QueueNames.JOBS
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import Mock
|
||||
import pytest
|
||||
import requests_mock
|
||||
@@ -13,8 +13,8 @@ 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.scheduled_tasks import check_job_status
|
||||
from app.celery.tasks import (
|
||||
s3,
|
||||
build_dvla_file,
|
||||
create_dvla_file_contents_for_job,
|
||||
process_job,
|
||||
@@ -22,20 +22,26 @@ from app.celery.tasks import (
|
||||
send_sms,
|
||||
send_email,
|
||||
persist_letter,
|
||||
process_incomplete_job,
|
||||
process_incomplete_jobs,
|
||||
get_template_class,
|
||||
send_inbound_sms_to_service)
|
||||
s3,
|
||||
send_inbound_sms_to_service
|
||||
)
|
||||
from app.config import QueueNames
|
||||
from app.dao import jobs_dao, services_dao
|
||||
from app.models import (
|
||||
Job,
|
||||
Notification,
|
||||
EMAIL_TYPE,
|
||||
KEY_TYPE_NORMAL,
|
||||
KEY_TYPE_TEAM,
|
||||
KEY_TYPE_TEST,
|
||||
JOB_STATUS_FINISHED,
|
||||
JOB_STATUS_IN_PROGRESS,
|
||||
LETTER_TYPE,
|
||||
SERVICE_PERMISSION_TYPES,
|
||||
SMS_TYPE,
|
||||
Job,
|
||||
Notification
|
||||
SMS_TYPE
|
||||
)
|
||||
|
||||
from tests.app import load_example_csv
|
||||
@@ -1204,3 +1210,211 @@ def test_send_inbound_sms_to_service_does_not_retries_if_request_returns_404(not
|
||||
send_inbound_sms_to_service(inbound_sms.id, inbound_sms.service_id)
|
||||
|
||||
mocked.call_count == 0
|
||||
|
||||
|
||||
def test_check_job_status_task_does_not_raise_error(sample_template):
|
||||
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_FINISHED)
|
||||
job_2 = 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()
|
||||
|
||||
|
||||
def test_process_incomplete_job_sms(mocker, sample_template):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
|
||||
create_notification(sample_template, job, 0)
|
||||
create_notification(sample_template, job, 1)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 2
|
||||
|
||||
process_incomplete_job(str(job.id))
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert send_sms.call_count == 8 # There are 10 in the file and we've added two already
|
||||
|
||||
|
||||
def test_process_incomplete_job_with_notifications_all_sent(mocker, sample_template):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
mock_send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
|
||||
create_notification(sample_template, job, 0)
|
||||
create_notification(sample_template, job, 1)
|
||||
create_notification(sample_template, job, 2)
|
||||
create_notification(sample_template, job, 3)
|
||||
create_notification(sample_template, job, 4)
|
||||
create_notification(sample_template, job, 5)
|
||||
create_notification(sample_template, job, 6)
|
||||
create_notification(sample_template, job, 7)
|
||||
create_notification(sample_template, job, 8)
|
||||
create_notification(sample_template, job, 9)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 10
|
||||
|
||||
process_incomplete_job(str(job.id))
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert mock_send_sms.call_count == 0 # There are 10 in the file and we've added 10 it should not have been called
|
||||
|
||||
|
||||
def test_process_incomplete_jobs_sms(mocker, sample_template):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
mock_send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
create_notification(sample_template, job, 0)
|
||||
create_notification(sample_template, job, 1)
|
||||
create_notification(sample_template, job, 2)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 3
|
||||
|
||||
job2 = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
|
||||
create_notification(sample_template, job2, 0)
|
||||
create_notification(sample_template, job2, 1)
|
||||
create_notification(sample_template, job2, 2)
|
||||
create_notification(sample_template, job2, 3)
|
||||
create_notification(sample_template, job2, 4)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job2.id).count() == 5
|
||||
|
||||
jobs = [job.id, job2.id]
|
||||
process_incomplete_jobs(jobs)
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
completed_job2 = Job.query.filter(Job.id == job2.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert completed_job2.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert mock_send_sms.call_count == 12 # There are 20 in total over 2 jobs we've added 8 already
|
||||
|
||||
|
||||
def test_process_incomplete_jobs_no_notifications_added(mocker, sample_template):
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
mock_send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 0
|
||||
|
||||
process_incomplete_job(job.id)
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert mock_send_sms.call_count == 10 # There are 10 in the csv file
|
||||
|
||||
|
||||
def test_process_incomplete_jobs(mocker):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
mock_send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
jobs = []
|
||||
process_incomplete_jobs(jobs)
|
||||
|
||||
assert mock_send_sms.call_count == 0 # There are no jobs to process so it will not have been called
|
||||
|
||||
|
||||
def test_process_incomplete_job_no_job_in_database(mocker, fake_uuid):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_sms'))
|
||||
mock_send_sms = mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
|
||||
with pytest.raises(expected_exception=Exception) as e:
|
||||
process_incomplete_job(fake_uuid)
|
||||
|
||||
assert mock_send_sms.call_count == 0 # There is no job in the db it will not have been called
|
||||
|
||||
|
||||
def test_process_incomplete_job_email(mocker, sample_email_template):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_email'))
|
||||
mock_email_sender = mocker.patch('app.celery.tasks.send_email.apply_async')
|
||||
|
||||
job = create_job(template=sample_email_template, notification_count=10,
|
||||
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)
|
||||
|
||||
create_notification(sample_email_template, job, 0)
|
||||
create_notification(sample_email_template, job, 1)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 2
|
||||
|
||||
process_incomplete_job(str(job.id))
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert mock_email_sender.call_count == 8 # There are 10 in the file and we've added two already
|
||||
|
||||
|
||||
def test_process_incomplete_job_letter(mocker, sample_letter_template):
|
||||
|
||||
mocker.patch('app.celery.tasks.s3.get_job_from_s3', return_value=load_example_csv('multiple_letter'))
|
||||
mock_letter_sender = mocker.patch('app.celery.tasks.persist_letter.apply_async')
|
||||
|
||||
job = create_job(template=sample_letter_template, notification_count=10,
|
||||
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)
|
||||
|
||||
create_notification(sample_letter_template, job, 0)
|
||||
create_notification(sample_letter_template, job, 1)
|
||||
|
||||
assert Notification.query.filter(Notification.job_id == job.id).count() == 2
|
||||
|
||||
process_incomplete_job(str(job.id))
|
||||
|
||||
completed_job = Job.query.filter(Job.id == job.id).one()
|
||||
|
||||
assert completed_job.job_status == JOB_STATUS_FINISHED
|
||||
|
||||
assert mock_letter_sender.call_count == 8
|
||||
|
||||
@@ -22,8 +22,8 @@ from app.models import (
|
||||
NOTIFICATION_DELIVERED,
|
||||
KEY_TYPE_NORMAL,
|
||||
KEY_TYPE_TEAM,
|
||||
KEY_TYPE_TEST
|
||||
)
|
||||
KEY_TYPE_TEST,
|
||||
JOB_STATUS_IN_PROGRESS)
|
||||
|
||||
from app.dao.notifications_dao import (
|
||||
dao_create_notification,
|
||||
@@ -50,8 +50,8 @@ from app.dao.notifications_dao import (
|
||||
is_delivery_slow_for_provider,
|
||||
set_scheduled_notification_to_processed,
|
||||
update_notification_status_by_id,
|
||||
update_notification_status_by_reference
|
||||
)
|
||||
update_notification_status_by_reference,
|
||||
dao_get_last_notification_added_for_job_id)
|
||||
|
||||
from app.dao.services_dao import dao_update_service
|
||||
from tests.app.db import (
|
||||
@@ -2037,3 +2037,31 @@ def test_dao_get_notification_email_reply_for_notification(sample_service, sampl
|
||||
|
||||
def test_dao_get_notification_email_reply_for_notification_where_no_mapping(notify_db_session, fake_uuid):
|
||||
assert dao_get_notification_email_reply_for_notification(fake_uuid) is None
|
||||
|
||||
|
||||
def test_dao_get_last_notification_added_for_job_id_valid_job_id(sample_template):
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
create_notification(sample_template, job, 0)
|
||||
create_notification(sample_template, job, 1)
|
||||
last = create_notification(sample_template, job, 2)
|
||||
|
||||
assert dao_get_last_notification_added_for_job_id(job.id) == last
|
||||
|
||||
|
||||
def test_dao_get_last_notification_added_for_job_id_no_notifications(sample_template):
|
||||
job = create_job(template=sample_template, notification_count=10,
|
||||
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)
|
||||
|
||||
assert dao_get_last_notification_added_for_job_id(job.id) is None
|
||||
|
||||
|
||||
def test_dao_get_last_notification_added_for_job_id_no_notifications(sample_template, fake_uuid):
|
||||
|
||||
assert dao_get_last_notification_added_for_job_id(fake_uuid) is None
|
||||
|
||||
Reference in New Issue
Block a user