From c36561ee4d86c745135af0fd1184e85595b72205 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Fri, 30 Aug 2024 09:50:01 -0700 Subject: [PATCH 01/17] start load test work --- app/main/views/platform_admin.py | 43 ++++++++++++++++++- app/main/views/send.py | 5 +++ .../views/platform-admin/services.html | 4 ++ poetry.lock | 5 +-- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index f0b5983b5..b0a3da7cc 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -5,7 +5,7 @@ from collections import OrderedDict from datetime import datetime from io import StringIO -from flask import Response, abort, flash, render_template, request, url_for +from flask import Response, abort, flash, render_template, request, session, url_for from notifications_python_client.errors import HTTPError from app import ( @@ -25,17 +25,19 @@ from app.main.forms import ( DateFilterForm, RequiredDateFilterForm, ) +from app.main.views.send import _send_notification, send_notification from app.statistics_utils import ( get_formatted_percentage, get_formatted_percentage_two_dp, ) +from app.utils import hilite from app.utils.csv import Spreadsheet from app.utils.pagination import ( generate_next_dict, generate_previous_dict, get_page_from_request, ) -from app.utils.user import user_is_platform_admin +from app.utils.user import user_has_permissions, user_is_platform_admin COMPLAINT_THRESHOLD = 0.02 FAILURE_THRESHOLD = 3 @@ -771,3 +773,40 @@ def _get_user_row(r): row.append(r["password_changed_at"]) row.append(r["state"]) return row + + +@main.route( + "/platform-admin/load-test", + methods=["POST", "GET"], +) +@user_is_platform_admin +def load_test(): + # SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167") + print(hilite("ENTER LOAD TEST")) + session["recipient"] = "+14254147755" + session["placeholders"] = {"day of week": "Monday", "color": "blue"} + services = service_api_client.find_services_by_name("Test service") + services = services["data"] + + for service in services: + # print(hilite(f"WHAT IS THE TYPE OF ONE SERVICE {type(service)} {service}")) + # print("\n") + # service = json.loads(service) + # print(hilite(f"SERVICE: {service}")) + # service = service['data'] + if service["name"] is "Test service": + break + # print(hilite(f"SERVICE IS {service}")) + templates = service_api_client.get_service_templates(service["id"]) + templates = templates["data"] + # templates = json.loads(templates) + # print(hilite(f"TEMPLATES are {templates}")) + example_template = None + for template in templates: + # template = json.loads(template) + print(hilite(f"TEMPLATE {template['name']}")) + if template["name"] == "Example text message template": + print(hilite(f"FOUND EXAMPLE TEMPLATE")) + example_template = template + print(f"GOING TO SEND NOTIFICATION NOW") + _send_notification(service["id"], example_template["id"]) diff --git a/app/main/views/send.py b/app/main/views/send.py index e6843da18..dcaec8560 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -7,6 +7,7 @@ from flask import ( abort, current_app, flash, + json, redirect, render_template, request, @@ -942,6 +943,10 @@ def preview_notification(service_id, template_id): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def send_notification(service_id, template_id): + return _send_notification(service_id, template_id) + + +def _send_notification(service_id, template_id): scheduled_for = session.pop("scheduled_for", "") recipient = get_recipient() if not recipient: diff --git a/app/templates/views/platform-admin/services.html b/app/templates/views/platform-admin/services.html index 65f10e281..13b6320dc 100644 --- a/app/templates/views/platform-admin/services.html +++ b/app/templates/views/platform-admin/services.html @@ -28,6 +28,10 @@ {% if not service['active'] %}  Archived {% endif %} + {% if service['name'] == 'Test service' %} + Load Test + {% endif %} + {% endcall %} {% endcall %} diff --git a/poetry.lock b/poetry.lock index 2684ecc21..96135cf31 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1285,13 +1285,9 @@ files = [ {file = "lxml-5.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edcfa83e03370032a489430215c1e7783128808fd3e2e0a3225deee278585196"}, {file = "lxml-5.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28bf95177400066596cdbcfc933312493799382879da504633d16cf60bba735b"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a745cc98d504d5bd2c19b10c79c61c7c3df9222629f1b6210c0368177589fb8"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b590b39ef90c6b22ec0be925b211298e810b4856909c8ca60d27ffbca6c12e6"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b336b0416828022bfd5a2e3083e7f5ba54b96242159f83c7e3eebaec752f1716"}, - {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:c2faf60c583af0d135e853c86ac2735ce178f0e338a3c7f9ae8f622fd2eb788c"}, {file = "lxml-5.2.2-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:4bc6cb140a7a0ad1f7bc37e018d0ed690b7b6520ade518285dc3171f7a117905"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7ff762670cada8e05b32bf1e4dc50b140790909caa8303cfddc4d702b71ea184"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:57f0a0bbc9868e10ebe874e9f129d2917750adf008fe7b9c1598c0fbbfdde6a6"}, - {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:a6d2092797b388342c1bc932077ad232f914351932353e2e8706851c870bca1f"}, {file = "lxml-5.2.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:60499fe961b21264e17a471ec296dcbf4365fbea611bf9e303ab69db7159ce61"}, {file = "lxml-5.2.2-cp37-cp37m-win32.whl", hash = "sha256:d9b342c76003c6b9336a80efcc766748a333573abf9350f4094ee46b006ec18f"}, {file = "lxml-5.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b16db2770517b8799c79aa80f4053cd6f8b716f21f8aca962725a9565ce3ee40"}, @@ -1626,6 +1622,7 @@ files = [ {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"}, {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] From dcc805537740f7886ee8e23ffb8e9ba0422ec753 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 07:51:57 -0700 Subject: [PATCH 02/17] more work on load test --- app/main/views/platform_admin.py | 94 +++++++++---- app/main/views/send.py | 126 ++++++++++-------- app/models/user.py | 3 + .../views/platform-admin/services.html | 2 +- 4 files changed, 142 insertions(+), 83 deletions(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index b0a3da7cc..820287675 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -5,7 +5,16 @@ from collections import OrderedDict from datetime import datetime from io import StringIO -from flask import Response, abort, flash, render_template, request, session, url_for +from flask import ( + Response, + abort, + current_app, + flash, + render_template, + request, + session, + url_for, +) from notifications_python_client.errors import HTTPError from app import ( @@ -781,32 +790,69 @@ def _get_user_row(r): ) @user_is_platform_admin def load_test(): + """ + The load test assumes that a service called 'Test service' exists. It will make + the platform admin a member of this service if the platform is not already. All + messagese will be sent in this service. + """ # SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167") print(hilite("ENTER LOAD TEST")) - session["recipient"] = "+14254147755" - session["placeholders"] = {"day of week": "Monday", "color": "blue"} + service = _find_load_test_service() + _prepare_load_test_service(service) + example_template = _find_example_template(service) + + for _ in range(0, 3): + session["recipient"] = "+14254147755" + session["placeholders"] = { + "day of week": "Monday", + "color": "blue", + "phone number": "+14254147755", + } + _send_notification(service["id"], example_template["id"]) + for _ in range(0, 3): + session["recipient"] = "+14254147167" + session["placeholders"] = { + "day of week": "Monday", + "color": "blue", + "phone number": "+14254147167", + } + _send_notification(service["id"], example_template["id"]) + + return render_template("views/dashboard/dashboard.html") + + +def _find_example_template(service): + templates = service_api_client.get_service_templates(service["id"]) + templates = templates["data"] + for template in templates: + # template = json.loads(template) + if template["name"] == "Example text message template": + return template + + raise Exception("Could not find example template for load test") + + +def _find_load_test_service(): services = service_api_client.find_services_by_name("Test service") services = services["data"] for service in services: - # print(hilite(f"WHAT IS THE TYPE OF ONE SERVICE {type(service)} {service}")) - # print("\n") - # service = json.loads(service) - # print(hilite(f"SERVICE: {service}")) - # service = service['data'] - if service["name"] is "Test service": - break - # print(hilite(f"SERVICE IS {service}")) - templates = service_api_client.get_service_templates(service["id"]) - templates = templates["data"] - # templates = json.loads(templates) - # print(hilite(f"TEMPLATES are {templates}")) - example_template = None - for template in templates: - # template = json.loads(template) - print(hilite(f"TEMPLATE {template['name']}")) - if template["name"] == "Example text message template": - print(hilite(f"FOUND EXAMPLE TEMPLATE")) - example_template = template - print(f"GOING TO SEND NOTIFICATION NOW") - _send_notification(service["id"], example_template["id"]) + if service["name"] == "Test service": + return service + + raise Exception("Could not find 'Test service' for load test") + + +def _prepare_load_test_service(service): + users = user_api_client.get_all_users() + for user in users: + if user["platform_admin"] == "t": + try: + user_api_client.add_user_to_service( + service["id"], user["id"], ["send messages"] + ) + except Exception as e: + current_app.logger.warning( + f"Couldnt add user, may already be part of service" + ) + pass diff --git a/app/main/views/send.py b/app/main/views/send.py index dcaec8560..dc33cdbd9 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -621,6 +621,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, **kwargs): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def check_messages(service_id, template_id, upload_id, row_index=2): + print(hilite("ENTER check_messages")) data = _check_messages(service_id, template_id, upload_id, row_index) data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS @@ -943,64 +944,7 @@ def preview_notification(service_id, template_id): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def send_notification(service_id, template_id): - return _send_notification(service_id, template_id) - - -def _send_notification(service_id, template_id): - scheduled_for = session.pop("scheduled_for", "") - recipient = get_recipient() - if not recipient: - return redirect( - url_for( - ".send_one_off", - service_id=service_id, - template_id=template_id, - ) - ) - - keys = [] - values = [] - for k, v in session["placeholders"].items(): - keys.append(k) - values.append(v) - - data = ",".join(keys) - vals = ",".join(values) - data = f"{data}\r\n{vals}" - - filename = ( - f"one-off-{uuid.uuid4()}.csv" # {current_user.name} removed from filename - ) - my_data = {"filename": filename, "template_id": template_id, "data": data} - upload_id = s3upload(service_id, my_data) - - # To debug messages that the user reports have not been sent, we log - # the csv filename and the job id. The user will give us the file name, - # so we can search on that to obtain the job id, which we can use elsewhere - # on the API side to find out what happens to the message. - current_app.logger.info( - hilite( - f"One-off file: {filename} job_id: {upload_id} s3 location: service-{service_id}-notify/{upload_id}.csv" - ) - ) - - form = CsvUploadForm() - form.file.data = my_data - form.file.name = filename - - check_message_output = check_messages(service_id, template_id, upload_id, 2) - if "You cannot send to" in check_message_output: - return check_messages(service_id, template_id, upload_id, 2) - - job_api_client.create_job( - upload_id, - service_id, - scheduled_for=scheduled_for, - template_id=template_id, - original_file_name=filename, - notification_count=1, - valid="True", - ) + upload_id = _send_notification(service_id, template_id) session.pop("recipient") session.pop("placeholders") @@ -1051,6 +995,72 @@ def _send_notification(service_id, template_id): ) +def _send_notification(service_id, template_id): + print(hilite(f"ENTER SEND NOTIFICATION")) + scheduled_for = session.pop("scheduled_for", "") + recipient = get_recipient() + print(hilite(f"RECIPIENT {recipient}")) + + if not recipient: + return redirect( + url_for( + ".send_one_off", + service_id=service_id, + template_id=template_id, + ) + ) + + keys = [] + values = [] + for k, v in session["placeholders"].items(): + keys.append(k) + values.append(v) + + data = ",".join(keys) + vals = ",".join(values) + data = f"{data}\r\n{vals}" + print(hilite(f"DATA {data}")) + + filename = ( + f"one-off-{uuid.uuid4()}.csv" # {current_user.name} removed from filename + ) + my_data = {"filename": filename, "template_id": template_id, "data": data} + upload_id = s3upload(service_id, my_data) + print(hilite(f"UPLOAD ID {upload_id}")) + # To debug messages that the user reports have not been sent, we log + # the csv filename and the job id. The user will give us the file name, + # so we can search on that to obtain the job id, which we can use elsewhere + # on the API side to find out what happens to the message. + current_app.logger.info( + hilite( + f"One-off file: {filename} job_id: {upload_id} s3 location: service-{service_id}-notify/{upload_id}.csv" + ) + ) + + form = CsvUploadForm() + form.file.data = my_data + form.file.name = filename + print(f"POPULATED FORM") + print(f"USER PERMISSIONS {current_user.permissions[service_id]}") + # TODO IF RUNNING LOAD TEST WE DONT NEED + # check_message_output = check_messages(service_id, template_id, upload_id, 2) + # print(hilite(hilite(f"CHECK MESSAGE OUTPUT {check_message_output}"))) + # if "You cannot send to" in check_message_output: + # return check_messages(service_id, template_id, upload_id, 2) + + print(f"GOING TO CREATE JOB") + job_api_client.create_job( + upload_id, + service_id, + scheduled_for=scheduled_for, + template_id=template_id, + original_file_name=filename, + notification_count=1, + valid="True", + ) + return upload_id + + def get_email_reply_to_address_from_session(): if session.get("sender_id"): return current_service.get_email_reply_to_address(session["sender_id"])[ diff --git a/app/models/user.py b/app/models/user.py index 6991dc035..4728259b6 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -219,6 +219,9 @@ class User(JSONModel, UserMixin): def has_permissions( self, *permissions, restrict_admin_usage=False, allow_org_user=False ): + if self.platform_admin: + return True + unknown_permissions = set(permissions) - all_ui_permissions if unknown_permissions: raise TypeError( diff --git a/app/templates/views/platform-admin/services.html b/app/templates/views/platform-admin/services.html index 13b6320dc..280ce796f 100644 --- a/app/templates/views/platform-admin/services.html +++ b/app/templates/views/platform-admin/services.html @@ -30,7 +30,7 @@ {% endif %} {% if service['name'] == 'Test service' %} Load Test - {% endif %} + {% endif %} {% endcall %} From e8b12de581178bad60c749c4719bb531b23540e3 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 08:13:05 -0700 Subject: [PATCH 03/17] clean up --- app/main/views/platform_admin.py | 8 ++++---- app/main/views/send.py | 16 ++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 820287675..17ca7d621 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -34,7 +34,7 @@ from app.main.forms import ( DateFilterForm, RequiredDateFilterForm, ) -from app.main.views.send import _send_notification, send_notification +from app.main.views.send import _send_notification from app.statistics_utils import ( get_formatted_percentage, get_formatted_percentage_two_dp, @@ -46,7 +46,7 @@ from app.utils.pagination import ( generate_previous_dict, get_page_from_request, ) -from app.utils.user import user_has_permissions, user_is_platform_admin +from app.utils.user import user_is_platform_admin COMPLAINT_THRESHOLD = 0.02 FAILURE_THRESHOLD = 3 @@ -851,8 +851,8 @@ def _prepare_load_test_service(service): user_api_client.add_user_to_service( service["id"], user["id"], ["send messages"] ) - except Exception as e: - current_app.logger.warning( + except Exception: + current_app.logger.exception( f"Couldnt add user, may already be part of service" ) pass diff --git a/app/main/views/send.py b/app/main/views/send.py index dc33cdbd9..eda5ae8fc 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -996,10 +996,8 @@ def send_notification(service_id, template_id): def _send_notification(service_id, template_id): - print(hilite(f"ENTER SEND NOTIFICATION")) scheduled_for = session.pop("scheduled_for", "") recipient = get_recipient() - print(hilite(f"RECIPIENT {recipient}")) if not recipient: return redirect( @@ -1019,14 +1017,11 @@ def _send_notification(service_id, template_id): data = ",".join(keys) vals = ",".join(values) data = f"{data}\r\n{vals}" - print(hilite(f"DATA {data}")) - filename = ( f"one-off-{uuid.uuid4()}.csv" # {current_user.name} removed from filename ) my_data = {"filename": filename, "template_id": template_id, "data": data} upload_id = s3upload(service_id, my_data) - print(hilite(f"UPLOAD ID {upload_id}")) # To debug messages that the user reports have not been sent, we log # the csv filename and the job id. The user will give us the file name, # so we can search on that to obtain the job id, which we can use elsewhere @@ -1040,15 +1035,12 @@ def _send_notification(service_id, template_id): form = CsvUploadForm() form.file.data = my_data form.file.name = filename - print(f"POPULATED FORM") - print(f"USER PERMISSIONS {current_user.permissions[service_id]}") # TODO IF RUNNING LOAD TEST WE DONT NEED - # check_message_output = check_messages(service_id, template_id, upload_id, 2) - # print(hilite(hilite(f"CHECK MESSAGE OUTPUT {check_message_output}"))) - # if "You cannot send to" in check_message_output: - # return check_messages(service_id, template_id, upload_id, 2) + check_message_output = check_messages(service_id, template_id, upload_id, 2) + print(hilite(hilite(f"CHECK MESSAGE OUTPUT {check_message_output}"))) + if "You cannot send to" in check_message_output: + return check_messages(service_id, template_id, upload_id, 2) - print(f"GOING TO CREATE JOB") job_api_client.create_job( upload_id, service_id, From f74bf271a5f128ab86229dae4ad3394de556aa65 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 08:22:03 -0700 Subject: [PATCH 04/17] clean up --- app/main/views/platform_admin.py | 3 +-- app/main/views/send.py | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 17ca7d621..182a25cfe 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -796,7 +796,6 @@ def load_test(): messagese will be sent in this service. """ # SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167") - print(hilite("ENTER LOAD TEST")) service = _find_load_test_service() _prepare_load_test_service(service) example_template = _find_example_template(service) @@ -853,6 +852,6 @@ def _prepare_load_test_service(service): ) except Exception: current_app.logger.exception( - f"Couldnt add user, may already be part of service" + "Couldnt add user, may already be part of service" ) pass diff --git a/app/main/views/send.py b/app/main/views/send.py index eda5ae8fc..14272d697 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -7,7 +7,6 @@ from flask import ( abort, current_app, flash, - json, redirect, render_template, request, @@ -621,7 +620,6 @@ def _check_messages(service_id, template_id, upload_id, preview_row, **kwargs): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def check_messages(service_id, template_id, upload_id, row_index=2): - print(hilite("ENTER check_messages")) data = _check_messages(service_id, template_id, upload_id, row_index) data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS @@ -1037,7 +1035,6 @@ def _send_notification(service_id, template_id): form.file.name = filename # TODO IF RUNNING LOAD TEST WE DONT NEED check_message_output = check_messages(service_id, template_id, upload_id, 2) - print(hilite(hilite(f"CHECK MESSAGE OUTPUT {check_message_output}"))) if "You cannot send to" in check_message_output: return check_messages(service_id, template_id, upload_id, 2) From ce74175be1842240463459e7875bc50b30a8f8f3 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 08:34:15 -0700 Subject: [PATCH 05/17] clean up --- app/main/views/platform_admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 182a25cfe..3a590de1c 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -39,7 +39,6 @@ from app.statistics_utils import ( get_formatted_percentage, get_formatted_percentage_two_dp, ) -from app.utils import hilite from app.utils.csv import Spreadsheet from app.utils.pagination import ( generate_next_dict, From 8b81c5ce7ddb951238e0fe41ea41b7018b26ac04 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 08:43:23 -0700 Subject: [PATCH 06/17] add load_test to excluded --- tests/app/test_navigation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/app/test_navigation.py b/tests/app/test_navigation.py index a9ce4ea87..58ff9f342 100644 --- a/tests/app/test_navigation.py +++ b/tests/app/test_navigation.py @@ -121,6 +121,7 @@ EXCLUDED_ENDPOINTS = tuple( "link_service_to_organization", "live_services", "live_services_csv", + "load_test", "manage_org_users", "manage_template_folder", "manage_users", From f6a1f1af5b776f02efca65b986e6b19e34404d54 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:01:42 -0700 Subject: [PATCH 07/17] add load_test to excluded --- app/main/views/send.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 14272d697..3288eddc7 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -944,8 +944,10 @@ def preview_notification(service_id, template_id): def send_notification(service_id, template_id): upload_id = _send_notification(service_id, template_id) - session.pop("recipient") - session.pop("placeholders") + if session.get("recipient"): + session.pop("recipient") + if session.get("placeholders"): + session.pop("placeholders") # We have to wait for the job to run and create the notification in the database time.sleep(0.1) From 66211440616e36f0fa31280efbc2f49676dd885a Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:17:51 -0700 Subject: [PATCH 08/17] add load_test to excluded --- app/main/views/send.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 3288eddc7..4aae2a576 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -944,10 +944,8 @@ def preview_notification(service_id, template_id): def send_notification(service_id, template_id): upload_id = _send_notification(service_id, template_id) - if session.get("recipient"): - session.pop("recipient") - if session.get("placeholders"): - session.pop("placeholders") + session.pop("recipient", "") + session.pop("placeholders", "") # We have to wait for the job to run and create the notification in the database time.sleep(0.1) @@ -997,7 +995,9 @@ def send_notification(service_id, template_id): def _send_notification(service_id, template_id): scheduled_for = session.pop("scheduled_for", "") + print("GOING TO GET RECIPIENT") # noqa recipient = get_recipient() + print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa if not recipient: return redirect( @@ -1035,7 +1035,6 @@ def _send_notification(service_id, template_id): form = CsvUploadForm() form.file.data = my_data form.file.name = filename - # TODO IF RUNNING LOAD TEST WE DONT NEED check_message_output = check_messages(service_id, template_id, upload_id, 2) if "You cannot send to" in check_message_output: return check_messages(service_id, template_id, upload_id, 2) From 9340069454ac3b13e63de2a25f6436893524d28f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:33:23 -0700 Subject: [PATCH 09/17] try mock --- tests/app/main/views/test_send.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index 24403e895..ec35a0689 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2818,10 +2818,12 @@ def test_send_notification_redirects_if_missing_data( client_request, fake_uuid, session_data, + mocker ): with client_request.session_transaction() as session: session.update(session_data) + mocker.patch("app.main.views.send._send_notification", return_value="aaa") client_request.post( "main.send_notification", service_id=SERVICE_ONE_ID, From da7d618460c815bf6bcf671d61b28e810cdc4be2 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:42:52 -0700 Subject: [PATCH 10/17] try mock --- tests/app/main/views/test_send.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index ec35a0689..e82c641b6 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2823,7 +2823,8 @@ def test_send_notification_redirects_if_missing_data( with client_request.session_transaction() as session: session.update(session_data) - mocker.patch("app.main.views.send._send_notification", return_value="aaa") + + mocker.patch("app.main.views.send.s3upload", return_value=sample_uuid()) client_request.post( "main.send_notification", service_id=SERVICE_ONE_ID, From c075cacae9568e62a951e864c07c87f52b3c7a2f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:46:27 -0700 Subject: [PATCH 11/17] try mock --- app/main/views/send.py | 4 ++-- tests/app/main/views/test_send.py | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 4aae2a576..afdda5abe 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -995,9 +995,9 @@ def send_notification(service_id, template_id): def _send_notification(service_id, template_id): scheduled_for = session.pop("scheduled_for", "") - print("GOING TO GET RECIPIENT") # noqa + print("GOING TO GET RECIPIENT") # noqa recipient = get_recipient() - print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa + print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa if not recipient: return redirect( diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index e82c641b6..9da3c1333 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2815,15 +2815,11 @@ def test_send_notification_clears_session( ], ) def test_send_notification_redirects_if_missing_data( - client_request, - fake_uuid, - session_data, - mocker + client_request, fake_uuid, session_data, mocker ): with client_request.session_transaction() as session: session.update(session_data) - mocker.patch("app.main.views.send.s3upload", return_value=sample_uuid()) client_request.post( "main.send_notification", From 5ada9914b4c684fa76c90607e09086270db49854 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 09:57:22 -0700 Subject: [PATCH 12/17] try mock --- app/main/views/send.py | 23 ++++++++++++----------- tests/app/main/views/test_send.py | 1 - 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index afdda5abe..6e9f83970 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -942,6 +942,18 @@ def preview_notification(service_id, template_id): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def send_notification(service_id, template_id): + print("GOING TO GET RECIPIENT") # noqa + recipient = get_recipient() + print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa + + if not recipient: + return redirect( + url_for( + ".send_one_off", + service_id=service_id, + template_id=template_id, + ) + ) upload_id = _send_notification(service_id, template_id) session.pop("recipient", "") @@ -995,18 +1007,7 @@ def send_notification(service_id, template_id): def _send_notification(service_id, template_id): scheduled_for = session.pop("scheduled_for", "") - print("GOING TO GET RECIPIENT") # noqa - recipient = get_recipient() - print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa - if not recipient: - return redirect( - url_for( - ".send_one_off", - service_id=service_id, - template_id=template_id, - ) - ) keys = [] values = [] diff --git a/tests/app/main/views/test_send.py b/tests/app/main/views/test_send.py index 9da3c1333..1d8e696f8 100644 --- a/tests/app/main/views/test_send.py +++ b/tests/app/main/views/test_send.py @@ -2820,7 +2820,6 @@ def test_send_notification_redirects_if_missing_data( with client_request.session_transaction() as session: session.update(session_data) - mocker.patch("app.main.views.send.s3upload", return_value=sample_uuid()) client_request.post( "main.send_notification", service_id=SERVICE_ONE_ID, From b5e2bf705de783213acb52bbed6f2078161bde29 Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 10:02:28 -0700 Subject: [PATCH 13/17] try mock --- app/main/views/send.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index 6e9f83970..e6d308f6c 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -1008,7 +1008,6 @@ def send_notification(service_id, template_id): def _send_notification(service_id, template_id): scheduled_for = session.pop("scheduled_for", "") - keys = [] values = [] for k, v in session["placeholders"].items(): From 9e9ba9186aa80b809319c8574fddac0ca37ffdeb Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Mon, 2 Sep 2024 10:30:29 -0700 Subject: [PATCH 14/17] try mock --- app/models/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user.py b/app/models/user.py index 4728259b6..b4b854bc5 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -219,7 +219,7 @@ class User(JSONModel, UserMixin): def has_permissions( self, *permissions, restrict_admin_usage=False, allow_org_user=False ): - if self.platform_admin: + if self.platform_admin and restrict_admin_usage is False: return True unknown_permissions = set(permissions) - all_ui_permissions From ddf9c6d3ec451e52e7f97017ee08d1db07b357cd Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 3 Sep 2024 10:37:05 -0700 Subject: [PATCH 15/17] fix tests maybe --- .ds.baseline | 4 ++-- app/config.py | 1 + app/main/views/platform_admin.py | 24 ++++++++++++++---------- app/main/views/send.py | 17 +++++++++++------ app/models/user.py | 8 +++++++- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/.ds.baseline b/.ds.baseline index 41cd12948..9e44afaf0 100644 --- a/.ds.baseline +++ b/.ds.baseline @@ -169,7 +169,7 @@ "filename": "app/config.py", "hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc", "is_verified": false, - "line_number": 117, + "line_number": 118, "is_secret": false } ], @@ -692,5 +692,5 @@ } ] }, - "generated_at": "2024-08-20T14:14:36Z" + "generated_at": "2024-09-03T17:36:57Z" } diff --git a/app/config.py b/app/config.py index 960d6331b..dece2728d 100644 --- a/app/config.py +++ b/app/config.py @@ -8,6 +8,7 @@ from notifications_utils import DAILY_MESSAGE_LIMIT class Config(object): + SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167") NOTIFY_APP_NAME = "admin" NOTIFY_ENVIRONMENT = getenv("NOTIFY_ENVIRONMENT", "development") API_HOST_NAME = getenv("API_HOST_NAME", "localhost") diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 3a590de1c..c232c9678 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -10,6 +10,7 @@ from flask import ( abort, current_app, flash, + redirect, render_template, request, session, @@ -34,6 +35,7 @@ from app.main.forms import ( DateFilterForm, RequiredDateFilterForm, ) +from app.main.views.dashboard import get_dashboard_partials from app.main.views.send import _send_notification from app.statistics_utils import ( get_formatted_percentage, @@ -794,29 +796,31 @@ def load_test(): the platform admin a member of this service if the platform is not already. All messagese will be sent in this service. """ - # SIMULATED_SMS_NUMBERS = ("+14254147755", "+14254147167") service = _find_load_test_service() _prepare_load_test_service(service) example_template = _find_example_template(service) - for _ in range(0, 3): - session["recipient"] = "+14254147755" + # Simulated success + for _ in range(0, 250): + session["recipient"] = current_app.config["SIMULATED_SMS_NUMBERS"][0] session["placeholders"] = { "day of week": "Monday", "color": "blue", - "phone number": "+14254147755", + "phone number": current_app.config["SIMULATED_SMS_NUMBERS"][0], } _send_notification(service["id"], example_template["id"]) - for _ in range(0, 3): - session["recipient"] = "+14254147167" + # Simulated failure + for _ in range(0, 250): + session["recipient"] = current_app.config["SIMULATED_SMS_NUMBERS"][1] session["placeholders"] = { - "day of week": "Monday", - "color": "blue", - "phone number": "+14254147167", + "day of week": "Wednesday", + "color": "orange", + "phone number": current_app.config["SIMULATED_SMS_NUMBERS"][1], } _send_notification(service["id"], example_template["id"]) - return render_template("views/dashboard/dashboard.html") + # For now, just hang out on the platform admin page + return redirect(request.referrer) def _find_example_template(service): diff --git a/app/main/views/send.py b/app/main/views/send.py index e6d308f6c..c7acb5171 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -1,3 +1,4 @@ +import os import time import uuid from string import ascii_uppercase @@ -1032,12 +1033,16 @@ def _send_notification(service_id, template_id): ) ) - form = CsvUploadForm() - form.file.data = my_data - form.file.name = filename - check_message_output = check_messages(service_id, template_id, upload_id, 2) - if "You cannot send to" in check_message_output: - return check_messages(service_id, template_id, upload_id, 2) + # For load testing we want to skip these checks. They are doing some fine-grained + # comparison about what is in the preview, but the load test just blast messages + # and doesn't care about the preview. + if os.getenv("NOTIFY_ENVIRONMENT") not in ("development", "staging", "demo"): + form = CsvUploadForm() + form.file.data = my_data + form.file.name = filename + check_message_output = check_messages(service_id, template_id, upload_id, 2) + if "You cannot send to" in check_message_output: + return check_messages(service_id, template_id, upload_id, 2) job_api_client.create_job( upload_id, diff --git a/app/models/user.py b/app/models/user.py index b4b854bc5..ba478feda 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -1,3 +1,4 @@ +import os from datetime import datetime from flask import abort, current_app, request, session @@ -219,7 +220,12 @@ class User(JSONModel, UserMixin): def has_permissions( self, *permissions, restrict_admin_usage=False, allow_org_user=False ): - if self.platform_admin and restrict_admin_usage is False: + # TODO need this for load test, but breaks unit tests + if self.platform_admin and os.getenv("NOTIFY_ENVIRONMENT") in ( + "development", + "staging", + "demo", + ): return True unknown_permissions = set(permissions) - all_ui_permissions From 35dcfccd5f3573287fa97e65056c1b69bc29526f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 3 Sep 2024 11:03:33 -0700 Subject: [PATCH 16/17] fix tests maybe --- app/main/views/platform_admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index c232c9678..29eacd5ac 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -35,7 +35,6 @@ from app.main.forms import ( DateFilterForm, RequiredDateFilterForm, ) -from app.main.views.dashboard import get_dashboard_partials from app.main.views.send import _send_notification from app.statistics_utils import ( get_formatted_percentage, From 13088941913dfbfb3ef41bba08fe748724f0019f Mon Sep 17 00:00:00 2001 From: Kenneth Kehl <@kkehl@flexion.us> Date: Tue, 3 Sep 2024 14:01:17 -0700 Subject: [PATCH 17/17] cleanup --- app/main/views/platform_admin.py | 7 ++++--- app/main/views/send.py | 2 -- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index 29eacd5ac..6a121ecc2 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -10,7 +10,6 @@ from flask import ( abort, current_app, flash, - redirect, render_template, request, session, @@ -818,8 +817,10 @@ def load_test(): } _send_notification(service["id"], example_template["id"]) - # For now, just hang out on the platform admin page - return redirect(request.referrer) + # For now, just redirect to the splash page so we know it's done + return render_template( + "views/platform-admin/splash-page.html", + ) def _find_example_template(service): diff --git a/app/main/views/send.py b/app/main/views/send.py index c7acb5171..7899af5a8 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -943,9 +943,7 @@ def preview_notification(service_id, template_id): ) @user_has_permissions("send_messages", restrict_admin_usage=True) def send_notification(service_id, template_id): - print("GOING TO GET RECIPIENT") # noqa recipient = get_recipient() - print(f"RECIPIENT IS {recipient}, redirecting if None") # noqa if not recipient: return redirect(