Files
notifications-admin/tests/app/main/views/test_platform_admin.py
T

1290 lines
39 KiB
Python
Raw Normal View History

2017-01-03 16:14:25 +00:00
import datetime
2018-06-25 13:34:54 +01:00
import re
import uuid
from functools import partial
2019-02-15 11:13:53 +00:00
from unittest.mock import ANY, call
2017-01-03 16:14:25 +00:00
import pytest
2019-11-29 13:03:23 +00:00
from flask import url_for
2018-06-25 13:34:54 +01:00
from freezegun import freeze_time
2016-05-24 15:52:44 +01:00
2018-02-20 11:22:17 +00:00
from app.main.views.platform_admin import (
create_global_stats,
format_stats_by_service,
2018-06-25 13:34:54 +01:00
get_tech_failure_status_box_data,
is_over_threshold,
2018-02-20 11:22:17 +00:00
sum_service_usage,
)
2018-04-25 14:12:58 +01:00
from tests import service_json
from tests.conftest import SERVICE_ONE_ID, SERVICE_TWO_ID, normalize_spaces
2017-09-22 23:09:44 +01:00
2016-05-24 15:52:44 +01:00
@pytest.mark.parametrize(
"endpoint",
[
"main.platform_admin",
"main.live_services",
"main.trial_services",
],
)
2024-07-11 09:38:32 -07:00
def test_should_redirect_if_not_logged_in(client_request, endpoint, mocker):
mocker.patch("app.notify_client.user_api_client.UserApiClient.deactivate_user")
2022-01-04 15:40:42 +00:00
client_request.logout()
client_request.get(
endpoint,
_expected_redirect=url_for("main.sign_in", next=url_for(endpoint)),
2022-01-04 15:40:42 +00:00
)
2016-05-24 15:52:44 +01:00
@pytest.mark.parametrize(
"endpoint",
[
"main.platform_admin",
"main.platform_admin_splash_page",
"main.live_services",
"main.trial_services",
],
)
2017-02-03 10:42:01 +00:00
def test_should_403_if_not_platform_admin(
client_request,
endpoint,
2017-02-03 10:42:01 +00:00
):
client_request.get(endpoint, _expected_status=403)
2016-05-24 15:52:44 +01:00
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("endpoint", "expected_services_shown"),
[
("main.live_services", 1),
("main.trial_services", 1),
],
)
def test_should_render_platform_admin_page(
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
2016-08-24 16:26:08 +01:00
mock_get_detailed_services,
endpoint,
expected_services_shown,
):
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(endpoint)
assert [
normalize_spaces(column.text)
for column in page.select("tbody tr")[1].select("td")
] == [
"0 emails sent",
"0 text messages sent",
]
mock_get_detailed_services.assert_called_once_with(
{"detailed": True, "include_from_test_key": True, "only_active": False}
)
2016-05-25 16:51:09 +01:00
@pytest.mark.parametrize(
"endpoint",
[
"main.live_services",
"main.trial_services",
],
)
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("partial_url_for", "inc"),
[
(partial(url_for), True),
(partial(url_for, include_from_test_key="y", start_date="", end_date=""), True),
(partial(url_for, start_date="", end_date=""), False),
],
)
2017-10-23 15:08:08 +01:00
def test_live_trial_services_toggle_including_from_test_key(
partial_url_for,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
2017-02-03 10:42:01 +00:00
mock_get_detailed_services,
endpoint,
inc,
):
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
client_request.get_url(partial_url_for(endpoint))
mock_get_detailed_services.assert_called_once_with(
{
"detailed": True,
"only_active": False,
"include_from_test_key": inc,
}
)
@pytest.mark.parametrize("endpoint", ["main.live_services", "main.trial_services"])
2017-10-23 15:08:08 +01:00
def test_live_trial_services_with_date_filter(
client_request, platform_admin_user, mock_get_detailed_services, endpoint
):
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(
endpoint,
start_date="2016-12-20",
end_date="2016-12-28",
2021-12-30 16:13:49 +00:00
)
assert "Platform admin" in page.text
mock_get_detailed_services.assert_called_once_with(
{
"include_from_test_key": False,
"end_date": datetime.date(2016, 12, 28),
"start_date": datetime.date(2016, 12, 20),
"detailed": True,
"only_active": False,
}
)
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("endpoint", "expected_big_numbers"),
[
(
"main.live_services",
(
"55 emails sent 5 failed 5.0%",
"110 text messages sent 10 failed 5.0%",
),
2017-07-31 11:29:04 +01:00
),
(
"main.trial_services",
(
"6 emails sent 1 failed 10.0%",
"11 text messages sent 1 failed 5.0%",
),
2017-07-31 11:29:04 +01:00
),
],
)
2017-10-23 15:08:08 +01:00
def test_should_show_total_on_live_trial_services_pages(
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
2017-07-31 11:29:04 +01:00
mock_get_detailed_services,
endpoint,
fake_uuid,
expected_big_numbers,
):
services = [
service_json(fake_uuid, "My Service 1", [], restricted=False),
service_json(fake_uuid, "My Service 2", [], restricted=True),
2017-07-31 11:29:04 +01:00
]
services[0]["statistics"] = create_stats(
2017-07-31 11:29:04 +01:00
emails_requested=100,
emails_delivered=50,
emails_failed=5,
sms_requested=200,
sms_delivered=100,
sms_failed=10,
)
services[1]["statistics"] = create_stats(
2017-07-31 11:29:04 +01:00
emails_requested=10,
emails_delivered=5,
emails_failed=1,
sms_requested=20,
sms_delivered=10,
sms_failed=1,
)
mock_get_detailed_services.return_value = {"data": services}
2017-07-31 11:29:04 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(endpoint)
2017-07-31 11:29:04 +01:00
assert (
normalize_spaces(page.select(".big-number-with-status")[0].text),
normalize_spaces(page.select(".big-number-with-status")[1].text),
2022-12-05 15:33:44 -05:00
# normalize_spaces(page.select('.big-number-with-status')[2].text),
2017-07-31 11:29:04 +01:00
) == expected_big_numbers
def test_create_global_stats_sets_failure_rates(fake_uuid):
services = [service_json(fake_uuid, "a", []), service_json(fake_uuid, "b", [])]
services[0]["statistics"] = create_stats(
2017-10-18 14:51:26 +01:00
emails_requested=1,
emails_delivered=1,
emails_failed=0,
)
services[1]["statistics"] = create_stats(
2017-10-18 14:51:26 +01:00
emails_requested=2,
emails_delivered=1,
emails_failed=1,
)
2016-05-25 16:51:09 +01:00
stats = create_global_stats(services)
assert stats == {
"email": {"delivered": 2, "failed": 1, "requested": 3, "failure_rate": "33.3"},
"sms": {"delivered": 0, "failed": 0, "requested": 0, "failure_rate": "0"},
}
def create_stats(
emails_requested=0,
emails_delivered=0,
emails_failed=0,
sms_requested=0,
sms_delivered=0,
sms_failed=0,
):
return {
"sms": {
"requested": sms_requested,
"delivered": sms_delivered,
"failed": sms_failed,
},
"email": {
"requested": emails_requested,
"delivered": emails_delivered,
"failed": emails_failed,
},
}
def test_format_stats_by_service_returns_correct_values(fake_uuid):
services = [service_json(fake_uuid, "a", [])]
services[0]["statistics"] = create_stats(
emails_requested=10,
emails_delivered=3,
emails_failed=5,
sms_requested=50,
sms_delivered=7,
sms_failed=11,
)
ret = list(format_stats_by_service(services))
assert len(ret) == 1
2016-11-15 11:12:19 +00:00
assert ret[0]["stats"]["email"]["requested"] == 10
assert ret[0]["stats"]["email"]["delivered"] == 3
assert ret[0]["stats"]["email"]["failed"] == 5
assert ret[0]["stats"]["sms"]["requested"] == 50
assert ret[0]["stats"]["sms"]["delivered"] == 7
assert ret[0]["stats"]["sms"]["failed"] == 11
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("endpoint", "restricted", "research_mode"),
[("main.trial_services", True, False), ("main.live_services", False, False)],
)
def test_should_show_email_and_sms_stats_for_all_service_types(
endpoint,
restricted,
research_mode,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
mock_get_detailed_services,
2017-02-03 10:42:01 +00:00
fake_uuid,
):
services = [
service_json(
fake_uuid,
"My Service",
[],
restricted=restricted,
research_mode=research_mode,
)
]
services[0]["statistics"] = create_stats(
emails_requested=10,
emails_delivered=3,
emails_failed=5,
sms_requested=50,
sms_delivered=7,
sms_failed=11,
)
mock_get_detailed_services.return_value = {"data": services}
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(endpoint)
mock_get_detailed_services.assert_called_once_with(
{"detailed": True, "include_from_test_key": True, "only_active": ANY}
)
table_body = page.find_all("table")[0].find_all("tbody")[0]
service_row_group = table_body.find_all("tbody")[0].find_all("tr")
email_stats = service_row_group[1].select(".big-number-number")[0]
sms_stats = service_row_group[1].select(".big-number-number")[1]
assert normalize_spaces(email_stats.text) == "10"
assert normalize_spaces(sms_stats.text) == "50"
2016-11-08 13:17:08 +00:00
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("endpoint", "restricted"),
[("main.live_services", False), ("main.trial_services", True)],
ids=["live", "trial"],
)
2016-11-08 13:17:08 +00:00
def test_should_show_archived_services_last(
endpoint,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
2016-11-08 13:17:08 +00:00
mock_get_detailed_services,
restricted,
):
services = [
service_json(
name="C",
restricted=restricted,
active=False,
created_at="2002-02-02 12:00:00",
),
service_json(
name="B",
restricted=restricted,
active=True,
created_at="2001-01-01 12:00:00",
),
service_json(
name="A",
restricted=restricted,
active=True,
created_at="2003-03-03 12:00:00",
),
2016-11-08 13:17:08 +00:00
]
services[0]["statistics"] = create_stats()
services[1]["statistics"] = create_stats()
services[2]["statistics"] = create_stats()
2016-11-08 13:17:08 +00:00
mock_get_detailed_services.return_value = {"data": services}
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(endpoint)
2016-11-08 13:17:08 +00:00
mock_get_detailed_services.assert_called_once_with(
{"detailed": True, "include_from_test_key": True, "only_active": ANY}
)
2016-11-14 17:25:07 +00:00
table_body = page.find_all("table")[0].find_all("tbody")[0]
services = [service.tr for service in table_body.find_all("tbody")]
2016-11-14 17:25:07 +00:00
assert len(services) == 3
assert normalize_spaces(services[0].td.text) == "A"
assert normalize_spaces(services[1].td.text) == "B"
assert normalize_spaces(services[2].td.text) == "C Archived"
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("endpoint", "restricted", "research_mode"),
[("main.trial_services", True, False), ("main.live_services", False, False)],
)
def test_should_order_services_by_usage_with_inactive_last(
endpoint,
restricted,
research_mode,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
mock_get_detailed_services,
fake_uuid,
):
services = [
service_json(
fake_uuid,
"My Service 1",
[],
restricted=restricted,
research_mode=research_mode,
),
service_json(
fake_uuid,
"My Service 2",
[],
restricted=restricted,
research_mode=research_mode,
),
service_json(
fake_uuid,
"My Service 3",
[],
restricted=restricted,
research_mode=research_mode,
active=False,
),
]
services[0]["statistics"] = create_stats(
emails_requested=100,
emails_delivered=25,
emails_failed=25,
sms_requested=100,
sms_delivered=25,
sms_failed=25,
)
services[1]["statistics"] = create_stats(
emails_requested=200,
emails_delivered=50,
emails_failed=50,
sms_requested=200,
sms_delivered=50,
sms_failed=50,
)
services[2]["statistics"] = create_stats(
emails_requested=200,
emails_delivered=50,
emails_failed=50,
sms_requested=200,
sms_delivered=50,
sms_failed=50,
)
mock_get_detailed_services.return_value = {"data": services}
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(endpoint)
mock_get_detailed_services.assert_called_once_with(
{"detailed": True, "include_from_test_key": True, "only_active": ANY}
)
table_body = page.find_all("table")[0].find_all("tbody")[0]
services = [service.tr for service in table_body.find_all("tbody")]
assert len(services) == 3
assert normalize_spaces(services[0].td.text) == "My Service 2"
assert normalize_spaces(services[1].td.text) == "My Service 1"
assert normalize_spaces(services[2].td.text) == "My Service 3 Archived"
def test_sum_service_usage_is_sum_of_all_activity(fake_uuid):
service = service_json(fake_uuid, "My Service 1")
service["statistics"] = create_stats(
emails_requested=100,
emails_delivered=25,
emails_failed=25,
sms_requested=100,
sms_delivered=25,
sms_failed=25,
)
assert sum_service_usage(service) == 200
def test_sum_service_usage_with_zeros(fake_uuid):
service = service_json(fake_uuid, "My Service 1")
service["statistics"] = create_stats(
emails_requested=0,
emails_delivered=0,
emails_failed=25,
sms_requested=0,
sms_delivered=0,
sms_failed=0,
)
assert sum_service_usage(service) == 0
def test_platform_admin_list_complaints(client_request, platform_admin_user, mocker):
complaint = {
"id": str(uuid.uuid4()),
"notification_id": str(uuid.uuid4()),
"service_id": str(uuid.uuid4()),
"service_name": "Sample service",
"ses_feedback_id": "Some ses id",
"complaint_type": "abuse",
"complaint_date": "2018-06-05T13:50:30.012354",
"created_at": "2018-06-05T13:50:30.012354",
}
mock = mocker.patch(
"app.complaint_api_client.get_all_complaints",
return_value={"complaints": [complaint], "links": {}},
2021-12-30 16:13:49 +00:00
)
client_request.login(platform_admin_user)
page = client_request.get("main.platform_admin_list_complaints")
assert "Email complaints" in page.text
assert mock.called
2018-06-25 13:34:54 +01:00
2021-12-30 16:13:49 +00:00
def test_should_show_complaints_with_next_previous(
client_request,
platform_admin_user,
mocker,
service_one,
fake_uuid,
):
2018-07-03 10:54:33 +01:00
api_response = {
"complaints": [
{
"complaint_date": None,
"complaint_type": None,
"created_at": "2017-12-18T05:00:00.000000Z",
"id": fake_uuid,
"notification_id": fake_uuid,
"service_id": service_one["id"],
"service_name": service_one["name"],
"ses_feedback_id": "None",
}
],
"links": {
"last": "/complaint?page=3",
"next": "/complaint?page=3",
"prev": "/complaint?page=1",
},
2018-07-03 10:54:33 +01:00
}
mocker.patch(
"app.complaint_api_client.get_all_complaints", return_value=api_response
)
2018-07-03 10:54:33 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get(
"main.platform_admin_list_complaints",
2021-12-30 16:13:49 +00:00
page=2,
)
2018-07-03 10:54:33 +01:00
next_page_link = page.find("a", {"rel": "next"})
prev_page_link = page.find("a", {"rel": "previous"})
assert (
url_for("main.platform_admin_list_complaints", page=3) in next_page_link["href"]
)
assert "Next page" in next_page_link.text.strip()
assert "page 3" in next_page_link.text.strip()
assert (
url_for("main.platform_admin_list_complaints", page=1) in prev_page_link["href"]
)
assert "Previous page" in prev_page_link.text.strip()
assert "page 1" in prev_page_link.text.strip()
2018-07-03 10:54:33 +01:00
2021-12-30 16:13:49 +00:00
def test_platform_admin_list_complaints_returns_404_with_invalid_page(
client_request,
platform_admin_user,
mocker,
):
mocker.patch(
"app.complaint_api_client.get_all_complaints",
return_value={"complaints": [], "links": {}},
)
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
client_request.get(
"main.platform_admin_list_complaints",
page="invalid",
2021-12-30 16:13:49 +00:00
_expected_status=404,
)
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("number", "total", "threshold", "result"),
[
(0, 0, 0, False),
(1, 1, 0, True),
(2, 3, 66, True),
(2, 3, 67, False),
],
)
2018-06-25 13:34:54 +01:00
def test_is_over_threshold(number, total, threshold, result):
assert is_over_threshold(number, total, threshold) is result
def test_get_tech_failure_status_box_data_removes_percentage_data():
stats = {
"failures": {
"permanent-failure": 0,
"technical-failure": 0,
"temporary-failure": 1,
},
"test-key": 0,
"total": 5589,
2018-06-25 13:34:54 +01:00
}
tech_failure_data = get_tech_failure_status_box_data(stats)
assert "percentage" not in tech_failure_data
2018-06-25 13:34:54 +01:00
def test_platform_admin_splash_doesnt_talk_to_api(
client_request,
platform_admin_user,
):
client_request.login(platform_admin_user)
page = client_request.get("main.platform_admin_splash_page")
2023-08-28 12:12:21 -04:00
assert page.select_one("main .usa-body a")["href"] == url_for(
"main.platform_admin",
)
2021-12-30 16:13:49 +00:00
def test_platform_admin_with_start_and_end_dates_provided(
mocker,
client_request,
platform_admin_user,
):
start_date = "2018-01-01"
end_date = "2018-06-01"
api_args = {
"start_date": datetime.date(2018, 1, 1),
"end_date": datetime.date(2018, 6, 1),
}
2018-06-25 13:34:54 +01:00
mocker.patch("app.main.views.platform_admin.make_columns")
2018-06-25 13:34:54 +01:00
aggregate_stats_mock = mocker.patch(
"app.main.views.platform_admin.platform_stats_api_client.get_aggregate_platform_stats"
)
complaint_count_mock = mocker.patch(
"app.main.views.platform_admin.complaint_api_client.get_complaint_count"
)
2018-06-25 13:34:54 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
client_request.get(
"main.platform_admin",
start_date=start_date,
end_date=end_date,
2018-06-25 13:34:54 +01:00
)
aggregate_stats_mock.assert_called_with(api_args)
complaint_count_mock.assert_called_with(api_args)
@freeze_time("2018-6-11")
2021-12-30 16:13:49 +00:00
def test_platform_admin_with_only_a_start_date_provided(
mocker,
client_request,
platform_admin_user,
):
start_date = "2018-01-01"
api_args = {
"start_date": datetime.date(2018, 1, 1),
"end_date": datetime.datetime.utcnow().date(),
}
2018-06-25 13:34:54 +01:00
mocker.patch("app.main.views.platform_admin.make_columns")
2018-06-25 13:34:54 +01:00
aggregate_stats_mock = mocker.patch(
"app.main.views.platform_admin.platform_stats_api_client.get_aggregate_platform_stats"
)
complaint_count_mock = mocker.patch(
"app.main.views.platform_admin.complaint_api_client.get_complaint_count"
)
2018-06-25 13:34:54 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
client_request.get(
"main.platform_admin",
2021-12-30 16:13:49 +00:00
start_date=start_date,
)
2018-06-25 13:34:54 +01:00
aggregate_stats_mock.assert_called_with(api_args)
complaint_count_mock.assert_called_with(api_args)
2021-12-30 16:13:49 +00:00
def test_platform_admin_without_dates_provided(
mocker,
client_request,
platform_admin_user,
):
2018-06-25 13:34:54 +01:00
api_args = {}
mocker.patch("app.main.views.platform_admin.make_columns")
2018-06-25 13:34:54 +01:00
aggregate_stats_mock = mocker.patch(
"app.main.views.platform_admin.platform_stats_api_client.get_aggregate_platform_stats"
)
complaint_count_mock = mocker.patch(
"app.main.views.platform_admin.complaint_api_client.get_complaint_count"
)
2018-06-25 13:34:54 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
client_request.get("main.platform_admin")
2018-06-25 13:34:54 +01:00
aggregate_stats_mock.assert_called_with(api_args)
complaint_count_mock.assert_called_with(api_args)
2018-07-10 14:39:54 +01:00
def test_platform_admin_displays_stats_in_right_boxes_and_with_correct_styling(
2018-06-25 13:34:54 +01:00
mocker,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
2018-06-25 13:34:54 +01:00
):
platform_stats = {
"email": {
"failures": {
"permanent-failure": 3,
"technical-failure": 0,
"temporary-failure": 0,
},
"test-key": 0,
"total": 145,
},
"sms": {
"failures": {
"permanent-failure": 0,
"technical-failure": 1,
"temporary-failure": 0,
},
"test-key": 5,
"total": 168,
},
2018-06-25 13:34:54 +01:00
}
mocker.patch(
"app.main.views.platform_admin.platform_stats_api_client.get_aggregate_platform_stats",
return_value=platform_stats,
)
mocker.patch(
"app.main.views.platform_admin.complaint_api_client.get_complaint_count",
return_value=15,
)
2018-06-25 13:34:54 +01:00
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get("main.platform_admin")
2018-06-25 13:34:54 +01:00
# Email permanent failure status box - number is correct
2023-08-28 12:12:21 -04:00
assert "3 permanent failures" in page.find_all("div", class_="grid-col-6")[0].find(
string=re.compile("permanent")
)
2018-06-25 13:34:54 +01:00
# Email complaints status box - link exists and number is correct
assert page.find("a", string="15 complaints")
2018-06-25 13:34:54 +01:00
# SMS total box - number is correct
assert page.find_all("span", class_="big-number-number")[1].text.strip() == "168"
2018-06-25 13:34:54 +01:00
# Test SMS box - number is correct
2023-08-28 12:12:21 -04:00
assert "5" in page.find_all("div", class_="grid-col-6")[3].text
2018-06-25 13:34:54 +01:00
# SMS technical failure status box - number is correct and failure class is used
assert (
"1 technical failures"
2023-08-28 12:12:21 -04:00
in page.find_all("div", class_="grid-col-6")[1]
2023-09-18 12:29:40 -04:00
.find("div", class_="big-number-status--failing")
.text
)
2018-09-26 16:42:40 +01:00
2021-12-30 16:13:49 +00:00
def test_clear_cache_shows_form(
client_request,
platform_admin_user,
mocker,
):
redis = mocker.patch("app.main.views.platform_admin.redis_client")
2019-02-15 11:13:53 +00:00
client_request.login(platform_admin_user)
page = client_request.get("main.clear_cache")
2019-02-15 11:13:53 +00:00
2022-02-22 10:47:04 +00:00
assert not redis.delete_by_pattern.called
radios = {el["value"] for el in page.select("input[type=checkbox]")}
2022-02-21 11:19:50 +00:00
assert radios == {
"user",
"service",
"template",
"organization",
2022-02-21 11:19:50 +00:00
}
2019-02-15 11:13:53 +00:00
@pytest.mark.parametrize(
2023-09-11 16:51:30 -04:00
("model_type", "expected_calls", "expected_confirmation"),
[
(
"template",
[
call("service-????????-????-????-????-????????????-templates"),
call(
2023-10-30 08:42:11 -07:00
"service-????????-????-????-????-????????????-template"
"-????????-????-????-????-????????????-version-*"
),
call(
2023-10-30 08:42:11 -07:00
"service-????????-????-????-????-????????????-template"
"-????????-????-????-????-????????????-versions"
),
],
"Removed 6 objects across 3 key formats for template",
),
(
["service", "organization"],
[
call("has_jobs-????????-????-????-????-????????????"),
call("service-????????-????-????-????-????????????"),
call("service-????????-????-????-????-????????????-templates"),
call("service-????????-????-????-????-????????????-data-retention"),
call("service-????????-????-????-????-????????????-template-folders"),
call("organizations"),
call("domains"),
call("live-service-and-organization-counts"),
call("organization-????????-????-????-????-????????????-name"),
],
"Removed 18 objects across 9 key formats for service, organization",
),
2023-09-11 16:51:30 -04:00
],
)
def test_clear_cache_submits_and_tells_you_how_many_things_were_deleted(
client_request,
platform_admin_user,
mocker,
model_type,
expected_calls,
expected_confirmation,
):
redis = mocker.patch("app.main.views.platform_admin.redis_client")
2022-02-22 10:47:04 +00:00
redis.delete_by_pattern.return_value = 2
2019-02-15 11:13:53 +00:00
client_request.login(platform_admin_user)
2022-02-21 10:37:51 +00:00
page = client_request.post(
"main.clear_cache", _data={"model_type": model_type}, _expected_status=200
2022-02-21 10:37:51 +00:00
)
2019-02-15 11:13:53 +00:00
2022-02-22 10:47:04 +00:00
assert redis.delete_by_pattern.call_args_list == expected_calls
2019-02-15 11:13:53 +00:00
flash_banner = page.find("div", class_="banner-default")
assert flash_banner.text.strip() == expected_confirmation
2019-02-15 11:13:53 +00:00
2021-12-30 16:13:49 +00:00
def test_clear_cache_requires_option(
client_request,
platform_admin_user,
mocker,
):
redis = mocker.patch("app.main.views.platform_admin.redis_client")
2019-02-15 11:13:53 +00:00
client_request.login(platform_admin_user)
page = client_request.post("main.clear_cache", _data={}, _expected_status=200)
2019-02-15 11:13:53 +00:00
assert (
normalize_spaces(page.find("span", class_="usa-error-message").text)
== "Error: Select at least one option"
)
2022-02-22 10:47:04 +00:00
assert not redis.delete_by_pattern.called
def test_reports_page(
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
):
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
page = client_request.get("main.platform_admin_reports")
2019-04-24 16:23:12 +01:00
assert (
page.find("a", text="Download live services csv report").attrs["href"]
== "/platform-admin/reports/live-services.csv"
)
assert page.find("a", text="Monthly notification statuses for live services").attrs[
"href"
] == url_for("main.notifications_sent_by_service")
2019-04-24 16:23:12 +01:00
2021-12-30 16:13:49 +00:00
def test_get_live_services_report(
client_request,
platform_admin_user,
mocker,
):
2019-04-24 16:23:12 +01:00
mocker.patch(
"app.service_api_client.get_live_services_data",
return_value={
"data": [
{
"service_id": 1,
"service_name": "jessie the oak tree",
"organization_name": "Forest",
"consent_to_research": True,
"contact_name": "Forest fairy",
"organization_type": "Ecosystem",
"contact_email": "forest.fairy@digital.cabinet-office.gov.uk",
"contact_mobile": "+12028675109",
"live_date": "Sat, 29 Mar 2014 00:00:00 GMT",
"sms_volume_intent": 100,
"email_volume_intent": 50,
"sms_totals": 300,
"email_totals": 1200,
"free_sms_fragment_limit": 100,
},
{
"service_id": 2,
"service_name": "james the pine tree",
"organization_name": "Forest",
"consent_to_research": None,
"contact_name": None,
"organization_type": "Ecosystem",
"contact_email": None,
"contact_mobile": None,
"live_date": None,
"sms_volume_intent": None,
"email_volume_intent": 60,
"sms_totals": 0,
"email_totals": 0,
"free_sms_fragment_limit": 200,
},
]
},
2019-04-24 16:23:12 +01:00
)
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
2021-12-31 12:16:12 +00:00
response = client_request.get_response(
"main.live_services_csv",
2021-12-30 16:13:49 +00:00
)
2019-04-24 16:23:12 +01:00
report = response.get_data(as_text=True)
assert report.strip() == (
"Service ID,Organization,Organization type,Service name,Consent to research,Main contact,Contact email,"
+ "Contact mobile,Live date,SMS volume intent,Email volume intent,SMS sent this year,"
+ "Emails sent this year,Free sms allowance\r\n"
+ "1,Forest,Ecosystem,jessie the oak tree,True,Forest fairy,forest.fairy@digital.cabinet-office.gov.uk,"
+ "+12028675109,29-03-2014,100,50,300,1200,100\r\n"
+ "2,Forest,Ecosystem,james the pine tree,,,,,,,60,0,0,200"
)
2021-12-30 16:13:49 +00:00
def test_get_notifications_sent_by_service_shows_date_form(
client_request,
platform_admin_user,
):
client_request.login(platform_admin_user)
page = client_request.get("main.notifications_sent_by_service")
assert [
(input["type"], input["name"], input.get("value"))
for input in page.select("input")
] == [
("text", "start_date", None),
("text", "end_date", None),
("hidden", "csrf_token", ANY),
]
2021-12-30 16:13:49 +00:00
def test_get_notifications_sent_by_service_validates_form(
mocker,
client_request,
platform_admin_user,
):
mock_get_stats_from_api = mocker.patch(
"app.main.views.platform_admin.notification_api_client"
)
client_request.login(platform_admin_user)
page = client_request.post(
"main.notifications_sent_by_service",
_expected_status=200,
_data={"start_date": "", "end_date": "20190101"},
)
errors = page.select(".usa-error-message")
assert len(errors) == 2
for error in errors:
assert "Not a valid date value" in error.text
2020-08-28 13:26:14 +01:00
assert mock_get_stats_from_api.called is False
def test_get_billing_report_when_no_results_for_date(
client_request, platform_admin_user, mocker
):
client_request.login(platform_admin_user)
mocker.patch(
"app.main.views.platform_admin.billing_api_client.get_data_for_billing_report",
return_value=[],
)
page = client_request.post(
"main.get_billing_report",
_expected_status=200,
_data={"start_date": "2019-01-01", "end_date": "2019-03-31"},
)
error = page.select_one(".banner-dangerous")
assert normalize_spaces(error.text) == "No results for dates"
def test_get_billing_report_calls_api_and_download_data(
client_request, platform_admin_user, mocker
2021-12-30 16:13:49 +00:00
):
mocker.patch(
2021-03-15 18:04:01 +00:00
"app.main.views.platform_admin.billing_api_client.get_data_for_billing_report",
return_value=[
{
"organization_id": "7832a1be-a1f0-4f2a-982f-05adfd3d6354",
"organization_name": "Org for a - with sms",
"service_id": "48e82ac0-c8c4-4e46-8712-c83c35a94006",
"service_name": "a - with sms",
"sms_cost": 0,
"sms_chargeable_units": 0,
"purchase_order_number": "PO1234",
"contact_names": "Anne, Marie, Josh",
"contact_email_addresses": "billing@example.com, accounts@example.com",
"billing_reference": "Notify2020",
}
],
)
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
2021-12-31 12:16:12 +00:00
response = client_request.post_response(
"main.get_billing_report",
_data={"start_date": "2019-01-01", "end_date": "2019-03-31"},
2021-12-30 16:13:49 +00:00
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert response.headers["Content-Disposition"] == (
'attachment; filename="Billing Report from {} to {}.csv"'.format(
"2019-01-01", "2019-03-31"
)
)
assert response.get_data(as_text=True) == (
"organization_id,organization_name,service_id,service_name,sms_cost,sms_chargeable_units,"
+ "purchase_order_number,contact_names,contact_email_addresses,"
+ "billing_reference\r\n"
+ "7832a1be-a1f0-4f2a-982f-05adfd3d6354,"
+ "Org for a - with sms,"
+ "48e82ac0-c8c4-4e46-8712-c83c35a94006,"
+ "a - with sms,"
+ "0,"
+ "0,"
+ 'PO1234,"Anne, Marie, Josh","billing@example.com, accounts@example.com",Notify2020'
+ "\r\n"
)
def test_get_notifications_sent_by_service_calls_api_and_downloads_data(
mocker,
2021-12-30 16:13:49 +00:00
client_request,
platform_admin_user,
service_one,
service_two,
):
api_data = [
[
"2019-01-01",
SERVICE_ONE_ID,
service_one["name"],
"email",
191,
0,
0,
14,
0,
0,
],
["2019-01-01", SERVICE_ONE_ID, service_one["name"], "sms", 42, 0, 0, 8, 0, 0],
["2019-01-01", SERVICE_TWO_ID, service_two["name"], "email", 3, 1, 0, 2, 0, 0],
]
mocker.patch(
"app.main.views.platform_admin.notification_api_client.get_notification_status_by_service",
return_value=api_data,
)
start_date = datetime.date(2019, 1, 1)
end_date = datetime.date(2019, 1, 31)
2021-12-30 16:13:49 +00:00
client_request.login(platform_admin_user)
2021-12-31 12:16:12 +00:00
response = client_request.post_response(
"main.notifications_sent_by_service",
_data={"start_date": start_date, "end_date": end_date},
2021-12-30 16:13:49 +00:00
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert response.headers["Content-Disposition"] == (
'attachment; filename="{} to {} notification status per service report.csv"'.format(
start_date, end_date
)
)
assert response.get_data(as_text=True) == (
"date_created,service_id,service_name,notification_type,count_sending,count_delivered,"
+ "count_technical_failure,count_temporary_failure,count_permanent_failure,count_sent\r\n"
+ "2019-01-01,596364a0-858e-42c8-9062-a8fe822260eb,service one,email,191,0,0,14,0,0\r\n"
+ "2019-01-01,596364a0-858e-42c8-9062-a8fe822260eb,service one,sms,42,0,0,8,0,0\r\n"
+ "2019-01-01,147ad62a-2951-4fa1-9ca0-093cd1a52c52,service two,email,3,1,0,2,0,0\r\n"
)
2022-03-09 15:02:52 +00:00
def test_get_volumes_by_service_report_calls_api_and_download_data(
client_request, platform_admin_user, mocker
2022-03-09 15:02:52 +00:00
):
mocker.patch(
"app.main.views.platform_admin.billing_api_client.get_data_for_volumes_by_service_report",
return_value=[
{
"organization_id": "7832a1be-a1f0-4f2a-982f-05adfd3d6354",
"organization_name": "Org name",
"service_id": "48e82ac0-c8c4-4e46-8712-c83c35a94006",
"service_name": "service name",
"free_allowance": 10000,
"sms_notifications": 10,
"sms_chargeable_units": 20,
"email_totals": 8,
}
],
2022-03-09 15:02:52 +00:00
)
client_request.login(platform_admin_user)
response = client_request.post_response(
"main.get_volumes_by_service",
_data={"start_date": "2019-01-01", "end_date": "2019-03-31"},
2022-03-09 15:02:52 +00:00
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert response.headers["Content-Disposition"] == (
'attachment; filename="Volumes by service report from {} to {}.csv"'.format(
"2019-01-01", "2019-03-31"
)
2022-03-09 15:02:52 +00:00
)
assert response.get_data(as_text=True) == (
"organization id,organization name,service id,service name,free allowance,sms notifications,"
+ "sms chargeable units,email totals\r\n"
+ "7832a1be-a1f0-4f2a-982f-05adfd3d6354,"
+ "Org name,"
+ "48e82ac0-c8c4-4e46-8712-c83c35a94006,"
+ "service name,"
+ "10000,"
+ "10,"
+ "20,"
+ "8"
+ "\r\n"
2022-03-09 15:02:52 +00:00
)
def test_get_daily_volumes_report_calls_api_and_download_data(
client_request, platform_admin_user, mocker
2022-03-09 15:02:52 +00:00
):
mocker.patch(
"app.main.views.platform_admin.billing_api_client.get_data_for_daily_volumes_report",
return_value=[
{
"day": "2019-01-01",
"sms_totals": 20,
"sms_fragment_totals": 40,
"sms_chargeable_units": 60,
"email_totals": 100,
}
],
2022-03-09 15:02:52 +00:00
)
client_request.login(platform_admin_user)
response = client_request.post_response(
"main.get_daily_volumes",
_data={"start_date": "2019-01-01", "end_date": "2019-03-31"},
2022-03-09 15:02:52 +00:00
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert response.headers["Content-Disposition"] == (
'attachment; filename="Daily volumes report from {} to {}.csv"'.format(
"2019-01-01", "2019-03-31"
)
2022-03-09 15:02:52 +00:00
)
assert response.get_data(as_text=True) == (
"day,sms totals,sms fragment totals,sms chargeable units,email totals\r\n"
+ "2019-01-01,"
+ "20,"
+ "40,"
+ "60,"
+ "100"
+ "\r\n"
2022-03-09 15:02:52 +00:00
)
2022-04-08 16:05:43 +01:00
def test_get_users_report(client_request, platform_admin_user, mocker):
mocker.patch(
"app.main.views.platform_admin.user_api_client.get_all_users",
return_value=[
{
"name": "Johnny Sokko",
"organizations": [],
"password_changed_at": "2023-07-21 14:12:54.832850",
"permissions": {
"test service": [
"manage_users",
"manage_templates",
"manage_settings",
"send_texts",
"send_emails",
"manage_api_keys",
"view_activity",
]
},
"platform_admin": True,
"services": ["test service"],
"state": "active",
}
],
)
client_request.login(platform_admin_user)
response = client_request.post_response(
"main.get_users_report",
_data={},
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert "attachment" in response.headers["Content-Disposition"]
assert "filename" in response.headers["Content-Disposition"]
assert "User Report" in response.headers["Content-Disposition"]
my_response = response.get_data(as_text=True)
assert "Johnny Sokko" in my_response
assert "manage_users" in my_response
assert "test service" in my_response
assert "active" in my_response
def test_get_daily_sms_provider_volumes_report_calls_api_and_download_data(
client_request, platform_admin_user, mocker
2022-04-08 16:05:43 +01:00
):
mocker.patch(
"app.main.views.platform_admin.billing_api_client.get_data_for_daily_sms_provider_volumes_report",
return_value=[
{
"day": "2019-01-01",
"provider": "foo",
"sms_totals": 20,
"sms_fragment_totals": 40,
"sms_chargeable_units": 60,
"sms_cost": 80,
}
],
2022-04-08 16:05:43 +01:00
)
client_request.login(platform_admin_user)
response = client_request.post_response(
"main.get_daily_sms_provider_volumes",
_data={"start_date": "2019-01-01", "end_date": "2019-03-31"},
2022-04-08 16:05:43 +01:00
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert response.headers["Content-Disposition"] == (
'attachment; filename="Daily SMS provider volumes report from {} to {}.csv"'.format(
"2019-01-01", "2019-03-31"
)
2022-04-08 16:05:43 +01:00
)
assert response.get_data(as_text=True) == (
"day,provider,sms totals,sms fragment totals,sms chargeable units,sms cost\r\n"
+ "2019-01-01,"
+ "foo,"
+ "20,"
+ "40,"
+ "60,"
+ "80"
+ "\r\n"
2022-04-08 16:05:43 +01:00
)
2024-08-08 13:11:58 -07:00
2024-08-08 13:16:29 -07:00
def test_download_all_users(client_request, platform_admin_user, mocker):
2024-08-08 13:11:58 -07:00
mocker.patch(
"app.main.views.platform_admin.user_api_client.get_all_users_detailed",
return_value=[
{
"name": "Johnny Sokko",
"email_address": "j_sokko@unicorn.gov",
"mobile_number": "15555555555",
"service": "Emperor, Guillotine, Service",
}
],
)
client_request.login(platform_admin_user)
response = client_request.get_response(
"main.download_all_users",
_data={},
_expected_status=200,
)
assert response.content_type == "text/csv; charset=utf-8"
assert "attachment" in response.headers["Content-Disposition"]
assert "filename" in response.headers["Content-Disposition"]
assert "users" in response.headers["Content-Disposition"]
my_response = response.get_data(as_text=True)
assert "Johnny Sokko" in my_response
assert "Emperor Guillotine Service" in my_response
assert "j_sokko@unicorn.gov" in my_response
assert "15555555555" in my_response