mirror of
https://github.com/GSA/notifications-api.git
synced 2025-12-15 09:42:38 -05:00
Delete old 'process-virus-scan-passed-task'
This has been replaced by a new task, `sanitise-letter`, to this deletes all the code in the old task and ensures that when antivirus is not enabled locally we are calling the new task.
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import math
|
||||
import base64
|
||||
from datetime import datetime, timedelta
|
||||
from uuid import UUID
|
||||
from hashlib import sha512
|
||||
from base64 import urlsafe_b64encode
|
||||
|
||||
@@ -13,7 +11,6 @@ from requests import (
|
||||
)
|
||||
from celery.exceptions import MaxRetriesExceededError
|
||||
from notifications_utils.statsd_decorators import statsd
|
||||
from notifications_utils.s3 import s3upload
|
||||
from notifications_utils.letter_timings import LETTER_PROCESSING_DEADLINE
|
||||
from notifications_utils.timezones import convert_utc_to_bst
|
||||
|
||||
@@ -32,10 +29,8 @@ from app.letters.utils import get_letter_pdf_filename
|
||||
from app.errors import VirusScanError
|
||||
from app.exceptions import NotificationTechnicalFailureException
|
||||
from app.letters.utils import (
|
||||
copy_redaction_failed_pdf,
|
||||
get_billable_units_for_letter_page_count,
|
||||
get_reference_from_filename,
|
||||
get_folder_name,
|
||||
upload_letter_pdf,
|
||||
ScanErrorType,
|
||||
move_failed_pdf,
|
||||
@@ -213,72 +208,6 @@ def group_letters(letter_pdfs):
|
||||
yield list_of_files
|
||||
|
||||
|
||||
@notify_celery.task(bind=True, name='process-virus-scan-passed', max_retries=15, default_retry_delay=300)
|
||||
def process_virus_scan_passed(self, filename):
|
||||
reference = get_reference_from_filename(filename)
|
||||
notification = dao_get_notification_by_reference(reference)
|
||||
current_app.logger.info('notification id {} Virus scan passed: {}'.format(notification.id, filename))
|
||||
|
||||
is_test_key = notification.key_type == KEY_TYPE_TEST
|
||||
|
||||
scan_pdf_object = s3.get_s3_object(current_app.config['LETTERS_SCAN_BUCKET_NAME'], filename)
|
||||
old_pdf = scan_pdf_object.get()['Body'].read()
|
||||
|
||||
sanitise_response, result = _sanitise_precompiled_pdf(self, notification, old_pdf)
|
||||
new_pdf = None
|
||||
if result == 'validation_passed':
|
||||
new_pdf = base64.b64decode(sanitise_response["file"].encode())
|
||||
|
||||
redaction_failed_message = sanitise_response.get("redaction_failed_message")
|
||||
if redaction_failed_message and not is_test_key:
|
||||
current_app.logger.info('{} for notification id {} ({})'.format(
|
||||
redaction_failed_message, notification.id, filename)
|
||||
)
|
||||
copy_redaction_failed_pdf(filename)
|
||||
|
||||
billable_units = get_billable_units_for_letter_page_count(sanitise_response.get("page_count"))
|
||||
|
||||
# TODO: Remove this once CYSP update their template to not cross over the margins
|
||||
if notification.service_id == UUID('fe44178f-3b45-4625-9f85-2264a36dd9ec'): # CYSP
|
||||
# Check your state pension submit letters with good addresses and notify tags, so just use their supplied pdf
|
||||
new_pdf = old_pdf
|
||||
|
||||
if result == 'validation_failed' and not new_pdf:
|
||||
current_app.logger.info('Invalid precompiled pdf received {} ({})'.format(notification.id, filename))
|
||||
_move_invalid_letter_and_update_status(
|
||||
notification=notification,
|
||||
filename=filename,
|
||||
scan_pdf_object=scan_pdf_object,
|
||||
message=sanitise_response["message"],
|
||||
invalid_pages=sanitise_response.get("invalid_pages"),
|
||||
page_count=sanitise_response.get("page_count")
|
||||
)
|
||||
return
|
||||
|
||||
current_app.logger.info('notification id {} ({}) sanitised and ready to send'.format(notification.id, filename))
|
||||
|
||||
try:
|
||||
_upload_pdf_to_test_or_live_pdf_bucket(
|
||||
new_pdf,
|
||||
filename,
|
||||
is_test_letter=is_test_key,
|
||||
created_at=notification.created_at
|
||||
)
|
||||
|
||||
update_letter_pdf_status(
|
||||
reference=reference,
|
||||
status=NOTIFICATION_DELIVERED if is_test_key else NOTIFICATION_CREATED,
|
||||
billable_units=billable_units,
|
||||
recipient_address=sanitise_response.get("recipient_address")
|
||||
)
|
||||
scan_pdf_object.delete()
|
||||
except BotoClientError:
|
||||
current_app.logger.exception(
|
||||
"Error uploading letter to live pdf bucket for notification: {}".format(notification.id)
|
||||
)
|
||||
update_notification_status_by_id(notification.id, NOTIFICATION_TECHNICAL_FAILURE)
|
||||
|
||||
|
||||
@notify_celery.task(bind=True, name='sanitise-letter', max_retries=15, default_retry_delay=300)
|
||||
def sanitise_letter(self, filename):
|
||||
try:
|
||||
@@ -412,60 +341,6 @@ def _move_invalid_letter_and_update_status(
|
||||
raise NotificationTechnicalFailureException
|
||||
|
||||
|
||||
def _upload_pdf_to_test_or_live_pdf_bucket(pdf_data, filename, is_test_letter, created_at):
|
||||
target_bucket_config = 'TEST_LETTERS_BUCKET_NAME' if is_test_letter else 'LETTERS_PDF_BUCKET_NAME'
|
||||
target_bucket_name = current_app.config[target_bucket_config]
|
||||
target_filename = get_folder_name(created_at, dont_use_sending_date=is_test_letter) + filename
|
||||
|
||||
s3upload(
|
||||
filedata=pdf_data,
|
||||
region=current_app.config['AWS_REGION'],
|
||||
bucket_name=target_bucket_name,
|
||||
file_location=target_filename
|
||||
)
|
||||
|
||||
|
||||
def _sanitise_precompiled_pdf(self, notification, precompiled_pdf):
|
||||
try:
|
||||
response = requests_post(
|
||||
'{}/precompiled/sanitise'.format(
|
||||
current_app.config['TEMPLATE_PREVIEW_API_HOST']
|
||||
),
|
||||
data=precompiled_pdf,
|
||||
headers={'Authorization': 'Token {}'.format(current_app.config['TEMPLATE_PREVIEW_API_KEY']),
|
||||
'Service-ID': str(notification.service_id),
|
||||
'Notification-ID': str(notification.id)}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json(), "validation_passed"
|
||||
except RequestException as ex:
|
||||
if ex.response is not None and ex.response.status_code == 400:
|
||||
message = "sanitise_precompiled_pdf validation error for notification: {}. ".format(notification.id)
|
||||
if response.json().get("message"):
|
||||
message += response.json()["message"]
|
||||
if response.json().get("invalid_pages"):
|
||||
message += (" on pages: " + ", ".join(map(str, response.json()["invalid_pages"])))
|
||||
|
||||
current_app.logger.info(
|
||||
message
|
||||
)
|
||||
return response.json(), "validation_failed"
|
||||
|
||||
try:
|
||||
current_app.logger.exception(
|
||||
"sanitise_precompiled_pdf failed for notification: {}".format(notification.id)
|
||||
)
|
||||
self.retry(queue=QueueNames.RETRY)
|
||||
except MaxRetriesExceededError:
|
||||
current_app.logger.error(
|
||||
"RETRY FAILED: sanitise_precompiled_pdf failed for notification {}".format(notification.id),
|
||||
)
|
||||
|
||||
notification.status = NOTIFICATION_TECHNICAL_FAILURE
|
||||
dao_update_notification(notification)
|
||||
raise
|
||||
|
||||
|
||||
@notify_celery.task(name='process-virus-scan-failed')
|
||||
def process_virus_scan_failed(filename):
|
||||
move_failed_pdf(filename, ScanErrorType.FAILURE)
|
||||
@@ -529,9 +404,9 @@ def replay_letters_in_error(filename=None):
|
||||
)
|
||||
else:
|
||||
# stub out antivirus in dev
|
||||
process_virus_scan_passed.apply_async(
|
||||
kwargs={'filename': filename},
|
||||
queue=QueueNames.LETTERS,
|
||||
sanitise_letter.apply_async(
|
||||
[filename],
|
||||
queue=QueueNames.LETTERS
|
||||
)
|
||||
else:
|
||||
error_files = get_file_names_from_error_bucket()
|
||||
@@ -548,7 +423,7 @@ def replay_letters_in_error(filename=None):
|
||||
)
|
||||
else:
|
||||
# stub out antivirus in dev
|
||||
process_virus_scan_passed.apply_async(
|
||||
kwargs={'filename': moved_file_name},
|
||||
queue=QueueNames.LETTERS,
|
||||
sanitise_letter.apply_async(
|
||||
[filename],
|
||||
queue=QueueNames.LETTERS
|
||||
)
|
||||
|
||||
@@ -114,14 +114,6 @@ def move_failed_pdf(source_filename, scan_error_type):
|
||||
_move_s3_object(scan_bucket, source_filename, scan_bucket, target_filename)
|
||||
|
||||
|
||||
def copy_redaction_failed_pdf(source_filename):
|
||||
scan_bucket = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
|
||||
target_filename = 'REDACTION_FAILURE/' + source_filename
|
||||
|
||||
_copy_s3_object(scan_bucket, source_filename, scan_bucket, target_filename)
|
||||
|
||||
|
||||
def move_error_pdf_to_scan_bucket(source_filename):
|
||||
scan_bucket = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
error_file = 'ERROR/' + source_filename
|
||||
@@ -213,22 +205,6 @@ def _move_s3_object(source_bucket, source_filename, target_bucket, target_filena
|
||||
source_bucket, source_filename, target_bucket, target_filename))
|
||||
|
||||
|
||||
def _copy_s3_object(source_bucket, source_filename, target_bucket, target_filename):
|
||||
s3 = boto3.resource('s3')
|
||||
copy_source = {'Bucket': source_bucket, 'Key': source_filename}
|
||||
|
||||
target_bucket = s3.Bucket(target_bucket)
|
||||
obj = target_bucket.Object(target_filename)
|
||||
|
||||
# Tags are copied across but the expiration time is reset in the destination bucket
|
||||
# e.g. if a file has 5 days left to expire on a ONE_WEEK retention in the source bucket,
|
||||
# in the destination bucket the expiration time will be reset to 7 days left to expire
|
||||
obj.copy(copy_source, ExtraArgs={'ServerSideEncryption': 'AES256'})
|
||||
|
||||
current_app.logger.info("Copied letter PDF: {}/{} to {}/{}".format(
|
||||
source_bucket, source_filename, target_bucket, target_filename))
|
||||
|
||||
|
||||
def letter_print_day(created_at):
|
||||
bst_print_datetime = convert_utc_to_bst(created_at) + timedelta(hours=6, minutes=30)
|
||||
bst_print_date = bst_print_datetime.date()
|
||||
|
||||
@@ -17,7 +17,7 @@ from app import (
|
||||
encryption,
|
||||
DATETIME_FORMAT
|
||||
)
|
||||
from app.celery.letters_pdf_tasks import create_letters_pdf, process_virus_scan_passed
|
||||
from app.celery.letters_pdf_tasks import create_letters_pdf, sanitise_letter
|
||||
from app.celery.research_mode_tasks import create_fake_letter_response_file
|
||||
from app.celery.tasks import save_api_email
|
||||
from app.clients.document_download import DocumentDownloadError
|
||||
@@ -407,9 +407,9 @@ def process_precompiled_letter_notifications(*, letter_data, api_key, template,
|
||||
)
|
||||
else:
|
||||
# stub out antivirus in dev
|
||||
process_virus_scan_passed.apply_async(
|
||||
kwargs={'filename': filename},
|
||||
queue=QueueNames.LETTERS,
|
||||
sanitise_letter.apply_async(
|
||||
[filename],
|
||||
queue=QueueNames.LETTERS
|
||||
)
|
||||
|
||||
return notification
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from unittest.mock import Mock, call, ANY
|
||||
from unittest.mock import call
|
||||
|
||||
import base64
|
||||
import boto3
|
||||
from datetime import datetime, timedelta
|
||||
from moto import mock_s3
|
||||
@@ -9,7 +8,7 @@ from freezegun import freeze_time
|
||||
import pytest
|
||||
import requests_mock
|
||||
from botocore.exceptions import ClientError
|
||||
from celery.exceptions import MaxRetriesExceededError, Retry
|
||||
from celery.exceptions import MaxRetriesExceededError
|
||||
from requests import RequestException
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
@@ -23,13 +22,11 @@ from app.celery.letters_pdf_tasks import (
|
||||
get_key_and_size_of_letters_to_be_sent_to_print,
|
||||
group_letters,
|
||||
process_sanitised_letter,
|
||||
process_virus_scan_passed,
|
||||
process_virus_scan_failed,
|
||||
process_virus_scan_error,
|
||||
replay_letters_in_error,
|
||||
sanitise_letter,
|
||||
_move_invalid_letter_and_update_status,
|
||||
_sanitise_precompiled_pdf
|
||||
)
|
||||
from app.config import QueueNames, TaskNames
|
||||
from app.letters.utils import ScanErrorType
|
||||
@@ -53,7 +50,6 @@ from tests.conftest import set_config_values
|
||||
def test_should_have_decorated_tasks_functions():
|
||||
assert create_letters_pdf.__wrapped__.__name__ == 'create_letters_pdf'
|
||||
assert collate_letter_pdfs_to_be_sent.__wrapped__.__name__ == 'collate_letter_pdfs_to_be_sent'
|
||||
assert process_virus_scan_passed.__wrapped__.__name__ == 'process_virus_scan_passed'
|
||||
assert process_virus_scan_failed.__wrapped__.__name__ == 'process_virus_scan_failed'
|
||||
assert process_virus_scan_error.__wrapped__.__name__ == 'process_virus_scan_error'
|
||||
assert sanitise_letter.__wrapped__.__name__ == 'sanitise_letter'
|
||||
@@ -521,256 +517,6 @@ def test_group_letters_with_no_letters():
|
||||
assert list(group_letters([])) == []
|
||||
|
||||
|
||||
@freeze_time('2018-01-01 18:00')
|
||||
@mock_s3
|
||||
@pytest.mark.parametrize('key_type,noti_status,bucket_config_name,destination_folder', [
|
||||
(KEY_TYPE_NORMAL, NOTIFICATION_CREATED, 'LETTERS_PDF_BUCKET_NAME', '2018-01-02/'),
|
||||
(KEY_TYPE_TEST, NOTIFICATION_DELIVERED, 'TEST_LETTERS_BUCKET_NAME', '')
|
||||
])
|
||||
def test_process_letter_task_check_virus_scan_passed(
|
||||
sample_letter_template, mocker, key_type, noti_status, bucket_config_name, destination_folder
|
||||
):
|
||||
letter_notification = create_notification(template=sample_letter_template, billable_units=0,
|
||||
status='pending-virus-check', key_type=key_type,
|
||||
reference='{} letter'.format(key_type))
|
||||
filename = 'NOTIFY.{}'.format(letter_notification.reference)
|
||||
source_bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
target_bucket_name = current_app.config[bucket_config_name]
|
||||
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
conn.create_bucket(Bucket=source_bucket_name)
|
||||
conn.create_bucket(Bucket=target_bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=source_bucket_name, Key=filename, Body=b'old_pdf')
|
||||
|
||||
mock_s3upload = mocker.patch('app.celery.letters_pdf_tasks.s3upload')
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json={
|
||||
"file": base64.b64encode(b"new_pdf").decode("utf-8"),
|
||||
"recipient_address": "Bugs Bunny",
|
||||
"validation_passed": True,
|
||||
"message": "",
|
||||
"invalid_pages": [],
|
||||
"page_count": 1
|
||||
},
|
||||
status_code=200
|
||||
)
|
||||
process_virus_scan_passed(filename)
|
||||
|
||||
assert letter_notification.status == noti_status
|
||||
assert letter_notification.billable_units == 1
|
||||
assert rmock.called
|
||||
assert rmock.request_history[0].url == endpoint
|
||||
|
||||
mock_s3upload.assert_called_once_with(
|
||||
bucket_name=target_bucket_name,
|
||||
filedata=b'new_pdf',
|
||||
file_location=destination_folder + filename,
|
||||
region='eu-west-1',
|
||||
)
|
||||
|
||||
|
||||
@freeze_time('2018-01-01 18:00')
|
||||
@mock_s3
|
||||
@pytest.mark.parametrize('key_type', [KEY_TYPE_NORMAL, KEY_TYPE_TEST])
|
||||
def test_process_letter_task_check_virus_scan_passed_when_sanitise_fails(
|
||||
sample_letter_notification, mocker, key_type
|
||||
):
|
||||
filename = 'NOTIFY.{}'.format(sample_letter_notification.reference)
|
||||
source_bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
target_bucket_name = current_app.config['INVALID_PDF_BUCKET_NAME']
|
||||
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
conn.create_bucket(Bucket=source_bucket_name)
|
||||
conn.create_bucket(Bucket=target_bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=source_bucket_name, Key=filename, Body=b'pdf_content')
|
||||
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
sample_letter_notification.key_type = key_type
|
||||
mock_move_s3 = mocker.patch('app.letters.utils._move_s3_object')
|
||||
sanitise_response = {
|
||||
"file": base64.b64encode(b"nyan").decode("utf-8"),
|
||||
"validation_passed": False,
|
||||
"message": "content-outside-printable-area",
|
||||
"invalid_pages": [1, 2],
|
||||
"page_count": 2
|
||||
}
|
||||
mock_sanitise = mocker.patch(
|
||||
'app.celery.letters_pdf_tasks._sanitise_precompiled_pdf', return_value=(sanitise_response, "validation_failed")
|
||||
)
|
||||
|
||||
process_virus_scan_passed(filename)
|
||||
|
||||
assert sample_letter_notification.status == NOTIFICATION_VALIDATION_FAILED
|
||||
assert sample_letter_notification.billable_units == 0
|
||||
mock_sanitise.assert_called_once_with(
|
||||
ANY,
|
||||
sample_letter_notification,
|
||||
b'pdf_content'
|
||||
)
|
||||
mock_move_s3.assert_called_once_with(
|
||||
source_bucket=source_bucket_name, source_filename=filename,
|
||||
target_bucket=target_bucket_name, target_filename=filename, metadata={
|
||||
"message": "content-outside-printable-area",
|
||||
"invalid_pages": "[1, 2]",
|
||||
"page_count": "2"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@freeze_time('2018-01-01 18:00')
|
||||
@mock_s3
|
||||
@pytest.mark.parametrize('key_type,notification_status,bucket_config_name', [
|
||||
(KEY_TYPE_NORMAL, NOTIFICATION_CREATED, 'LETTERS_PDF_BUCKET_NAME'),
|
||||
(KEY_TYPE_TEST, NOTIFICATION_DELIVERED, 'TEST_LETTERS_BUCKET_NAME')
|
||||
])
|
||||
def test_process_letter_task_check_virus_scan_passed_when_redaction_fails(
|
||||
sample_letter_notification, mocker, key_type, notification_status, bucket_config_name
|
||||
):
|
||||
filename = 'NOTIFY.{}'.format(sample_letter_notification.reference)
|
||||
bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
target_bucket_name = current_app.config[bucket_config_name]
|
||||
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
conn.create_bucket(Bucket=bucket_name)
|
||||
conn.create_bucket(Bucket=target_bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=bucket_name, Key=filename, Body=b'pdf_content')
|
||||
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
sample_letter_notification.key_type = key_type
|
||||
mock_copy_s3 = mocker.patch('app.letters.utils._copy_s3_object')
|
||||
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json={
|
||||
"file": base64.b64encode(b"new_pdf").decode("utf-8"),
|
||||
"validation_passed": True,
|
||||
"redaction_failed_message": "No matches for address block during redaction procedure",
|
||||
"message": "",
|
||||
"invalid_pages": "",
|
||||
"page_count": 3
|
||||
},
|
||||
status_code=200
|
||||
)
|
||||
process_virus_scan_passed(filename)
|
||||
|
||||
assert sample_letter_notification.billable_units == 2
|
||||
assert sample_letter_notification.status == notification_status
|
||||
if key_type == KEY_TYPE_NORMAL:
|
||||
mock_copy_s3.assert_called_once_with(
|
||||
bucket_name, filename,
|
||||
bucket_name, 'REDACTION_FAILURE/' + filename
|
||||
)
|
||||
else:
|
||||
mock_copy_s3.assert_not_called()
|
||||
|
||||
|
||||
@freeze_time('2018-01-01 18:00')
|
||||
@mock_s3
|
||||
@pytest.mark.parametrize('key_type', [KEY_TYPE_NORMAL, KEY_TYPE_TEST])
|
||||
def test_process_letter_task_check_virus_scan_passed_when_file_cannot_be_opened(
|
||||
sample_letter_notification, mocker, key_type
|
||||
):
|
||||
filename = 'NOTIFY.{}'.format(sample_letter_notification.reference)
|
||||
source_bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
target_bucket_name = current_app.config['INVALID_PDF_BUCKET_NAME']
|
||||
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
conn.create_bucket(Bucket=source_bucket_name)
|
||||
conn.create_bucket(Bucket=target_bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=source_bucket_name, Key=filename, Body=b'pdf_content')
|
||||
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
sample_letter_notification.key_type = key_type
|
||||
mock_move_s3 = mocker.patch('app.letters.utils._move_s3_object')
|
||||
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json={
|
||||
"page_count": None,
|
||||
"recipient_address": None,
|
||||
"message": 'unable-to-read-the-file',
|
||||
"invalid_pages": None,
|
||||
"file": None
|
||||
},
|
||||
status_code=400
|
||||
)
|
||||
process_virus_scan_passed(filename)
|
||||
|
||||
mock_move_s3.assert_called_once_with(
|
||||
source_bucket=source_bucket_name, source_filename=filename,
|
||||
target_bucket=target_bucket_name, target_filename=filename, metadata={'message': 'unable-to-read-the-file'}
|
||||
)
|
||||
assert sample_letter_notification.status == NOTIFICATION_VALIDATION_FAILED
|
||||
assert sample_letter_notification.billable_units == 0
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_process_virus_scan_passed_logs_error_and_sets_tech_failure_if_s3_error_uploading_to_live_bucket(
|
||||
mocker,
|
||||
sample_letter_notification,
|
||||
):
|
||||
mock_logger = mocker.patch('app.celery.tasks.current_app.logger.exception')
|
||||
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
filename = 'NOTIFY.{}'.format(sample_letter_notification.reference)
|
||||
|
||||
source_bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
conn.create_bucket(Bucket=source_bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=source_bucket_name, Key=filename, Body=b'pdf_content')
|
||||
|
||||
error_response = {
|
||||
'Error': {
|
||||
'Code': 'InvalidParameterValue',
|
||||
'Message': 'some error message from amazon',
|
||||
'Type': 'Sender'
|
||||
}
|
||||
}
|
||||
mocker.patch('app.celery.letters_pdf_tasks._upload_pdf_to_test_or_live_pdf_bucket',
|
||||
side_effect=ClientError(error_response, 'operation_name'))
|
||||
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json={
|
||||
"file": base64.b64encode(b"new_pdf").decode("utf-8"),
|
||||
"validation_passed": True,
|
||||
"message": "",
|
||||
"invalid_pages": [],
|
||||
"page_count": 1
|
||||
},
|
||||
status_code=200
|
||||
)
|
||||
process_virus_scan_passed(filename)
|
||||
|
||||
assert sample_letter_notification.status == NOTIFICATION_TECHNICAL_FAILURE
|
||||
mock_logger.assert_called_once_with(
|
||||
'Error uploading letter to live pdf bucket for notification: {}'.format(sample_letter_notification.id)
|
||||
)
|
||||
|
||||
|
||||
def test_move_invalid_letter_and_update_status_logs_error_and_sets_tech_failure_state_if_s3_error(
|
||||
mocker,
|
||||
sample_letter_notification,
|
||||
@@ -1087,100 +833,3 @@ def test_replay_letters_in_error_for_one_file(notify_api, mocker):
|
||||
replay_letters_in_error("file_name")
|
||||
mock_move.assert_called_once_with('file_name')
|
||||
mock_celery.assert_called_once_with(name='scan-file', kwargs={'filename': 'file_name'}, queue='antivirus-tasks')
|
||||
|
||||
|
||||
def test_sanitise_precompiled_pdf_returns_data_from_template_preview(rmock, sample_letter_notification):
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json={
|
||||
"file": base64.b64encode(b"new_pdf").decode("utf-8"),
|
||||
"validation_passed": True,
|
||||
"message": "",
|
||||
"invalid_pages": [],
|
||||
"page_count": 1
|
||||
},
|
||||
status_code=200
|
||||
)
|
||||
mock_celery = Mock(**{'retry.side_effect': Retry})
|
||||
response, result = _sanitise_precompiled_pdf(mock_celery, sample_letter_notification, b'old_pdf')
|
||||
assert rmock.called
|
||||
assert rmock.request_history[0].url == endpoint
|
||||
|
||||
assert result == "validation_passed"
|
||||
assert base64.b64decode(response["file"].encode()) == b"new_pdf"
|
||||
assert rmock.last_request.text == 'old_pdf'
|
||||
|
||||
|
||||
def test_sanitise_precompiled_pdf_return_validation_error(rmock, sample_letter_notification):
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
|
||||
endpoint = 'http://localhost:9999/precompiled/sanitise'
|
||||
response_json = {
|
||||
"file": base64.b64encode(b"nyan").decode("utf-8"),
|
||||
"validation_passed": False,
|
||||
"message": "content-outside-printable-area",
|
||||
"invalid_pages": [1],
|
||||
"page_count": 1
|
||||
}
|
||||
with requests_mock.mock() as rmock:
|
||||
rmock.request(
|
||||
"POST",
|
||||
endpoint,
|
||||
json=response_json,
|
||||
status_code=400
|
||||
)
|
||||
mock_celery = Mock(**{'retry.side_effect': Retry})
|
||||
response, result = _sanitise_precompiled_pdf(mock_celery, sample_letter_notification, b'old_pdf')
|
||||
assert rmock.called
|
||||
assert rmock.request_history[0].url == endpoint
|
||||
|
||||
assert result == "validation_failed"
|
||||
assert response == response_json
|
||||
|
||||
|
||||
def test_sanitise_precompiled_pdf_passes_the_service_id_and_notification_id_to_template_preview(
|
||||
mocker,
|
||||
sample_letter_notification,
|
||||
):
|
||||
tp_mock = mocker.patch('app.celery.letters_pdf_tasks.requests_post')
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
mock_celery = Mock(**{'retry.side_effect': Retry})
|
||||
_sanitise_precompiled_pdf(mock_celery, sample_letter_notification, b'old_pdf')
|
||||
|
||||
service_id = str(sample_letter_notification.service_id)
|
||||
notification_id = str(sample_letter_notification.id)
|
||||
|
||||
tp_mock.assert_called_once_with(
|
||||
'http://localhost:9999/precompiled/sanitise',
|
||||
data=b'old_pdf',
|
||||
headers={'Authorization': 'Token my-secret-key',
|
||||
'Service-ID': service_id,
|
||||
'Notification-ID': notification_id}
|
||||
)
|
||||
|
||||
|
||||
def test_sanitise_precompiled_pdf_retries_on_http_error(rmock, sample_letter_notification):
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
rmock.post('http://localhost:9999/precompiled/sanitise', content=b'new_pdf', status_code=500)
|
||||
mock_celery = Mock(**{'retry.side_effect': Retry})
|
||||
|
||||
with pytest.raises(Retry):
|
||||
_sanitise_precompiled_pdf(mock_celery, sample_letter_notification, b'old_pdf')
|
||||
|
||||
|
||||
def test_sanitise_precompiled_pdf_sets_notification_to_technical_failure_after_too_many_errors(
|
||||
rmock,
|
||||
sample_letter_notification
|
||||
):
|
||||
sample_letter_notification.status = NOTIFICATION_PENDING_VIRUS_CHECK
|
||||
rmock.post('http://localhost:9999/precompiled/sanitise', content=b'new_pdf', status_code=500)
|
||||
mock_celery = Mock(**{'retry.side_effect': MaxRetriesExceededError})
|
||||
|
||||
with pytest.raises(MaxRetriesExceededError):
|
||||
_sanitise_precompiled_pdf(mock_celery, sample_letter_notification, b'old_pdf')
|
||||
|
||||
assert sample_letter_notification.status == NOTIFICATION_TECHNICAL_FAILURE
|
||||
|
||||
@@ -7,7 +7,6 @@ from freezegun import freeze_time
|
||||
from moto import mock_s3
|
||||
|
||||
from app.letters.utils import (
|
||||
copy_redaction_failed_pdf,
|
||||
get_bucket_name_and_prefix_for_notification,
|
||||
get_letter_pdf_filename,
|
||||
get_letter_pdf_and_metadata,
|
||||
@@ -294,24 +293,6 @@ def test_move_failed_pdf_scan_failed(notify_api):
|
||||
assert filename not in [o.key for o in bucket.objects.all()]
|
||||
|
||||
|
||||
@mock_s3
|
||||
@freeze_time(FROZEN_DATE_TIME)
|
||||
def test_copy_redaction_failed_pdf(notify_api):
|
||||
filename = 'test.pdf'
|
||||
bucket_name = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||
|
||||
conn = boto3.resource('s3', region_name='eu-west-1')
|
||||
bucket = conn.create_bucket(Bucket=bucket_name)
|
||||
|
||||
s3 = boto3.client('s3', region_name='eu-west-1')
|
||||
s3.put_object(Bucket=bucket_name, Key=filename, Body=b'pdf_content')
|
||||
|
||||
copy_redaction_failed_pdf(filename)
|
||||
|
||||
assert 'REDACTION_FAILURE/' + filename in [o.key for o in bucket.objects.all()]
|
||||
assert filename in [o.key for o in bucket.objects.all()]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freeze_date, expected_folder_name",
|
||||
[("2018-04-01 17:50:00", "2018-04-02/"),
|
||||
("2018-07-02 16:29:00", "2018-07-02/"),
|
||||
|
||||
Reference in New Issue
Block a user