mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-11 09:28:27 -04:00
433 lines
12 KiB
Python
433 lines
12 KiB
Python
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
from flask import url_for
|
|
from freezegun import freeze_time
|
|
from hypothesis import HealthCheck, given, settings
|
|
from hypothesis import strategies as st
|
|
|
|
from tests import job_json
|
|
from tests.conftest import (
|
|
SERVICE_ONE_ID,
|
|
create_active_caseworking_user,
|
|
create_active_user_with_permissions,
|
|
normalize_spaces,
|
|
)
|
|
|
|
|
|
def test_old_jobs_hub_redirects(
|
|
client_request,
|
|
):
|
|
client_request.get(
|
|
"main.view_jobs",
|
|
service_id=SERVICE_ONE_ID,
|
|
_expected_status=302,
|
|
_expected_redirect=url_for(
|
|
"main.uploads",
|
|
service_id=SERVICE_ONE_ID,
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"user",
|
|
[
|
|
create_active_user_with_permissions(),
|
|
create_active_caseworking_user(),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
("status_argument", "expected_api_call"),
|
|
[
|
|
(
|
|
"",
|
|
[
|
|
"created",
|
|
"pending",
|
|
"sending",
|
|
"delivered",
|
|
"sent",
|
|
"failed",
|
|
"temporary-failure",
|
|
"permanent-failure",
|
|
"technical-failure",
|
|
"validation-failed",
|
|
],
|
|
),
|
|
("sending", ["sending", "created", "pending"]),
|
|
("delivered", ["delivered", "sent"]),
|
|
(
|
|
"failed",
|
|
[
|
|
"failed",
|
|
"temporary-failure",
|
|
"permanent-failure",
|
|
"technical-failure",
|
|
"validation-failed",
|
|
],
|
|
),
|
|
],
|
|
)
|
|
@freeze_time("2016-01-01 11:09:00.061258")
|
|
def test_should_show_page_for_one_job(
|
|
client_request,
|
|
mock_get_service_template,
|
|
mock_get_job,
|
|
mocker,
|
|
mock_get_notifications,
|
|
mock_get_service_data_retention,
|
|
fake_uuid,
|
|
status_argument,
|
|
expected_api_call,
|
|
user,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fake_uuid,
|
|
status=status_argument,
|
|
)
|
|
|
|
assert page.h1.text.strip() == "Message status"
|
|
assert page.select_one('[data-key="counts"]') is not None
|
|
assert page.select_one('[data-key="notifications"]') is not None
|
|
|
|
|
|
@freeze_time("2016-01-01 11:09:00.061258")
|
|
def test_should_show_page_for_one_job_with_flexible_data_retention(
|
|
client_request,
|
|
mock_get_service_template,
|
|
mock_get_job,
|
|
mock_get_service_data_retention,
|
|
fake_uuid,
|
|
):
|
|
mock_get_service_data_retention.side_effect = [
|
|
[{"days_of_retention": 10, "notification_type": "sms"}]
|
|
]
|
|
page = client_request.get(
|
|
"main.view_job", service_id=SERVICE_ONE_ID, job_id=fake_uuid, status="delivered"
|
|
)
|
|
|
|
assert page.select_one('[data-key="counts"]') is not None
|
|
|
|
|
|
def test_get_jobs_should_tell_user_if_more_than_one_page(
|
|
client_request,
|
|
fake_uuid,
|
|
service_one,
|
|
mock_get_job,
|
|
mock_get_service_template,
|
|
mock_get_service_data_retention,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
status="",
|
|
)
|
|
assert page.h1.text.strip() == "Message status"
|
|
|
|
|
|
def test_should_show_job_in_progress(
|
|
client_request,
|
|
service_one,
|
|
mock_get_service_template,
|
|
mock_get_job_in_progress,
|
|
fake_uuid,
|
|
mock_get_service_data_retention,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
)
|
|
assert page.h1.text.strip() == "Message status"
|
|
assert page.select_one('[data-key="counts"]') is not None
|
|
|
|
|
|
def test_should_show_job_without_notifications(
|
|
client_request,
|
|
service_one,
|
|
mock_get_service_template,
|
|
mock_get_job_in_progress,
|
|
fake_uuid,
|
|
mock_get_service_data_retention,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
)
|
|
assert page.h1.text.strip() == "Message status"
|
|
|
|
|
|
def test_should_show_job_with_sending_limit_exceeded_status(
|
|
client_request,
|
|
service_one,
|
|
mock_get_service_template,
|
|
mock_get_job_with_sending_limits_exceeded,
|
|
fake_uuid,
|
|
mock_get_service_data_retention,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
)
|
|
|
|
assert page.h1.text.strip() == "Message status"
|
|
|
|
|
|
@freeze_time("2020-01-10 1:0:0")
|
|
@pytest.mark.parametrize(
|
|
("created_at", "processing_started", "expected_message"),
|
|
[
|
|
# Recently created, not yet started
|
|
(datetime(2020, 1, 10, 0, 0, 0), None, ("No messages to show yet…")),
|
|
# Just started
|
|
(
|
|
datetime(2020, 1, 10, 0, 0, 0),
|
|
datetime(2020, 1, 10, 0, 0, 1),
|
|
("No messages to show yet…"),
|
|
),
|
|
# Created a while ago, just started
|
|
(
|
|
datetime(2020, 1, 1, 0, 0, 0),
|
|
datetime(2020, 1, 10, 0, 0, 1),
|
|
("No messages to show yet…"),
|
|
),
|
|
# Created a while ago, started just within the last 24h
|
|
# TODO -- fails locally, should pass, tech debt due to timezone changes, re-evaluate after UTC changes
|
|
pytest.param(
|
|
datetime(2020, 1, 1, 0, 0, 0),
|
|
datetime(2020, 1, 9, 6, 0, 1),
|
|
("No messages to show yet…"),
|
|
),
|
|
# Created a while ago, started exactly 24h ago
|
|
# ---
|
|
# It doesn't matter that 24h (1 day) and 7 days (the service's data
|
|
# retention) don't match up. We're testing the case of no
|
|
# notifications existing more than 1 day after the job started
|
|
# processing. In this case we assume it's because the service's
|
|
# data retention has kicked in.
|
|
(
|
|
datetime(2020, 1, 1, 0, 0, 0),
|
|
datetime(2020, 1, 9, 1, 0, 0),
|
|
(
|
|
"These messages have been deleted because they were sent more than 7 days ago"
|
|
),
|
|
),
|
|
],
|
|
)
|
|
def test_should_show_old_job(
|
|
client_request,
|
|
mock_get_service_template,
|
|
mocker,
|
|
fake_uuid,
|
|
created_at,
|
|
processing_started,
|
|
expected_message,
|
|
active_user_with_permissions,
|
|
mock_get_service_data_retention,
|
|
):
|
|
mocker.patch(
|
|
"app.job_api_client.get_job",
|
|
return_value={
|
|
"data": job_json(
|
|
SERVICE_ONE_ID,
|
|
active_user_with_permissions,
|
|
created_at=created_at.replace(tzinfo=timezone.utc).isoformat(),
|
|
processing_started=(
|
|
processing_started.replace(tzinfo=timezone.utc).isoformat()
|
|
if processing_started
|
|
else None
|
|
),
|
|
),
|
|
},
|
|
)
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fake_uuid,
|
|
)
|
|
assert page.h1.text.strip() == "Message status"
|
|
|
|
|
|
@freeze_time("2016-01-01T06:00:00.061258")
|
|
def test_should_show_scheduled_job(
|
|
client_request,
|
|
mock_get_service_template,
|
|
mock_get_scheduled_job,
|
|
fake_uuid,
|
|
mock_get_service_data_retention,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fake_uuid,
|
|
)
|
|
|
|
assert page.h1.text.strip() == "Message status"
|
|
|
|
|
|
def test_should_cancel_job(
|
|
client_request,
|
|
fake_uuid,
|
|
mock_get_job,
|
|
mock_get_service_template,
|
|
mocker,
|
|
):
|
|
mock_cancel = mocker.patch("app.job_api_client.cancel_job")
|
|
client_request.post(
|
|
"main.cancel_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fake_uuid,
|
|
_expected_status=302,
|
|
_expected_redirect=url_for(
|
|
"main.service_dashboard",
|
|
service_id=SERVICE_ONE_ID,
|
|
),
|
|
)
|
|
|
|
mock_cancel.assert_called_once_with(SERVICE_ONE_ID, fake_uuid)
|
|
|
|
|
|
@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
|
|
@given(fuzzed_uuid=st.uuids())
|
|
def test_should_not_show_cancelled_job(
|
|
client_request, active_user_with_permissions, mock_get_cancelled_job, fuzzed_uuid
|
|
):
|
|
client_request.get(
|
|
"main.view_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fuzzed_uuid,
|
|
_expected_status=404,
|
|
)
|
|
|
|
|
|
@freeze_time("2016-01-01 05:00:00.000001")
|
|
def test_time_left():
|
|
pass
|
|
|
|
|
|
def test_should_show_message_note(
|
|
client_request,
|
|
mock_get_service_template,
|
|
mock_get_scheduled_job,
|
|
mock_get_service_data_retention,
|
|
mock_get_notifications,
|
|
fake_uuid,
|
|
):
|
|
page = client_request.get(
|
|
"main.view_job",
|
|
service_id=SERVICE_ONE_ID,
|
|
job_id=fake_uuid,
|
|
)
|
|
|
|
assert normalize_spaces(page.select_one("main p.notification-status").text) == (
|
|
'Messages are sent immediately to the cell phone carrier, but will remain in "pending" status until we hear '
|
|
"back from the carrier they have received it and attempted deliver. More information on delivery status."
|
|
)
|
|
|
|
|
|
def test_poll_status_endpoint(
|
|
client_request,
|
|
service_one,
|
|
active_user_with_permissions,
|
|
mock_get_service_data_retention,
|
|
mocker,
|
|
fake_uuid,
|
|
):
|
|
"""Test that the poll status endpoint returns only required data without notifications"""
|
|
mock_job_status = mocker.patch("app.job_api_client.get_job_status")
|
|
mock_job_status.return_value = {
|
|
"total": 100,
|
|
"delivered": 90,
|
|
"failed": 10,
|
|
"pending": 0,
|
|
"finished": True,
|
|
}
|
|
|
|
response = client_request.get_response(
|
|
"main.view_job_status_poll",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
_expected_status=200,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.get_json()
|
|
assert data["total"] == 100
|
|
assert data["delivered"] == 90
|
|
assert data["failed"] == 10
|
|
assert data["pending"] == 0
|
|
assert data["finished"] is True
|
|
|
|
|
|
def test_poll_status_with_zero_notifications(
|
|
client_request,
|
|
service_one,
|
|
active_user_with_permissions,
|
|
mock_get_service_data_retention,
|
|
mocker,
|
|
fake_uuid,
|
|
):
|
|
"""Test poll status endpoint handles edge case of no notifications"""
|
|
mock_job_status = mocker.patch("app.job_api_client.get_job_status")
|
|
mock_job_status.return_value = {
|
|
"total": 0,
|
|
"delivered": 0,
|
|
"failed": 0,
|
|
"pending": 0,
|
|
"finished": True,
|
|
}
|
|
|
|
response = client_request.get_response(
|
|
"main.view_job_status_poll",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
_expected_status=200,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.get_json()
|
|
assert data["total"] == 0
|
|
assert data["pending"] == 0
|
|
|
|
|
|
def test_poll_status_endpoint_does_not_query_notifications_table(
|
|
client_request,
|
|
service_one,
|
|
active_user_with_permissions,
|
|
mock_get_service_data_retention,
|
|
mocker,
|
|
fake_uuid,
|
|
):
|
|
"""Critical regression test: ensure poll status endpoint never queries notifications"""
|
|
mock_job_status = mocker.patch("app.job_api_client.get_job_status")
|
|
mock_job_status.return_value = {
|
|
"total": 500,
|
|
"delivered": 300,
|
|
"failed": 50,
|
|
"pending": 150,
|
|
"finished": False,
|
|
}
|
|
|
|
mock_get_notifications = mocker.patch(
|
|
"app.notification_api_client.get_notifications_for_service"
|
|
)
|
|
|
|
response = client_request.get_response(
|
|
"main.view_job_status_poll",
|
|
service_id=service_one["id"],
|
|
job_id=fake_uuid,
|
|
_expected_status=200,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.get_json()
|
|
assert data["total"] == 500
|
|
assert data["pending"] == 150
|
|
|
|
mock_get_notifications.assert_not_called()
|