Skip to content

Commit

Permalink
tests: add tests for new send code, template code, and changes to not…
Browse files Browse the repository at this point in the history
…ification_counts_client
  • Loading branch information
andrewleith committed Dec 5, 2024
1 parent 87f465e commit 31780b4
Show file tree
Hide file tree
Showing 3 changed files with 297 additions and 13 deletions.
129 changes: 118 additions & 11 deletions tests/app/main/views/test_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -3493,10 +3493,21 @@ def test_email_send_fails_approrpiately_when_over_limits(
),
)

# mock that `num_sent_this_year` have already been sent this year
mock_notification_counts_client.get_all_notification_counts_for_year.return_value = {
"sms": 1000, # not used in test but needs a value
"email": num_sent_this_year,
mock_notification_counts_client.get_limit_stats.return_value = {
"email": {
"annual": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": 10000
- num_sent_this_year
- num_sent_today, # The number of email notifications remaining this year
},
"daily": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": 1000 - num_sent_today, # The number of email notifications remaining today
},
}
}

# mock that we've already sent `emails_sent_today` emails today
Expand Down Expand Up @@ -3584,14 +3595,23 @@ def test_sms_send_fails_approrpiately_when_over_limits(
["phone number"] + ([mock_get_users_by_service(None)[0]["mobile_number"]] * num_being_sent)
),
)

# mock that `num_sent_this_year` have already been sent this year
mock_notification_counts_client.get_all_notification_counts_for_year.return_value = {
"sms": num_sent_this_year,
"email": 1000, # not used in test but needs a value
mock_notification_counts_client.get_limit_stats.return_value = {
"sms": {
"annual": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": 10000
- num_sent_this_year
- num_sent_today, # The number of email notifications remaining this year
},
"daily": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": 1000 - num_sent_today, # The number of email notifications remaining today
},
}
}

# mock that we've already sent `emails_sent_today` emails today
# mock that we've already sent `num_sent_today` emails today
mock_daily_email_count.return_value = 900 # not used in test but needs a value
mock_daily_sms_fragment_count.return_value = num_sent_today

Expand Down Expand Up @@ -3622,3 +3642,90 @@ def test_sms_send_fails_approrpiately_when_over_limits(
assert page.find(attrs={"data-testid": "exceeds-daily"}) is not None
else:
assert page.find(attrs={"data-testid": "exceeds-daily"}) is None

@pytest.mark.parametrize(
"num_to_send, remaining_daily, remaining_annual, error_shown",
[
(2, 2, 2, "none"),
(5, 5, 4, "annual"),
(5, 4, 5, "daily"),
(5, 4, 4, "annual"),
],
)
def test_correct_error_displayed(
self,
mocker,
client_request,
mock_get_live_service, # set email_annual_limit and sms_annual_limit to 1000
mock_get_users_by_service,
mock_get_service_email_template_without_placeholders,
mock_get_template_statistics,
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_s3_set_metadata,
mock_daily_email_count,
mock_notification_counts_client,
fake_uuid,
num_to_send,
remaining_daily,
remaining_annual,
error_shown,
app_,
):
with set_config(app_, "FF_ANNUAL_LIMIT", True): # REMOVE LINE WHEN FF REMOVED
# mock that `num_sent_this_year` have already been sent this year
mock_notification_counts_client.get_limit_stats.return_value = {
"email": {
"annual": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_annual, # The number of email notifications remaining this year
},
"daily": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_daily, # The number of email notifications remaining today
},
}
}

# only change this value when we're expecting an error
if error_shown != "none":
mock_daily_email_count.return_value = 1000 - (
num_to_send - 1
) # svc limit is 1000 - exceeding the daily limit is calculated based off of this
else:
mock_daily_email_count.return_value = 0 # none sent

mocker.patch(
"app.main.views.send.s3download",
return_value=",\n".join(
["email address"] + ([mock_get_users_by_service(None)[0]["email_address"]] * num_to_send)
),
)
with client_request.session_transaction() as session:
session["file_uploads"] = {
fake_uuid: {
"template_id": fake_uuid,
"notification_count": 1,
"valid": True,
}
}
page = client_request.get(
"main.check_messages",
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
upload_id=fake_uuid,
original_file_name="valid.csv",
_test_page_title=False,
)

if error_shown == "annual":
assert page.find(attrs={"data-testid": "exceeds-annual"}) is not None
assert page.find(attrs={"data-testid": "exceeds-daily"}) is None
elif error_shown == "daily":
assert page.find(attrs={"data-testid": "exceeds-annual"}) is None
assert page.find(attrs={"data-testid": "exceeds-daily"}) is not None
elif error_shown == "none":
assert page.find(attrs={"data-testid": "exceeds-annual"}) is None
assert page.find(attrs={"data-testid": "exceeds-daily"}) is None
69 changes: 68 additions & 1 deletion tests/app/main/views/test_templates.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime
from functools import partial
from unittest.mock import ANY, MagicMock, Mock
from unittest.mock import ANY, MagicMock, Mock, patch

import pytest
from flask import url_for
Expand Down Expand Up @@ -54,6 +54,12 @@
DEFAULT_PROCESS_TYPE = TemplateProcessTypes.BULK.value


@pytest.fixture
def mock_notification_counts_client():
with patch("app.main.views.templates.notification_counts_client") as mock:
yield mock


class TestRedisPreviewUtilities:
def test_set_get(self, fake_uuid, mocker):
mock_redis_obj = MockRedis()
Expand Down Expand Up @@ -2742,3 +2748,64 @@ def test_should_hide_category_name_from_template_list_if_marked_hidden(
# assert that "HIDDEN_CATEGORY" is not found anywhere in the page using beautifulsoup
assert "HIDDEN_CATEGORY" not in page.text
assert not page.find(text="HIDDEN_CATEGORY")


class TestAnnualLimits:
@pytest.mark.parametrize(
"remaining_daily, remaining_annual, buttons_shown",
[
(10, 100, True), # Within both limits
(0, 100, False), # Exceeds daily limit
(10, 0, False), # Exceeds annual limit
(0, 0, False), # Exceeds both limits
(1, 1, True), # Exactly at both limits
],
)
def test_should_hide_send_buttons_when_appropriate(
self,
client_request,
mock_get_service_template,
mock_get_template_folders,
mock_notification_counts_client,
fake_uuid,
remaining_daily,
remaining_annual,
buttons_shown,
):
mock_notification_counts_client.get_limit_stats.return_value = {
"email": {
"annual": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_annual, # The number of email notifications remaining this year
},
"daily": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_daily, # The number of email notifications remaining today
},
},
"sms": {
"annual": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_annual, # The number of email notifications remaining this year
},
"daily": {
"limit": 1, # doesn't matter for our test
"sent": 1, # doesn't matter for our test
"remaining": remaining_daily, # The number of email notifications remaining today
},
},
}

page = client_request.get(
".view_template",
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_test_page_title=False,
)
if buttons_shown:
assert page.find(attrs={"data-testid": "send-buttons"}) is not None
else:
assert page.find(attrs={"data-testid": "send-buttons"}) is None
112 changes: 111 additions & 1 deletion tests/app/notify_client/test_notification_counts_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from unittest.mock import patch
from datetime import datetime
from unittest.mock import Mock, patch

import pytest

Expand All @@ -23,6 +24,12 @@ def mock_service_api():
yield mock


@pytest.fixture
def mock_get_all_notification_counts_for_today():
with patch("app.notify_client.notification_counts_client.get_all_notification_counts_for_today") as mock:
yield mock


class TestNotificationCounts:
def test_get_all_notification_counts_for_today_redis_has_data(self, mock_redis):
# Setup
Expand Down Expand Up @@ -87,3 +94,106 @@ def test_get_all_notification_counts_for_year(self, mock_service_api):
# Assert
assert result["sms"] == 29 # 1 + 22 + 1 + 5
assert result["email"] == 21 # 1 + 1 + 12 + 1 + 1 + 5

def test_get_limit_stats(self, mocker):
# Setup
mock_service = Mock(id="service-1", email_annual_limit=1000, sms_annual_limit=500, message_limit=100, sms_daily_limit=50)

mock_notification_client = NotificationCounts()

# Mock the dependency methods

mocker.patch.object(
mock_notification_client, "get_all_notification_counts_for_today", return_value={"email": 20, "sms": 10}
)
mocker.patch.object(
mock_notification_client, "get_all_notification_counts_for_year", return_value={"email": 200, "sms": 100}
)

# Execute
result = mock_notification_client.get_limit_stats(mock_service)

# Assert
assert result == {
"email": {
"annual": {
"limit": 1000,
"sent": 200,
"remaining": 800,
},
"daily": {
"limit": 100,
"sent": 20,
"remaining": 80,
},
},
"sms": {
"annual": {
"limit": 500,
"sent": 100,
"remaining": 400,
},
"daily": {
"limit": 50,
"sent": 10,
"remaining": 40,
},
},
}

@pytest.mark.parametrize(
"today_counts,year_counts,expected_remaining",
[
(
{"email": 0, "sms": 0},
{"email": 0, "sms": 0},
{"email": {"annual": 1000, "daily": 100}, "sms": {"annual": 500, "daily": 50}},
),
(
{"email": 100, "sms": 50},
{"email": 1000, "sms": 500},
{"email": {"annual": 0, "daily": 0}, "sms": {"annual": 0, "daily": 0}},
),
(
{"email": 50, "sms": 25},
{"email": 500, "sms": 250},
{"email": {"annual": 500, "daily": 50}, "sms": {"annual": 250, "daily": 25}},
),
],
)
def test_get_limit_stats_remaining_calculations(self, mocker, today_counts, year_counts, expected_remaining):
# Setup
mock_service = Mock(id="service-1", email_annual_limit=1000, sms_annual_limit=500, message_limit=100, sms_daily_limit=50)

mock_notification_client = NotificationCounts()

mocker.patch.object(mock_notification_client, "get_all_notification_counts_for_today", return_value=today_counts)
mocker.patch.object(mock_notification_client, "get_all_notification_counts_for_year", return_value=year_counts)

# Execute
result = mock_notification_client.get_limit_stats(mock_service)

# Assert remaining counts
assert result["email"]["annual"]["remaining"] == expected_remaining["email"]["annual"]
assert result["email"]["daily"]["remaining"] == expected_remaining["email"]["daily"]
assert result["sms"]["annual"]["remaining"] == expected_remaining["sms"]["annual"]
assert result["sms"]["daily"]["remaining"] == expected_remaining["sms"]["daily"]

def test_get_limit_stats_dependencies_called(self, mocker):
# Setup
mock_service = Mock(id="service-1", email_annual_limit=1000, sms_annual_limit=500, message_limit=100, sms_daily_limit=50)
mock_notification_client = NotificationCounts()

mock_today = mocker.patch.object(
mock_notification_client, "get_all_notification_counts_for_today", return_value={"email": 0, "sms": 0}
)
mock_year = mocker.patch.object(
mock_notification_client, "get_all_notification_counts_for_year", return_value={"email": 0, "sms": 0}
)

# Execute
mock_notification_client.get_limit_stats(mock_service)

# Assert dependencies called
mock_today.assert_called_once_with(mock_service.id)
mock_year.assert_called_once_with(mock_service.id, datetime.now().year)

0 comments on commit 31780b4

Please sign in to comment.