Merge branch 'main' into notify-admin-1218

This commit is contained in:
Kenneth Kehl
2024-08-13 11:27:14 -07:00
committed by GitHub
16 changed files with 1549 additions and 1216 deletions

View File

@@ -300,9 +300,26 @@ def test_accepting_invite_removes_invite_from_session(
client_request.login(user)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
date_range = {"start_date": "2024-01-01", "days": 7}
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats",
return_value={
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
},
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value={
date_range["start_date"]: {
"email": {"delivered": 1, "failure": 0, "requested": 1},
"sms": {"delivered": 1, "failure": 0, "requested": 1},
},
},
)
page = client_request.get(
"main.accept_invite",

View File

@@ -3,11 +3,9 @@ import json
from datetime import datetime
import pytest
from flask import Flask, url_for
from flask_socketio import SocketIO, SocketIOTestClient
from flask import url_for
from freezegun import freeze_time
from app import create_app
from app.main.views.dashboard import (
aggregate_notifications_stats,
aggregate_status_types,
@@ -15,8 +13,6 @@ from app.main.views.dashboard import (
format_monthly_stats_to_list,
get_dashboard_totals,
get_tuples_of_financial_years,
handle_fetch_daily_stats,
handle_fetch_daily_stats_by_user,
)
from tests import (
organization_json,
@@ -27,8 +23,6 @@ from tests import (
from tests.conftest import (
ORGANISATION_ID,
SERVICE_ONE_ID,
SERVICE_TWO_ID,
USER_ONE_ID,
create_active_caseworking_user,
create_active_user_view_permissions,
normalize_spaces,
@@ -163,6 +157,22 @@ stub_template_stats = [
},
]
date_range = {"start_date": "2024-01-01", "days": 7}
mock_daily_stats = {
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
}
mock_daily_stats_by_user = {
date_range["start_date"]: {
"email": {"delivered": 1, "failure": 0, "requested": 1},
"sms": {"delivered": 1, "failure": 0, "requested": 1},
},
}
@pytest.mark.parametrize(
"user",
@@ -222,8 +232,12 @@ def test_get_started(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -252,8 +266,12 @@ def test_get_started_is_hidden_once_templates_exist(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -279,8 +297,12 @@ def test_inbound_messages_not_visible_to_service_without_permissions(
service_one["permissions"] = []
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -305,6 +327,14 @@ def test_inbound_messages_shows_count_of_messages_when_there_are_messages(
mock_get_inbound_sms_summary,
):
service_one["permissions"] = ["inbound_sms"]
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
service_id=SERVICE_ONE_ID,
@@ -333,6 +363,14 @@ def test_inbound_messages_shows_count_of_messages_when_there_are_no_messages(
mock_get_inbound_sms_summary_with_no_messages,
):
service_one["permissions"] = ["inbound_sms"]
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
service_id=SERVICE_ONE_ID,
@@ -580,8 +618,12 @@ def test_should_show_recent_templates_on_dashboard(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -637,8 +679,12 @@ def test_should_not_show_recent_templates_on_dashboard_if_only_one_template_used
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
main = page.select_one("main").text
@@ -792,8 +838,12 @@ def test_should_show_upcoming_jobs_on_dashboard(
mock_get_inbound_sms_summary,
):
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -834,6 +884,14 @@ def test_should_not_show_upcoming_jobs_on_dashboard_if_count_is_0(
},
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
service_id=SERVICE_ONE_ID,
@@ -857,8 +915,12 @@ def test_should_not_show_upcoming_jobs_on_dashboard_if_service_has_no_jobs(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
@@ -942,6 +1004,14 @@ def test_should_not_show_jobs_on_dashboard_for_users_with_uploads_page(
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
):
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get(
"main.service_dashboard",
service_id=SERVICE_ONE_ID,
@@ -1203,8 +1273,12 @@ def test_menu_send_messages(
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = _test_dashboard_menu(
client_request,
@@ -1240,8 +1314,12 @@ def test_menu_manage_service(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = _test_dashboard_menu(
client_request,
@@ -1277,8 +1355,12 @@ def test_menu_main_settings(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = _test_settings_menu(
client_request,
@@ -1313,8 +1395,12 @@ def test_menu_manage_api_keys(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = _test_dashboard_menu(
client_request,
@@ -1353,8 +1439,12 @@ def test_menu_all_services_for_platform_admin_user(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = _test_dashboard_menu(
client_request, mocker, platform_admin_user, service_one, []
@@ -1392,8 +1482,12 @@ def test_route_for_service_permissions(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
validate_route_permission(
mocker,
@@ -1537,8 +1631,12 @@ def test_org_breadcrumbs_do_not_show_if_service_has_no_org(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
@@ -1604,8 +1702,12 @@ def test_org_breadcrumbs_show_if_user_is_a_member_of_the_services_org(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
@@ -1639,10 +1741,13 @@ def test_org_breadcrumbs_do_not_show_if_user_is_a_member_of_the_services_org_but
mocker.patch("app.models.service.Organization")
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
@@ -1679,8 +1784,12 @@ def test_org_breadcrumbs_show_if_user_is_platform_admin(
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
client_request.login(platform_admin_user, service_one_json)
@@ -1715,9 +1824,14 @@ def test_breadcrumb_shows_if_service_is_suspended(
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
assert "Suspended" in page.select_one(".navigation-service-name").text
@@ -1748,8 +1862,12 @@ def test_service_dashboard_shows_usage(
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
service_one["permissions"] = permissions
@@ -1783,10 +1901,13 @@ def test_service_dashboard_shows_free_allowance(
],
)
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
@@ -1802,12 +1923,15 @@ def test_service_dashboard_shows_batched_jobs(
):
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats", return_value=mock_daily_stats
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value=mock_daily_stats_by_user,
)
page = client_request.get("main.service_dashboard", service_id=SERVICE_ONE_ID)
job_table_body = page.find("table", class_="job-table")
rows = job_table_body.find_all("tbody")[0].find_all("tr")
@@ -1815,158 +1939,3 @@ def test_service_dashboard_shows_batched_jobs(
assert job_table_body is not None
assert len(rows) == 1
@pytest.fixture
def app_with_socketio():
app = Flask("app")
create_app(app)
socketio = SocketIO(app)
socketio.on_event("fetch_daily_stats", handle_fetch_daily_stats)
socketio.on_event("fetch_daily_stats_by_user", handle_fetch_daily_stats_by_user)
return app, socketio
@pytest.mark.parametrize(
("service_id", "date_range", "expected_call_args"),
[
(
SERVICE_ONE_ID,
{"start_date": "2024-01-01", "days": 7},
{"service_id": SERVICE_ONE_ID, "start_date": "2024-01-01", "days": 7},
),
(
SERVICE_TWO_ID,
{"start_date": "2023-06-01", "days": 7},
{"service_id": SERVICE_TWO_ID, "start_date": "2023-06-01", "days": 7},
),
],
)
def test_fetch_daily_stats(
app_with_socketio,
mocker,
service_id,
date_range,
expected_call_args,
):
app, socketio = app_with_socketio
mocker.patch(
"app.main.views.dashboard.get_stats_date_range", return_value=date_range
)
mock_service_api = mocker.patch(
"app.service_api_client.get_service_notification_statistics_by_day",
return_value={
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
},
)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["service_id"] = service_id
socketio_client = SocketIOTestClient(app, socketio, flask_test_client=client)
connected = socketio_client.is_connected()
assert connected, "Client should be connected"
socketio_client.emit("fetch_daily_stats")
received = socketio_client.get_received()
mock_service_api.assert_called_once_with(
expected_call_args["service_id"],
start_date=expected_call_args["start_date"],
days=expected_call_args["days"],
)
assert received, "Should receive a response message"
assert received[0]["name"] == "daily_stats_update"
assert received[0]["args"][0] == {
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
}
socketio_client.disconnect()
disconnected = not socketio_client.is_connected()
assert disconnected, "Client should be disconnected"
@pytest.mark.parametrize(
("service_id", "user_id", "date_range", "expected_call_args", "user"),
[
(
SERVICE_ONE_ID,
USER_ONE_ID,
{"start_date": "2024-01-01", "days": 7},
{
"service_id": SERVICE_ONE_ID,
"user_id": USER_ONE_ID,
"start_date": "2024-01-01",
"days": 7,
},
{"id": USER_ONE_ID, "name": "Test User"},
),
],
)
def test_fetch_daily_stats_by_user(
app_with_socketio,
mocker,
service_id,
user_id,
date_range,
expected_call_args,
user,
):
app, socketio = app_with_socketio
mocker.patch(
"app.main.views.dashboard.get_stats_date_range", return_value=date_range
)
mock_service_api = mocker.patch(
"app.service_api_client.get_user_service_notification_statistics_by_day",
return_value={
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
},
)
mocker.patch("app.user_api_client.get_user", return_value=user)
with app.test_client() as client:
with client.session_transaction() as sess:
sess["service_id"] = service_id
sess["user_id"] = user_id
socketio_client = SocketIOTestClient(app, socketio, flask_test_client=client)
connected = socketio_client.is_connected()
assert connected, "Client should be connected"
socketio_client.emit("fetch_daily_stats_by_user")
received = socketio_client.get_received()
mock_service_api.assert_called_once_with(
expected_call_args["service_id"],
expected_call_args["user_id"],
start_date=expected_call_args["start_date"],
days=expected_call_args["days"],
)
assert received, "Should receive a response message"
assert received[0]["name"] == "daily_stats_by_user_update"
assert received[0]["args"][0] == {
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
}
socketio_client.disconnect()
disconnected = not socketio_client.is_connected()
assert disconnected, "Client should be disconnected"

View File

@@ -128,9 +128,26 @@ def test_sign_out_user(
# Check we are logged in
mocker.patch("app.job_api_client.get_jobs", return_value=MOCK_JOBS)
date_range = {"start_date": "2024-01-01", "days": 7}
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
"app.main.views.dashboard.get_daily_stats",
return_value={
date_range["start_date"]: {
"email": {"delivered": 0, "failure": 0, "requested": 0},
"sms": {"delivered": 0, "failure": 1, "requested": 1},
},
},
)
mocker.patch(
"app.main.views.dashboard.get_daily_stats_by_user",
return_value={
date_range["start_date"]: {
"email": {"delivered": 1, "failure": 0, "requested": 1},
"sms": {"delivered": 1, "failure": 0, "requested": 1},
},
},
)
client_request.get(