def test_get_notifications_renames_letter_statuses(client,
                                                   sample_letter_template,
                                                   db_status, expected_status):
    letter_noti = create_notification(sample_letter_template,
                                      status=db_status,
                                      personalisation={
                                          'address_line_1': 'Mr Foo',
                                          'address_line_2': '1 Bar Street',
                                          'postcode': 'N1'
                                      })
    auth_header = create_authorization_header(
        service_id=letter_noti.service_id)
    response = client.get(
        path=url_for('v2_notifications.get_notification_by_id',
                     notification_id=letter_noti.id),
        headers=[('Content-Type', 'application/json'), auth_header])

    json_response = json.loads(response.get_data(as_text=True))
    assert response.status_code == 200
    assert json_response['status'] == expected_status
示例#2
0
def test_upload_letter_pdf_uses_postage_from_notification(
        sample_letter_template, mocker, postage, expected_postage):
    letter_notification = create_notification(template=sample_letter_template,
                                              postage=postage)
    mock_s3 = mocker.patch('app.letters.utils.s3upload')

    filename = generate_letter_pdf_filename(
        reference=letter_notification.reference,
        crown=letter_notification.service.crown,
        created_at=letter_notification.created_at,
        ignore_folder=False,
        postage=letter_notification.postage)

    upload_letter_pdf(letter_notification, b'\x00\x01', precompiled=False)

    mock_s3.assert_called_once_with(
        bucket_name=current_app.config['LETTERS_PDF_BUCKET_NAME'],
        file_location=filename,
        filedata=b'\x00\x01',
        region=current_app.config['AWS_REGION'])
def test_notification_raises_a_retry_exception_if_mlwr_state_is_not_complete(
        sample_email_template, mocker):
    mocker.patch('app.aws_ses_client.send_email', return_value='reference')
    mocker.patch('app.delivery.send_to_providers.check_mlwr',
                 return_value={"state": "foo"})
    personalisation = {
        "file": {
            "document": {
                "mlwr_sid": "foo",
                "direct_file_url": "http://foo.bar",
                "url": "http://foo.bar"
            }
        }
    }

    db_notification = create_notification(template=sample_email_template,
                                          personalisation=personalisation)

    with pytest.raises(MalwarePendingException):
        send_to_providers.send_email_to_provider(db_notification, )
示例#4
0
def test_ses_callback_does_not_call_send_delivery_status_if_no_db_entry(
        client, notify_db_session, sample_email_template, mocker):
    with freeze_time('2001-01-01T12:00:00'):

        send_mock = mocker.patch(
            'app.celery.service_callback_tasks.send_delivery_status_to_service.apply_async'
        )
        notification = create_notification(
            template=sample_email_template,
            status='sending',
            reference='ref',
        )

        assert get_notification_by_id(notification.id).status == 'sending'

        assert process_ses_receipts_tasks.process_ses_results(
            ses_notification_callback(reference='ref'))
        assert get_notification_by_id(notification.id).status == 'delivered'

        send_mock.assert_not_called()
示例#5
0
def test_preview_letter_template_precompiled_png_file_type_hide_notify_tag_only_on_first_page(
        notify_api,
        client,
        admin_request,
        sample_service,
        mocker,
        page_number,
        expect_preview_url
):

    template = create_template(sample_service,
                               template_type='letter',
                               template_name='Pre-compiled PDF',
                               subject='Pre-compiled PDF',
                               hidden=True)

    notification = create_notification(template)

    with set_config_values(notify_api, {
        'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview',
        'TEMPLATE_PREVIEW_API_KEY': 'test-key'
    }):
        pdf_content = b'\x00\x01'
        png_content = b'\x00\x02'
        encoded = base64.b64encode(png_content).decode('utf-8')

        mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content)
        mocker.patch('app.template.rest.extract_page_from_pdf', return_value=png_content)
        mock_get_png_preview = mocker.patch('app.template.rest._get_png_preview', return_value=encoded)

        admin_request.get(
            'template.preview_letter_template_by_notification_id',
            service_id=notification.service_id,
            notification_id=notification.id,
            file_type='png',
            page=page_number
        )

        mock_get_png_preview.assert_called_once_with(
            expect_preview_url, encoded, notification.id, json=False
        )
示例#6
0
def test_find_missing_row_for_job_more_than_one_missing_row(
        sample_email_template):
    job = create_job(template=sample_email_template,
                     notification_count=5,
                     job_status=JOB_STATUS_FINISHED,
                     processing_finished=datetime.utcnow() -
                     timedelta(minutes=11))
    create_notification(job=job, job_row_number=0)
    create_notification(job=job, job_row_number=1)
    create_notification(job=job, job_row_number=4)

    results = find_missing_row_for_job(job.id, 5)
    assert len(results) == 2
    assert results[0].missing_row == 2
    assert results[1].missing_row == 3
def test_alert_if_letter_notifications_still_sending_only_alerts_sending(sample_letter_template, mocker):
    two_days_ago = datetime(2018, 1, 15, 13, 30)
    create_notification(template=sample_letter_template, status='sending', sent_at=two_days_ago)
    create_notification(template=sample_letter_template, status='delivered', sent_at=two_days_ago)
    create_notification(template=sample_letter_template, status='failed', sent_at=two_days_ago)

    mock_create_ticket = mocker.patch("app.celery.nightly_tasks.zendesk_client.create_ticket")

    raise_alert_if_letter_notifications_still_sending()

    mock_create_ticket.assert_called_once_with(
        subject="[test] Letters still sending",
        message="There are 1 letters in the 'sending' state from Monday 15 January",
        ticket_type='incident'
    )
def test_upload_letter_pdf_uses_postage_from_notification(
        sample_letter_template, mocker, postage, expected_postage):
    letter_notification = create_notification(template=sample_letter_template,
                                              postage=postage)
    mock_s3 = mocker.patch("app.letters.utils.s3upload")

    filename = get_letter_pdf_filename(
        reference=letter_notification.reference,
        crown=letter_notification.service.crown,
        is_scan_letter=False,
        postage=letter_notification.postage,
    )

    upload_letter_pdf(letter_notification, b"\x00\x01", precompiled=False)

    mock_s3.assert_called_once_with(
        bucket_name=current_app.config["LETTERS_PDF_BUCKET_NAME"],
        file_location=filename,
        filedata=b"\x00\x01",
        region=current_app.config["AWS_REGION"],
    )
示例#9
0
def test_send_delivery_status_to_service_succeeds_if_sent_at_is_none(
        notify_db_session,
        mocker
):
    callback_api, template = _set_up_test_data('email', "delivery_status")
    datestr = datetime(2017, 6, 20)
    notification = create_notification(template=template,
                                       created_at=datestr,
                                       updated_at=datestr,
                                       sent_at=None,
                                       status='technical-failure'
                                       )
    encrypted_data = _set_up_data_for_status_update(callback_api, notification)
    mocked = mocker.patch('app.celery.service_callback_tasks.send_delivery_status_to_service.retry')
    with requests_mock.Mocker() as request_mock:
        request_mock.post(callback_api.url,
                          json={},
                          status_code=404)
        send_delivery_status_to_service(notification.id, encrypted_status_update=encrypted_data)

    assert mocked.call_count == 0
示例#10
0
def test_get_notification_by_reference_returns_200(client, sample_template):
    sample_notification_with_reference = create_notification(
        template=sample_template, client_reference='some-client-reference')

    auth_header = create_authorization_header(
        service_id=sample_notification_with_reference.service_id)
    response = client.get(path='/v2/notifications?reference={}'.format(
        sample_notification_with_reference.client_reference),
                          headers=[('Content-Type', 'application/json'),
                                   auth_header])

    assert response.status_code == 200
    assert response.headers['Content-type'] == 'application/json'

    json_response = json.loads(response.get_data(as_text=True))
    assert len(json_response['notifications']) == 1

    assert json_response['notifications'][0]['id'] == str(
        sample_notification_with_reference.id)
    assert json_response['notifications'][0][
        'reference'] == "some-client-reference"
示例#11
0
def test_should_send_sms_with_downgraded_content(notify_db_session, mocker):
    # é, o, and u are in GSM.
    # ī, grapes, tabs, zero width space and ellipsis are not
    # ó isn't in GSM, but it is in the welsh alphabet so will still be sent
    msg = "a é ī o u 🍇 foo\tbar\u200bbaz((misc))…"
    placeholder = '∆∆∆abc'
    gsm_message = "?ódz Housing Service: a é i o u ? foo barbaz???abc..."
    service = create_service(service_name='Łódź Housing Service')
    template = create_template(service, content=msg)
    db_notification = create_notification(
        template=template, personalisation={'misc': placeholder})

    res = Mock(content=json.dumps({'sid': 1}))
    mocker.patch('app.twilio_client.send_sms', return_value=res)

    send_to_providers.send_sms_to_provider(db_notification)

    twilio_client.send_sms.assert_called_once_with(to=ANY,
                                                   content=gsm_message,
                                                   reference=ANY,
                                                   sender=ANY)
def test_should_send_sms_with_downgraded_content(notify_db_session, mock_sms_client):
    # é, o, and u are in GSM.
    # á, ï, grapes, tabs, zero width space and ellipsis are not
    msg = "á é ï o u � foo\tbar\u200bbaz((misc))…"
    placeholder = '∆∆∆abc'
    gsm_message = "?odz Housing Service: a é i o u ? foo barbaz???abc..."
    service = create_service(service_name='�ódź Housing Service', prefix_sms=True)
    template = create_template(service, content=msg)
    db_notification = create_notification(
        template=template,
        personalisation={'misc': placeholder}
    )

    send_to_providers.send_sms_to_provider(db_notification)

    mock_sms_client.send_sms.assert_called_once_with(
        to=ANY,
        content=gsm_message,
        reference=ANY,
        sender=ANY
    )
示例#13
0
def test_notification_raises_error_if_message_contains_sin_pii_that_passes_luhn(
        sample_email_template_with_html, mocker, notify_api):
    send_mock = mocker.patch("app.aws_ses_client.send_email",
                             return_value='reference')

    db_notification = create_notification(
        template=sample_email_template_with_html,
        to_field="*****@*****.**",
        personalisation={'name': '046-454-286'})

    with set_config_values(notify_api, {
            'SCAN_FOR_PII': "True",
    }):
        with pytest.raises(NotificationTechnicalFailureException) as e:
            send_to_providers.send_email_to_provider(db_notification)
            assert db_notification.id in e.value

    send_mock.assert_not_called()

    assert Notification.query.get(
        db_notification.id).status == 'pii-check-failed'
示例#14
0
def test__send_data_to_service_callback_api_retries_if_request_returns_500_with_encrypted_data(
        notify_db_session, mocker, notification_type
):
    callback_api, template = _set_up_test_data(notification_type, "delivery_status")
    datestr = datetime(2017, 6, 20)
    notification = create_notification(template=template,
                                       created_at=datestr,
                                       updated_at=datestr,
                                       sent_at=datestr,
                                       status='sent'
                                       )
    encrypted_data = _set_up_data_for_status_update(callback_api, notification)
    mocked = mocker.patch('app.celery.service_callback_tasks.send_delivery_status_to_service.retry')
    with requests_mock.Mocker() as request_mock:
        request_mock.post(callback_api.url,
                          json={},
                          status_code=500)
        send_delivery_status_to_service(notification.id, encrypted_status_update=encrypted_data)

    assert mocked.call_count == 1
    assert mocked.call_args[1]['queue'] == 'retry-tasks'
def test_should_respect_custom_sending_domains(sample_service, mocker, sample_email_template_with_html):
    db_notification = create_notification(
        template=sample_email_template_with_html,
        to_field="*****@*****.**",
        personalisation={"name": "Jo"},
    )

    sample_service.sending_domain = "foo.bar"
    mocker.patch("app.aws_ses_client.send_email", return_value="reference")

    send_to_providers.send_email_to_provider(db_notification)

    app.aws_ses_client.send_email.assert_called_once_with(
        '"Sample service" <*****@*****.**>',
        "*****@*****.**",
        "Jo <em>some HTML</em>",
        body="Hello Jo\nThis is an email from GOV.\u200bUK with <em>some HTML</em>\n",
        html_body=ANY,
        reply_to_address=None,
        attachments=[],
    )
示例#16
0
def test_should_handle_sms_sender_and_prefix_message(
    mocker,
    sms_sender,
    prefix_sms,
    expected_sender,
    expected_content,
    notify_db_session
):
    mocker.patch('app.mmg_client.send_sms')
    service = create_service_with_defined_sms_sender(sms_sender_value=sms_sender, prefix_sms=prefix_sms)
    template = create_template(service, content='bar')
    notification = create_notification(template, reply_to_text=sms_sender)

    send_to_providers.send_sms_to_provider(notification)

    mmg_client.send_sms.assert_called_once_with(
        content=expected_content,
        sender=expected_sender,
        to=ANY,
        reference=ANY,
    )
示例#17
0
def test_ses_callback_should_set_status_to_temporary_failure(
        client, notify_db_session, sample_email_template, mocker):
    send_mock = mocker.patch(
        'app.celery.service_callback_tasks.send_delivery_status_to_service.apply_async'
    )
    mock_logger = mocker.patch(
        'app.celery.process_ses_receipts_tasks.current_app.logger.info')
    notification = create_notification(
        template=sample_email_template,
        status='sending',
        reference='ref',
    )
    create_service_callback_api(service=notification.service,
                                url="https://original_url.com")
    assert get_notification_by_id(notification.id).status == 'sending'
    assert process_ses_results(ses_soft_bounce_callback(reference='ref'))
    assert get_notification_by_id(
        notification.id).status == 'temporary-failure'
    assert send_mock.called
    assert f'SES bounce for notification ID {notification.id}: ' in mock_logger.call_args[
        0][0]
示例#18
0
def test_should_update_billable_units_and_status_according_to_research_mode_and_key_type(
    sample_template,
    mocker,
    research_mode,
    key_type,
    billable_units,
    expected_status
):
    notification = create_notification(template=sample_template, billable_units=0, status='created', key_type=key_type)
    mocker.patch('app.mmg_client.send_sms')
    mocker.patch('app.delivery.send_to_providers.send_sms_response',
                 side_effect=__update_notification(notification, research_mode, expected_status))

    if research_mode:
        sample_template.service.research_mode = True

    send_to_providers.send_sms_to_provider(
        notification
    )
    assert notification.billable_units == billable_units
    assert notification.status == expected_status
示例#19
0
def test_send_email_should_use_service_reply_to_email(
        sample_service,
        sample_email_template,
        mocker):
    mocker.patch('app.aws_ses_client.send_email', return_value='reference')

    db_notification = create_notification(template=sample_email_template, reply_to_text='*****@*****.**')
    create_reply_to_email(service=sample_service, email_address='*****@*****.**')

    send_to_providers.send_email_to_provider(
        db_notification,
    )

    app.aws_ses_client.send_email.assert_called_once_with(
        ANY,
        ANY,
        ANY,
        body=ANY,
        html_body=ANY,
        reply_to_address='*****@*****.**'
    )
示例#20
0
def test_notification_can_have_document_attachment_without_mlwr_sid(
        sample_email_template, mocker, mock_email_client,
        mocked_build_ga_pixel_url):
    mlwr_mock = mocker.patch('app.delivery.send_to_providers.check_mlwr')
    personalisation = {
        "file": {
            "document": {
                "id": "foo",
                "direct_file_url": "http://foo.bar",
                "url": "http://foo.bar"
            }
        }
    }

    db_notification = create_notification(template=sample_email_template,
                                          personalisation=personalisation)

    send_to_providers.send_email_to_provider(db_notification, )

    mock_email_client.send_email.assert_called()
    mlwr_mock.assert_not_called()
def test_should_send_sms_with_downgraded_content(notify_db_session, mock_sms_client):
    # é, o, and u are in GSM.
    # á, ï, grapes, tabs, zero width space and ellipsis are not
    msg = "á é ï o u 🍇 foo\tbar\u200bbaz((misc))…"
    placeholder = '∆∆∆abc'
    gsm_message = "?odz Housing Service: a é i o u ? foo barbaz???abc..."
    service = create_service(service_name='Łódź Housing Service')
    template = create_template(service, content=msg)
    db_notification = create_notification(
        template=template,
        personalisation={'misc': placeholder}
    )

    send_to_providers.send_sms_to_provider(db_notification)

    mock_sms_client.send_sms.assert_called_once_with(
        to=ANY,
        content=gsm_message,
        reference=ANY,
        sender=ANY
    )
def test_send_delivery_status_to_service_post_https_request_to_service_with_encrypted_data(
        notify_db_session, notification_type):

    callback_api, template = _set_up_test_data(notification_type,
                                               "delivery_status")
    datestr = datetime(2017, 6, 20)

    notification = create_notification(template=template,
                                       created_at=datestr,
                                       updated_at=datestr,
                                       sent_at=datestr,
                                       status='sent')
    encrypted_status_update = _set_up_data_for_status_update(
        callback_api, notification)
    with requests_mock.Mocker() as request_mock:
        request_mock.post(callback_api.url, json={}, status_code=200)
        send_delivery_status_to_service(
            notification.id, encrypted_status_update=encrypted_status_update)

    mock_data = {
        "id": str(notification.id),
        "reference": notification.client_reference,
        "to": notification.to,
        "status": notification.status,
        "created_at": datestr.strftime(DATETIME_FORMAT),
        "completed_at": datestr.strftime(DATETIME_FORMAT),
        "sent_at": datestr.strftime(DATETIME_FORMAT),
        "notification_type": notification_type,
        "template_id": str(template.id),
        "template_version": 1
    }

    assert request_mock.call_count == 1
    assert request_mock.request_history[0].url == callback_api.url
    assert request_mock.request_history[0].method == 'POST'
    assert request_mock.request_history[0].text == json.dumps(mock_data)
    assert request_mock.request_history[0].headers[
        "Content-type"] == "application/json"
    assert request_mock.request_history[0].headers[
        "Authorization"] == "Bearer {}".format(callback_api.bearer_token)
示例#23
0
def test_get_total_notifications_counts_messages_within_10_seconds(
        sample_template):
    created_at = datetime.utcnow()

    create_notification(sample_template,
                        sent_at=created_at + timedelta(seconds=5))
    create_notification(sample_template,
                        sent_at=created_at + timedelta(seconds=10))
    create_notification(sample_template,
                        sent_at=created_at + timedelta(seconds=15))

    result = dao_get_total_notifications_sent_per_day_for_performance_platform(
        BEGINNING_OF_DAY, END_OF_DAY)

    assert result.messages_total == 3
    assert result.messages_within_10_secs == 2
示例#24
0
def test_filter_by_status_and_template_type(client, sample_template, sample_email_template):
    create_notification(sample_template)
    create_notification(sample_email_template)
    create_notification(sample_email_template, status="delivered")

    auth_header = create_authorization_header(service_id=sample_email_template.service_id)

    response = client.get(
        '/notifications?template_type=email&status=delivered',
        headers=[auth_header])

    notifications = json.loads(response.get_data(as_text=True))
    assert response.status_code == 200
    assert len(notifications['notifications']) == 1
    assert notifications['notifications'][0]['template']['template_type'] == 'email'
    assert notifications['notifications'][0]['status'] == 'delivered'
示例#25
0
def test_populate_redis_template_usage_only_populates_for_today(
        mocker, notify_api, sample_template):
    mock_redis = mocker.patch('app.commands.redis_store')
    # created at in utc
    create_notification(sample_template,
                        created_at=datetime(2017, 6, 9, 23, 0, 0))
    create_notification(sample_template,
                        created_at=datetime(2017, 6, 9, 23, 0, 0))
    create_notification(sample_template,
                        created_at=datetime(2017, 6, 10, 0, 0, 0))
    create_notification(sample_template,
                        created_at=datetime(2017, 6, 10, 23, 0,
                                            0))  # actually on 11th BST

    with set_config(notify_api, 'REDIS_ENABLED', True):
        populate_redis_template_usage.callback.__wrapped__(
            sample_template.service_id, datetime(2017, 6, 10))

    mock_redis.set_hash_and_expire.assert_called_once_with(
        'service-{}-template-usage-2017-06-10'.format(
            sample_template.service_id), {str(sample_template.id): 3},
        notify_api.config['EXPIRE_CACHE_EIGHT_DAYS'],
        raise_exception=True)
def test_fetch_billing_data_for_today_includes_data_with_the_right_date(
        notify_db_session):
    process_day = datetime(2018, 4, 1, 13, 30, 0)
    service = create_service()
    template = create_template(service=service, template_type="email")
    create_notification(template=template,
                        status='delivered',
                        created_at=process_day)
    create_notification(template=template,
                        status='delivered',
                        created_at=datetime(2018, 4, 1, 4, 23, 23))

    create_notification(template=template,
                        status='delivered',
                        created_at=datetime(2018, 3, 31, 20, 23, 23))
    create_notification(template=template,
                        status='sending',
                        created_at=process_day + timedelta(days=1))

    day_under_test = convert_utc_to_local_timezone(process_day)
    results = fetch_billing_data_for_day(day_under_test)
    assert len(results) == 1
    assert results[0].notifications_sent == 2
def test_get_monthly_notification_stats_combines_todays_data_and_historic_stats(
        admin_request, sample_template):
    create_ft_notification_status(datetime(2016, 5, 1),
                                  template=sample_template,
                                  count=1)
    create_ft_notification_status(
        datetime(2016, 6, 1),
        template=sample_template,
        notification_status="created",
        count=2,
    )  # noqa

    create_notification(sample_template,
                        created_at=datetime(2016, 6, 5),
                        status="created")
    create_notification(sample_template,
                        created_at=datetime(2016, 6, 5),
                        status="delivered")

    # this doesn't get returned in the stats because it is old - it should be in ft_notification_status by now
    create_notification(sample_template,
                        created_at=datetime(2016, 6, 4),
                        status="sending")

    response = admin_request.get(
        "service.get_monthly_notification_stats",
        service_id=sample_template.service_id,
        year=2016,
    )

    assert len(response["data"]) == 3  # apr, may, jun
    assert response["data"]["2016-05"] == {
        "sms": {
            "delivered": 1
        },
        "email": {},
        "letter": {},
    }
    assert response["data"]["2016-06"] == {
        "sms": {
            # combines the stats from the historic ft_notification_status and the current notifications
            "created": 3,
            "delivered": 1,
        },
        "email": {},
        "letter": {},
    }
def test_send_sms_should_use_template_version_from_notification_not_latest(
        sample_template, mocker):
    db_notification = create_notification(
        template=sample_template,
        to_field='+447234123123',
        status='created',
        reply_to_text=sample_template.service.get_default_sms_sender(),
        normalised_to='447234123123')

    mocker.patch('app.mmg_client.send_sms')

    version_on_notification = sample_template.version

    # Change the template
    from app.dao.templates_dao import (
        dao_get_template_by_id,
        dao_update_template,
    )
    sample_template.content = sample_template.content + " another version of the template"
    dao_update_template(sample_template)
    t = dao_get_template_by_id(sample_template.id)
    assert t.version > version_on_notification

    send_to_providers.send_sms_to_provider(db_notification)

    mmg_client.send_sms.assert_called_once_with(
        to=validate_and_format_phone_number("+447234123123"),
        content="Sample service: This is a template:\nwith a newline",
        reference=str(db_notification.id),
        sender=current_app.config['FROM_NUMBER'])

    persisted_notification = notifications_dao.get_notification_by_id(
        db_notification.id)
    assert persisted_notification.to == db_notification.to
    assert persisted_notification.template_id == sample_template.id
    assert persisted_notification.template_version == version_on_notification
    assert persisted_notification.template_version != sample_template.version
    assert persisted_notification.status == 'sending'
    assert not persisted_notification.personalisation
示例#29
0
def test_get_notification_by_reference_returns_200(client, sample_template):
    sample_notification_with_reference = create_notification(
        template=sample_template, client_reference="some-client-reference")

    auth_header = create_authorization_header(
        service_id=sample_notification_with_reference.service_id)
    response = client.get(
        path="/v2/notifications?reference={}".format(
            sample_notification_with_reference.client_reference),
        headers=[("Content-Type", "application/json"), auth_header],
    )

    assert response.status_code == 200
    assert response.headers["Content-type"] == "application/json"

    json_response = json.loads(response.get_data(as_text=True))
    assert len(json_response["notifications"]) == 1

    assert json_response["notifications"][0]["id"] == str(
        sample_notification_with_reference.id)
    assert json_response["notifications"][0][
        "reference"] == "some-client-reference"
示例#30
0
def test_notification_can_have_document_attachment_without_mlwr_sid(
        sample_email_template, mocker):
    send_mock = mocker.patch('app.aws_ses_client.send_email',
                             return_value='reference')
    mlwr_mock = mocker.patch('app.delivery.send_to_providers.check_mlwr')
    personalisation = {
        "file": {
            "document": {
                "id": "foo",
                "direct_file_url": "http://foo.bar",
                "url": "http://foo.bar"
            }
        }
    }

    db_notification = create_notification(template=sample_email_template,
                                          personalisation=personalisation)

    send_to_providers.send_email_to_provider(db_notification, )

    send_mock.assert_called()
    mlwr_mock.assert_not_called()