2023-08-14 07:21:18 -07:00
|
|
|
|
import os
|
2024-10-23 11:08:06 -07:00
|
|
|
|
from datetime import datetime, timedelta
|
2024-10-23 10:24:08 -07:00
|
|
|
|
from unittest.mock import MagicMock, mock_open
|
2023-08-11 15:02:34 -07:00
|
|
|
|
|
2022-03-22 09:46:26 +00:00
|
|
|
|
import pytest
|
2024-10-30 08:54:48 -07:00
|
|
|
|
from sqlalchemy import select
|
2022-03-22 09:46:26 +00:00
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
from app import db
|
2022-02-28 18:18:02 +00:00
|
|
|
|
from app.commands import (
|
2023-02-03 10:11:21 -05:00
|
|
|
|
_update_template,
|
2023-09-21 14:48:10 -07:00
|
|
|
|
bulk_invite_user_to_service,
|
2023-08-30 13:13:43 -07:00
|
|
|
|
create_new_service,
|
2022-10-28 14:07:43 -04:00
|
|
|
|
create_test_user,
|
2024-08-01 08:19:33 -07:00
|
|
|
|
download_csv_file_by_name,
|
2024-10-23 13:02:45 -07:00
|
|
|
|
dump_sms_senders,
|
|
|
|
|
|
dump_user_info,
|
2023-08-11 11:47:57 -07:00
|
|
|
|
fix_billable_units,
|
2022-02-28 18:18:02 +00:00
|
|
|
|
insert_inbound_numbers_from_file,
|
2022-03-22 09:46:26 +00:00
|
|
|
|
populate_annual_billing_with_defaults,
|
2023-08-10 12:58:52 -07:00
|
|
|
|
populate_annual_billing_with_the_previous_years_allowance,
|
2024-10-23 10:24:08 -07:00
|
|
|
|
populate_go_live,
|
2023-08-14 07:41:17 -07:00
|
|
|
|
populate_organization_agreement_details_from_file,
|
2023-08-14 07:21:18 -07:00
|
|
|
|
populate_organizations_from_file,
|
2024-10-23 11:45:20 -07:00
|
|
|
|
process_row_from_job,
|
2023-11-06 13:31:03 -08:00
|
|
|
|
promote_user_to_platform_admin,
|
2023-08-11 13:48:45 -07:00
|
|
|
|
purge_functional_test_data,
|
2023-08-11 15:02:34 -07:00
|
|
|
|
update_jobs_archived_flag,
|
2022-02-28 18:18:02 +00:00
|
|
|
|
)
|
|
|
|
|
|
from app.dao.inbound_numbers_dao import dao_get_available_inbound_numbers
|
2023-11-06 13:31:03 -08:00
|
|
|
|
from app.dao.users_dao import get_user_by_email
|
2024-01-30 10:18:53 -05:00
|
|
|
|
from app.enums import (
|
|
|
|
|
|
AuthType,
|
|
|
|
|
|
KeyType,
|
|
|
|
|
|
NotificationStatus,
|
|
|
|
|
|
NotificationType,
|
|
|
|
|
|
OrganizationType,
|
|
|
|
|
|
TemplateType,
|
|
|
|
|
|
)
|
2023-08-14 07:21:18 -07:00
|
|
|
|
from app.models import (
|
|
|
|
|
|
AnnualBilling,
|
|
|
|
|
|
Job,
|
|
|
|
|
|
Notification,
|
|
|
|
|
|
Organization,
|
2023-08-30 13:13:43 -07:00
|
|
|
|
Service,
|
2023-08-14 07:21:18 -07:00
|
|
|
|
Template,
|
|
|
|
|
|
User,
|
|
|
|
|
|
)
|
2024-05-23 13:59:51 -07:00
|
|
|
|
from app.utils import utc_now
|
2023-08-10 12:58:52 -07:00
|
|
|
|
from tests.app.db import (
|
|
|
|
|
|
create_annual_billing,
|
2023-08-11 15:02:34 -07:00
|
|
|
|
create_job,
|
2023-08-11 11:47:57 -07:00
|
|
|
|
create_notification,
|
2023-08-14 07:41:17 -07:00
|
|
|
|
create_organization,
|
2023-08-10 12:58:52 -07:00
|
|
|
|
create_service,
|
2023-08-11 15:02:34 -07:00
|
|
|
|
create_template,
|
2023-08-10 12:58:52 -07:00
|
|
|
|
)
|
|
|
|
|
|
|
2023-08-11 13:48:45 -07:00
|
|
|
|
|
2023-08-11 14:42:21 -07:00
|
|
|
|
def test_purge_functional_test_data(notify_db_session, notify_api):
|
|
|
|
|
|
orig_user_count = User.query.count()
|
2023-08-11 13:48:45 -07:00
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
create_test_user,
|
|
|
|
|
|
[
|
|
|
|
|
|
"--email",
|
|
|
|
|
|
"somebody+7af2cdb0-7cbc-44dc-a5d0-f817fc6ee94e@fake.gov",
|
|
|
|
|
|
"--mobile_number",
|
|
|
|
|
|
"202-555-5555",
|
|
|
|
|
|
"--password",
|
|
|
|
|
|
"correct horse battery staple",
|
|
|
|
|
|
"--name",
|
|
|
|
|
|
"Fake Humanson",
|
|
|
|
|
|
],
|
2023-08-11 13:48:45 -07:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
user_count = User.query.count()
|
2023-08-11 14:42:21 -07:00
|
|
|
|
assert user_count == orig_user_count + 1
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_api.test_cli_runner().invoke(purge_functional_test_data, ["-u", "somebody"])
|
2023-08-11 13:48:45 -07:00
|
|
|
|
# if the email address has a uuid, it is test data so it should be purged and there should be
|
|
|
|
|
|
# zero users. Otherwise, it is real data so there should be one user.
|
2023-08-11 14:42:21 -07:00
|
|
|
|
assert User.query.count() == orig_user_count
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-14 07:21:18 -07:00
|
|
|
|
def test_purge_functional_test_data_bad_mobile(notify_db_session, notify_api):
|
|
|
|
|
|
user_count = User.query.count()
|
|
|
|
|
|
assert user_count == 0
|
|
|
|
|
|
# run the command
|
2023-08-15 11:44:47 -07:00
|
|
|
|
command_response = notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
create_test_user,
|
|
|
|
|
|
[
|
|
|
|
|
|
"--email",
|
|
|
|
|
|
"somebody+7af2cdb0-7cbc-44dc-a5d0-f817fc6ee94e@fake.gov",
|
|
|
|
|
|
"--mobile_number",
|
|
|
|
|
|
"555-555-55554444",
|
|
|
|
|
|
"--password",
|
|
|
|
|
|
"correct horse battery staple",
|
|
|
|
|
|
"--name",
|
|
|
|
|
|
"Fake Personson",
|
|
|
|
|
|
],
|
2023-08-14 07:21:18 -07:00
|
|
|
|
)
|
2024-10-22 10:07:00 -07:00
|
|
|
|
# The bad mobile phone number results in a bad parameter error,
|
|
|
|
|
|
# leading to a system exit 2 and no entry made in db
|
2023-08-15 11:44:47 -07:00
|
|
|
|
assert "SystemExit(2)" in str(command_response)
|
2023-08-14 07:21:18 -07:00
|
|
|
|
user_count = User.query.count()
|
|
|
|
|
|
assert user_count == 0
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-11 15:02:34 -07:00
|
|
|
|
def test_update_jobs_archived_flag(notify_db_session, notify_api):
|
|
|
|
|
|
service = create_service()
|
|
|
|
|
|
|
2024-01-29 16:04:22 -05:00
|
|
|
|
sms_template = create_template(service=service, template_type=TemplateType.SMS)
|
2023-08-11 15:02:34 -07:00
|
|
|
|
create_job(sms_template)
|
|
|
|
|
|
|
2024-05-23 13:59:51 -07:00
|
|
|
|
right_now = utc_now()
|
2024-10-23 11:17:03 -07:00
|
|
|
|
tomorrow = right_now + timedelta(days=1)
|
2023-08-11 15:02:34 -07:00
|
|
|
|
|
|
|
|
|
|
right_now = right_now.strftime("%Y-%m-%d")
|
|
|
|
|
|
tomorrow = tomorrow.strftime("%Y-%m-%d")
|
|
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
stmt = select(Job).where(Job.archived is True)
|
2024-10-30 09:20:26 -07:00
|
|
|
|
archived_jobs = db.session.execute(stmt).scalar() or 0
|
2023-08-11 15:02:34 -07:00
|
|
|
|
assert archived_jobs == 0
|
|
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
update_jobs_archived_flag,
|
|
|
|
|
|
[
|
|
|
|
|
|
"-e",
|
|
|
|
|
|
tomorrow,
|
|
|
|
|
|
"-s",
|
|
|
|
|
|
right_now,
|
|
|
|
|
|
],
|
2023-08-11 15:02:34 -07:00
|
|
|
|
)
|
|
|
|
|
|
jobs = Job.query.all()
|
|
|
|
|
|
assert len(jobs) == 1
|
|
|
|
|
|
for job in jobs:
|
|
|
|
|
|
assert job.archived is True
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-14 07:21:18 -07:00
|
|
|
|
def test_populate_organizations_from_file(notify_db_session, notify_api):
|
|
|
|
|
|
org_count = Organization.query.count()
|
|
|
|
|
|
assert org_count == 0
|
|
|
|
|
|
|
|
|
|
|
|
file_name = "./tests/app/orgs1.csv"
|
2023-08-29 14:54:30 -07:00
|
|
|
|
text = "name|blah|blah|blah|||\n" "foo|Federal|True|'foo.gov'|'foo.gov'||\n"
|
2023-08-14 07:21:18 -07:00
|
|
|
|
f = open(file_name, "a")
|
|
|
|
|
|
f.write(text)
|
|
|
|
|
|
f.close()
|
2023-08-15 11:44:47 -07:00
|
|
|
|
command_response = notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_organizations_from_file, ["-f", file_name]
|
2023-08-14 07:21:18 -07:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
os.remove(file_name)
|
2023-08-15 11:44:47 -07:00
|
|
|
|
print(f"command_response = {command_response}")
|
2023-08-14 07:21:18 -07:00
|
|
|
|
|
|
|
|
|
|
org_count = Organization.query.count()
|
|
|
|
|
|
assert org_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
def test_populate_organization_agreement_details_from_file(
|
|
|
|
|
|
notify_db_session, notify_api
|
|
|
|
|
|
):
|
2023-08-14 07:41:17 -07:00
|
|
|
|
file_name = "./tests/app/orgs.csv"
|
|
|
|
|
|
|
|
|
|
|
|
org_count = Organization.query.count()
|
|
|
|
|
|
assert org_count == 0
|
|
|
|
|
|
create_organization()
|
|
|
|
|
|
org_count = Organization.query.count()
|
|
|
|
|
|
assert org_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
org = Organization.query.one()
|
|
|
|
|
|
org.agreement_signed = True
|
|
|
|
|
|
notify_db_session.commit()
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
text = (
|
|
|
|
|
|
"id,agreement_signed_version,agreement_signed_on_behalf_of_name,agreement_signed_at\n"
|
|
|
|
|
|
f"{org.id},1,bob,'2023-01-01 00:00:00'\n"
|
|
|
|
|
|
)
|
2023-08-14 07:41:17 -07:00
|
|
|
|
f = open(file_name, "a")
|
|
|
|
|
|
f.write(text)
|
|
|
|
|
|
f.close()
|
2023-08-15 11:44:47 -07:00
|
|
|
|
command_response = notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_organization_agreement_details_from_file, ["-f", file_name]
|
2023-08-14 07:41:17 -07:00
|
|
|
|
)
|
2023-08-15 11:44:47 -07:00
|
|
|
|
print(f"command_response = {command_response}")
|
2023-08-14 07:41:17 -07:00
|
|
|
|
|
|
|
|
|
|
org_count = Organization.query.count()
|
|
|
|
|
|
assert org_count == 1
|
|
|
|
|
|
org = Organization.query.one()
|
2023-08-29 14:54:30 -07:00
|
|
|
|
assert org.agreement_signed_on_behalf_of_name == "bob"
|
2023-08-14 07:41:17 -07:00
|
|
|
|
os.remove(file_name)
|
2021-09-08 09:45:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
2023-09-21 14:48:10 -07:00
|
|
|
|
def test_bulk_invite_user_to_service(
|
|
|
|
|
|
notify_db_session, notify_api, sample_service, sample_user
|
|
|
|
|
|
):
|
|
|
|
|
|
file_name = "./tests/app/users.csv"
|
|
|
|
|
|
|
|
|
|
|
|
text = (
|
|
|
|
|
|
"service,email_address,from_user,permissions,auth_type,invite_link_host\n"
|
|
|
|
|
|
f"{sample_service.id},someone@fake.gov,{sample_user.id},sms,platform_admin,https://somewhere.fake.gov'\n"
|
|
|
|
|
|
)
|
|
|
|
|
|
f = open(file_name, "a")
|
|
|
|
|
|
f.write(text)
|
|
|
|
|
|
f.close()
|
|
|
|
|
|
command_response = notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
bulk_invite_user_to_service,
|
|
|
|
|
|
[
|
|
|
|
|
|
"-f",
|
|
|
|
|
|
file_name,
|
|
|
|
|
|
"-s",
|
|
|
|
|
|
sample_service.id,
|
|
|
|
|
|
"-u",
|
|
|
|
|
|
sample_user.id,
|
|
|
|
|
|
"-p",
|
|
|
|
|
|
"send_texts",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
print(f"command_response = {command_response}")
|
|
|
|
|
|
|
|
|
|
|
|
assert "okay" in str(command_response)
|
|
|
|
|
|
|
|
|
|
|
|
os.remove(file_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-10-28 14:07:43 -04:00
|
|
|
|
def test_create_test_user_command(notify_db_session, notify_api):
|
|
|
|
|
|
# number of users before adding ours
|
2023-08-14 07:41:17 -07:00
|
|
|
|
user_count = User.query.count()
|
2022-10-28 14:42:25 -04:00
|
|
|
|
|
2022-10-28 14:07:43 -04:00
|
|
|
|
# run the command
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
create_test_user,
|
|
|
|
|
|
[
|
|
|
|
|
|
"--email",
|
|
|
|
|
|
"somebody@fake.gov",
|
|
|
|
|
|
"--mobile_number",
|
|
|
|
|
|
"202-555-5555",
|
|
|
|
|
|
"--password",
|
|
|
|
|
|
"correct horse battery staple",
|
|
|
|
|
|
"--name",
|
|
|
|
|
|
"Fake Personson",
|
|
|
|
|
|
],
|
2022-10-28 14:07:43 -04:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# there should be one more user
|
2023-08-14 07:41:17 -07:00
|
|
|
|
assert User.query.count() == user_count + 1
|
2022-10-28 14:07:43 -04:00
|
|
|
|
|
|
|
|
|
|
# that user should be the one we added
|
2024-10-30 09:20:26 -07:00
|
|
|
|
stmt = select(User).where(User.name == "Fake Personson")
|
2024-10-30 09:28:12 -07:00
|
|
|
|
user = db.session.execute(stmt).scalars().first()
|
2023-08-29 14:54:30 -07:00
|
|
|
|
assert user.email_address == "somebody@fake.gov"
|
2024-01-29 16:09:27 -05:00
|
|
|
|
assert user.auth_type == AuthType.SMS
|
2023-08-29 14:54:30 -07:00
|
|
|
|
assert user.state == "active"
|
2022-10-28 14:07:43 -04:00
|
|
|
|
|
|
|
|
|
|
|
2022-02-28 18:18:02 +00:00
|
|
|
|
def test_insert_inbound_numbers_from_file(notify_db_session, notify_api, tmpdir):
|
|
|
|
|
|
numbers_file = tmpdir.join("numbers.txt")
|
|
|
|
|
|
numbers_file.write("07700900373\n07700900473\n07700900375\n\n\n\n")
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
insert_inbound_numbers_from_file, ["-f", numbers_file]
|
|
|
|
|
|
)
|
2022-02-28 18:18:02 +00:00
|
|
|
|
|
|
|
|
|
|
inbound_numbers = dao_get_available_inbound_numbers()
|
|
|
|
|
|
assert len(inbound_numbers) == 3
|
2023-08-29 14:54:30 -07:00
|
|
|
|
assert set(x.number for x in inbound_numbers) == {
|
|
|
|
|
|
"07700900373",
|
|
|
|
|
|
"07700900473",
|
|
|
|
|
|
"07700900375",
|
|
|
|
|
|
}
|
2022-02-28 18:18:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
@pytest.mark.parametrize(
|
2024-01-29 16:04:22 -05:00
|
|
|
|
"organization_type, expected_allowance",
|
|
|
|
|
|
[(OrganizationType.FEDERAL, 40000), (OrganizationType.STATE, 40000)],
|
2023-08-29 14:54:30 -07:00
|
|
|
|
)
|
2022-03-22 09:46:26 +00:00
|
|
|
|
def test_populate_annual_billing_with_defaults(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_db_session, notify_api, organization_type, expected_allowance
|
2022-03-22 09:46:26 +00:00
|
|
|
|
):
|
2023-08-29 14:54:30 -07:00
|
|
|
|
service = create_service(
|
2024-02-21 12:35:18 -05:00
|
|
|
|
service_name=organization_type,
|
|
|
|
|
|
organization_type=organization_type,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
)
|
2022-03-22 09:46:26 +00:00
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_annual_billing_with_defaults, ["-y", 2022]
|
2022-03-22 09:46:26 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
stmt = select(AnnualBilling).where(
|
2022-03-22 09:46:26 +00:00
|
|
|
|
AnnualBilling.financial_year_start == 2022,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
AnnualBilling.service_id == service.id,
|
2024-10-30 08:54:48 -07:00
|
|
|
|
)
|
|
|
|
|
|
results = db.session.execute(stmt).scalars().all()
|
2022-03-22 09:46:26 +00:00
|
|
|
|
|
|
|
|
|
|
assert len(results) == 1
|
|
|
|
|
|
assert results[0].free_sms_fragment_limit == expected_allowance
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
@pytest.mark.parametrize(
|
2024-01-29 16:04:22 -05:00
|
|
|
|
"organization_type, expected_allowance",
|
|
|
|
|
|
[(OrganizationType.FEDERAL, 40000), (OrganizationType.STATE, 40000)],
|
2023-08-29 14:54:30 -07:00
|
|
|
|
)
|
2023-08-10 12:58:52 -07:00
|
|
|
|
def test_populate_annual_billing_with_the_previous_years_allowance(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_db_session, notify_api, organization_type, expected_allowance
|
2023-08-10 12:58:52 -07:00
|
|
|
|
):
|
2023-08-29 14:54:30 -07:00
|
|
|
|
service = create_service(
|
2024-02-21 12:35:18 -05:00
|
|
|
|
service_name=organization_type,
|
|
|
|
|
|
organization_type=organization_type,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
)
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_annual_billing_with_defaults, ["-y", 2022]
|
2023-08-10 12:58:52 -07:00
|
|
|
|
)
|
|
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
stmt = select(AnnualBilling).where(
|
2023-08-10 12:58:52 -07:00
|
|
|
|
AnnualBilling.financial_year_start == 2022,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
AnnualBilling.service_id == service.id,
|
2024-10-30 08:54:48 -07:00
|
|
|
|
)
|
|
|
|
|
|
results = db.session.execute(stmt).scalars().all()
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
assert len(results) == 1
|
|
|
|
|
|
assert results[0].free_sms_fragment_limit == expected_allowance
|
|
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_annual_billing_with_the_previous_years_allowance, ["-y", 2023]
|
2023-08-10 12:58:52 -07:00
|
|
|
|
)
|
|
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
stmt = select(AnnualBilling).where(
|
2023-08-10 12:58:52 -07:00
|
|
|
|
AnnualBilling.financial_year_start == 2023,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
AnnualBilling.service_id == service.id,
|
2024-10-30 08:54:48 -07:00
|
|
|
|
)
|
|
|
|
|
|
results = db.session.execute(stmt).scalars().all()
|
2023-08-10 12:58:52 -07:00
|
|
|
|
|
|
|
|
|
|
assert len(results) == 1
|
|
|
|
|
|
assert results[0].free_sms_fragment_limit == expected_allowance
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-08-11 11:47:57 -07:00
|
|
|
|
def test_fix_billable_units(notify_db_session, notify_api, sample_template):
|
|
|
|
|
|
create_notification(template=sample_template)
|
|
|
|
|
|
notification = Notification.query.one()
|
2023-08-14 09:04:06 -07:00
|
|
|
|
notification.billable_units = 0
|
2024-02-28 12:41:57 -05:00
|
|
|
|
notification.notification_type = NotificationType.SMS
|
2024-01-16 14:46:17 -05:00
|
|
|
|
notification.status = NotificationStatus.DELIVERED
|
2023-08-14 09:04:06 -07:00
|
|
|
|
notification.sent_at = None
|
2024-01-16 14:46:17 -05:00
|
|
|
|
notification.key_type = KeyType.NORMAL
|
2023-08-14 09:04:06 -07:00
|
|
|
|
|
|
|
|
|
|
notify_db_session.commit()
|
2023-08-11 11:47:57 -07:00
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_api.test_cli_runner().invoke(fix_billable_units, [])
|
2023-08-11 11:47:57 -07:00
|
|
|
|
|
|
|
|
|
|
notification = Notification.query.one()
|
|
|
|
|
|
assert notification.billable_units == 1
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-03-22 09:46:26 +00:00
|
|
|
|
def test_populate_annual_billing_with_defaults_sets_free_allowance_to_zero_if_previous_year_is_zero(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
notify_db_session, notify_api
|
2022-03-22 09:46:26 +00:00
|
|
|
|
):
|
2024-01-25 16:16:04 -05:00
|
|
|
|
service = create_service(organization_type=OrganizationType.FEDERAL)
|
2023-08-29 14:54:30 -07:00
|
|
|
|
create_annual_billing(
|
|
|
|
|
|
service_id=service.id, free_sms_fragment_limit=0, financial_year_start=2021
|
|
|
|
|
|
)
|
2022-03-22 09:46:26 +00:00
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-08-29 14:54:30 -07:00
|
|
|
|
populate_annual_billing_with_defaults, ["-y", 2022]
|
2022-03-22 09:46:26 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
2024-10-30 08:54:48 -07:00
|
|
|
|
stmt = select(AnnualBilling).where(
|
2022-03-22 09:46:26 +00:00
|
|
|
|
AnnualBilling.financial_year_start == 2022,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
AnnualBilling.service_id == service.id,
|
2024-10-30 08:54:48 -07:00
|
|
|
|
)
|
|
|
|
|
|
results = db.session.execute(stmt).scalars().all()
|
2022-03-22 09:46:26 +00:00
|
|
|
|
|
|
|
|
|
|
assert len(results) == 1
|
|
|
|
|
|
assert results[0].free_sms_fragment_limit == 0
|
2023-02-03 10:11:21 -05:00
|
|
|
|
|
|
|
|
|
|
|
2023-08-29 14:54:30 -07:00
|
|
|
|
def test_update_template(notify_db_session, email_2fa_code_template):
|
2023-02-03 10:11:21 -05:00
|
|
|
|
_update_template(
|
|
|
|
|
|
"299726d2-dba6-42b8-8209-30e1d66ea164",
|
|
|
|
|
|
"Example text message template!",
|
2024-02-09 12:24:09 -05:00
|
|
|
|
TemplateType.SMS,
|
2023-08-29 14:54:30 -07:00
|
|
|
|
[
|
2023-08-31 08:14:23 -07:00
|
|
|
|
"Hi, I’m trying out Notify.gov! Today is ((day of week)) and my favorite color is ((color))."
|
2023-08-29 14:54:30 -07:00
|
|
|
|
],
|
|
|
|
|
|
"",
|
2023-02-03 10:11:21 -05:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
t = Template.query.all()
|
|
|
|
|
|
|
|
|
|
|
|
assert t[0].name == "Example text message template!"
|
2023-08-30 13:13:43 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_create_service_command(notify_db_session, notify_api):
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
create_test_user,
|
|
|
|
|
|
[
|
|
|
|
|
|
"--email",
|
|
|
|
|
|
"somebody@fake.gov",
|
|
|
|
|
|
"--mobile_number",
|
|
|
|
|
|
"202-555-5555",
|
|
|
|
|
|
"--password",
|
|
|
|
|
|
"correct horse battery staple",
|
|
|
|
|
|
"--name",
|
|
|
|
|
|
"Fake Personson",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
user = User.query.first()
|
|
|
|
|
|
|
|
|
|
|
|
service_count = Service.query.count()
|
|
|
|
|
|
|
|
|
|
|
|
# run the command
|
|
|
|
|
|
result = notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
create_new_service,
|
|
|
|
|
|
["-e", "somebody@fake.gov", "-n", "Fake Service", "-c", user.id],
|
|
|
|
|
|
)
|
|
|
|
|
|
print(result)
|
|
|
|
|
|
|
|
|
|
|
|
# there should be one more service
|
|
|
|
|
|
assert Service.query.count() == service_count + 1
|
|
|
|
|
|
|
|
|
|
|
|
# that service should be the one we added
|
2024-10-30 09:08:58 -07:00
|
|
|
|
stmt = select(Service).where(Service.name == "Fake Service")
|
2024-10-30 09:20:26 -07:00
|
|
|
|
service = db.session.execute(stmt).scalars().first()
|
2023-08-30 13:13:43 -07:00
|
|
|
|
assert service.email_from == "somebody@fake.gov"
|
|
|
|
|
|
assert service.restricted is False
|
|
|
|
|
|
assert service.message_limit == 40000
|
2023-11-06 13:31:03 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_promote_user_to_platform_admin(
|
|
|
|
|
|
notify_db_session, notify_api, sample_user, sample_platform_admin
|
|
|
|
|
|
):
|
|
|
|
|
|
assert sample_user.platform_admin is False
|
|
|
|
|
|
assert sample_platform_admin.platform_admin is True
|
|
|
|
|
|
|
2023-11-07 07:08:42 -08:00
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2023-11-06 13:31:03 -08:00
|
|
|
|
promote_user_to_platform_admin,
|
|
|
|
|
|
[
|
|
|
|
|
|
"-u",
|
|
|
|
|
|
"notify@digital.fake.gov",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
user = get_user_by_email("notify@digital.fake.gov")
|
|
|
|
|
|
assert user.platform_admin is True
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-08-01 10:38:58 -07:00
|
|
|
|
def test_download_csv_file_by_name(notify_api, mocker):
|
|
|
|
|
|
mock_download = mocker.patch("app.commands.s3.download_from_s3")
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
2024-08-01 08:19:33 -07:00
|
|
|
|
download_csv_file_by_name,
|
|
|
|
|
|
[
|
2024-08-01 10:38:58 -07:00
|
|
|
|
"-f",
|
2024-08-01 08:19:33 -07:00
|
|
|
|
"NonExistentName",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
2024-08-01 10:38:58 -07:00
|
|
|
|
mock_download.assert_called_once()
|
2024-08-01 08:19:33 -07:00
|
|
|
|
|
|
|
|
|
|
|
2023-11-06 13:31:03 -08:00
|
|
|
|
def test_promote_user_to_platform_admin_no_result_found(
|
2024-08-01 10:38:58 -07:00
|
|
|
|
notify_db_session,
|
|
|
|
|
|
notify_api,
|
|
|
|
|
|
sample_user,
|
2023-11-06 13:31:03 -08:00
|
|
|
|
):
|
|
|
|
|
|
assert sample_user.platform_admin is False
|
|
|
|
|
|
|
|
|
|
|
|
result = notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
promote_user_to_platform_admin,
|
|
|
|
|
|
[
|
|
|
|
|
|
"-u",
|
|
|
|
|
|
"notify@digital.fake.asefasefasefasef",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
assert "NoResultFound" in str(result)
|
|
|
|
|
|
assert sample_user.platform_admin is False
|
2024-10-23 10:24:08 -07:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-23 10:54:47 -07:00
|
|
|
|
def test_populate_go_live_success(notify_api, mocker):
|
2024-10-23 10:24:08 -07:00
|
|
|
|
mock_csv_reader = mocker.patch("app.commands.csv.reader")
|
|
|
|
|
|
mocker.patch(
|
|
|
|
|
|
"app.commands.open",
|
|
|
|
|
|
new_callable=mock_open,
|
|
|
|
|
|
read_data="""count,Link,Service ID,DEPT,Service Name,Main contact,Contact detail,MOU,LIVE date,SMS,Email,Letters,CRM,Blue badge\n1,link,123,Dept A,Service A,Contact A,email@example.com,MOU,15/10/2024,Yes,Yes,Yes,Yes,No""", # noqa
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_current_app = mocker.patch("app.commands.current_app")
|
|
|
|
|
|
mock_logger = mock_current_app.logger
|
|
|
|
|
|
mock_dao_update_service = mocker.patch("app.commands.dao_update_service")
|
|
|
|
|
|
mock_dao_fetch_service_by_id = mocker.patch("app.commands.dao_fetch_service_by_id")
|
|
|
|
|
|
mock_get_user_by_email = mocker.patch("app.commands.get_user_by_email")
|
|
|
|
|
|
mock_csv_reader.return_value = iter(
|
|
|
|
|
|
[
|
|
|
|
|
|
[
|
|
|
|
|
|
"count",
|
|
|
|
|
|
"Link",
|
|
|
|
|
|
"Service ID",
|
|
|
|
|
|
"DEPT",
|
|
|
|
|
|
"Service Name",
|
|
|
|
|
|
"Main contract",
|
|
|
|
|
|
"Contact detail",
|
|
|
|
|
|
"MOU",
|
|
|
|
|
|
"LIVE date",
|
|
|
|
|
|
"SMS",
|
|
|
|
|
|
"Email",
|
|
|
|
|
|
"Letters",
|
|
|
|
|
|
"CRM",
|
|
|
|
|
|
"Blue badge",
|
|
|
|
|
|
],
|
|
|
|
|
|
[
|
|
|
|
|
|
"1",
|
|
|
|
|
|
"link",
|
|
|
|
|
|
"123",
|
|
|
|
|
|
"Dept A",
|
|
|
|
|
|
"Service A",
|
|
|
|
|
|
"Contact A",
|
|
|
|
|
|
"email@example.com",
|
|
|
|
|
|
"MOU",
|
|
|
|
|
|
"15/10/2024",
|
|
|
|
|
|
"Yes",
|
|
|
|
|
|
"Yes",
|
|
|
|
|
|
"Yes",
|
|
|
|
|
|
"Yes",
|
|
|
|
|
|
"No",
|
|
|
|
|
|
],
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_user = MagicMock()
|
|
|
|
|
|
mock_get_user_by_email.return_value = mock_user
|
|
|
|
|
|
mock_service = MagicMock()
|
|
|
|
|
|
mock_dao_fetch_service_by_id.return_value = mock_service
|
|
|
|
|
|
|
2024-10-23 10:54:47 -07:00
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
populate_go_live,
|
|
|
|
|
|
[
|
|
|
|
|
|
"-f",
|
|
|
|
|
|
"dummy_file.csv",
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
2024-10-23 10:24:08 -07:00
|
|
|
|
|
|
|
|
|
|
mock_get_user_by_email.assert_called_once_with("email@example.com")
|
|
|
|
|
|
mock_dao_fetch_service_by_id.assert_called_once_with("123")
|
|
|
|
|
|
mock_service.go_live_user = mock_user
|
2024-10-23 11:08:06 -07:00
|
|
|
|
mock_service.go_live_at = datetime.strptime("15/10/2024", "%d/%m/%Y") + timedelta(
|
|
|
|
|
|
hours=12
|
|
|
|
|
|
)
|
2024-10-23 10:24:08 -07:00
|
|
|
|
mock_dao_update_service.assert_called_once_with(mock_service)
|
|
|
|
|
|
|
|
|
|
|
|
mock_logger.info.assert_any_call("Populate go live user and date")
|
2024-10-23 11:45:20 -07:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-23 12:28:24 -07:00
|
|
|
|
def test_process_row_from_job_success(notify_api, mocker):
|
2024-10-23 11:45:20 -07:00
|
|
|
|
mock_current_app = mocker.patch("app.commands.current_app")
|
|
|
|
|
|
mock_logger = mock_current_app.logger
|
|
|
|
|
|
mock_dao_get_job_by_id = mocker.patch("app.commands.dao_get_job_by_id")
|
|
|
|
|
|
mock_dao_get_template_by_id = mocker.patch("app.commands.dao_get_template_by_id")
|
2024-10-23 12:06:34 -07:00
|
|
|
|
mock_get_job_from_s3 = mocker.patch("app.commands.s3.get_job_from_s3")
|
2024-10-23 11:45:20 -07:00
|
|
|
|
mock_recipient_csv = mocker.patch("app.commands.RecipientCSV")
|
|
|
|
|
|
mock_process_row = mocker.patch("app.commands.process_row")
|
|
|
|
|
|
|
|
|
|
|
|
mock_job = MagicMock()
|
|
|
|
|
|
mock_job.service_id = "service_123"
|
|
|
|
|
|
mock_job.id = "job_456"
|
|
|
|
|
|
mock_job.template_id = "template_789"
|
|
|
|
|
|
mock_job.template_version = 1
|
|
|
|
|
|
mock_template = MagicMock()
|
|
|
|
|
|
mock_template._as_utils_template.return_value = MagicMock(
|
|
|
|
|
|
template_type="sms", placeholders=["name", "date"]
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_row = MagicMock()
|
|
|
|
|
|
mock_row.index = 2
|
|
|
|
|
|
mock_recipient_csv.return_value.get_rows.return_value = [mock_row]
|
|
|
|
|
|
mock_dao_get_job_by_id.return_value = mock_job
|
|
|
|
|
|
mock_dao_get_template_by_id.return_value = mock_template
|
|
|
|
|
|
mock_get_job_from_s3.return_value = "some_csv_content"
|
|
|
|
|
|
mock_process_row.return_value = "notification_123"
|
2024-10-23 12:28:24 -07:00
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
process_row_from_job,
|
|
|
|
|
|
["-j", "job_456", "-n", "2"],
|
|
|
|
|
|
)
|
2024-10-23 11:45:20 -07:00
|
|
|
|
mock_dao_get_job_by_id.assert_called_once_with("job_456")
|
|
|
|
|
|
mock_dao_get_template_by_id.assert_called_once_with(
|
2024-10-23 12:28:24 -07:00
|
|
|
|
mock_job.template_id, mock_job.template_version
|
2024-10-23 11:45:20 -07:00
|
|
|
|
)
|
|
|
|
|
|
mock_get_job_from_s3.assert_called_once_with(
|
|
|
|
|
|
str(mock_job.service_id), str(mock_job.id)
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_recipient_csv.assert_called_once_with(
|
|
|
|
|
|
"some_csv_content", template_type="sms", placeholders=["name", "date"]
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_process_row.assert_called_once_with(
|
|
|
|
|
|
mock_row, mock_template._as_utils_template(), mock_job, mock_job.service
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_logger.infoassert_called_once_with(
|
|
|
|
|
|
"Process row 2 for job job_456 created notification_id: notification_123"
|
|
|
|
|
|
)
|
2024-10-23 13:02:45 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_dump_sms_senders_single_service(notify_api, mocker):
|
|
|
|
|
|
mock_get_services_by_partial_name = mocker.patch(
|
|
|
|
|
|
"app.commands.get_services_by_partial_name"
|
|
|
|
|
|
)
|
|
|
|
|
|
mock_dao_get_sms_senders_by_service_id = mocker.patch(
|
|
|
|
|
|
"app.commands.dao_get_sms_senders_by_service_id"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
mock_service = MagicMock()
|
|
|
|
|
|
mock_service.id = "service_123"
|
|
|
|
|
|
mock_get_services_by_partial_name.return_value = [mock_service]
|
|
|
|
|
|
mock_sender_1 = MagicMock()
|
|
|
|
|
|
mock_sender_1.serialize.return_value = {"name": "Sender 1", "id": "sender_1"}
|
|
|
|
|
|
mock_sender_2 = MagicMock()
|
|
|
|
|
|
mock_sender_2.serialize.return_value = {"name": "Sender 2", "id": "sender_2"}
|
|
|
|
|
|
mock_dao_get_sms_senders_by_service_id.return_value = [mock_sender_1, mock_sender_2]
|
|
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
dump_sms_senders,
|
|
|
|
|
|
["service_name"],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
mock_get_services_by_partial_name.assert_called_once_with("service_name")
|
|
|
|
|
|
mock_dao_get_sms_senders_by_service_id.assert_called_once_with("service_123")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_dump_user_info(notify_api, mocker):
|
|
|
|
|
|
mock_open_file = mocker.patch("app.commands.open", new_callable=mock_open)
|
|
|
|
|
|
mock_get_user_by_email = mocker.patch("app.commands.get_user_by_email")
|
|
|
|
|
|
mock_user = MagicMock()
|
|
|
|
|
|
mock_user.serialize.return_value = {"name": "John Doe", "email": "john@example.com"}
|
|
|
|
|
|
mock_get_user_by_email.return_value = mock_user
|
|
|
|
|
|
|
|
|
|
|
|
notify_api.test_cli_runner().invoke(
|
|
|
|
|
|
dump_user_info,
|
|
|
|
|
|
["john@example.com"],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
mock_get_user_by_email.assert_called_once_with("john@example.com")
|
|
|
|
|
|
mock_open_file.assert_called_once_with("user_download.json", "wb")
|