mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-14 15:34:20 -05:00
The GDS Way™[1] recommends using Flake8 to lint Python projects.
This commit takes the Flake8 config from Digital Marketplace API[2] and
removes the bits we don’t need.
It changes the `max_complexity` setting to 14, which is the most complex
code we have in this repo currently (we shouldn’t be writing code _more_
complex than what we already have).
This commit also fixes the errors found by Flake8, which includes 6(!)
tests which were never getting run because they had the same names as
existing tests.
Here is a full list of the errors that were found and fixed:
```
./app/__init__.py:2:1: F401 're' imported but unused
./app/__init__.py:4:1: F401 'json' imported but unused
./app/__init__.py:8:1: F401 'dateutil' imported but unused
./app/__init__.py:11:1: F401 'flask.escape' imported but unused
./app/__init__.py:41:1: F401 'app.proxy_fix' imported but unused
./app/__init__.py:129:5: F821 undefined name 'proxy_fix'
./app/__init__.py:221:19: F821 undefined name 'highlight'
./app/__init__.py:221:35: F821 undefined name 'JavascriptLexer'
./app/__init__.py:221:54: F821 undefined name 'HtmlFormatter'
./app/config.py:2:1: F401 'datetime.timedelta' imported but unused
./app/event_handlers.py:2:1: F401 'flask_login.current_user' imported but unused
./app/utils.py:11:1: F401 'dateutil.parser' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.two_factor' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.notifications' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.add_service' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.forgot_password' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.inbound_number' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.styleguide' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.organisations' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.letter_jobs' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.verify' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.conversation' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.api_keys' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.send' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.dashboard' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.jobs' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.manage_users' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.sign_in' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.sign_out' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.code_not_received' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.invites' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.platform_admin' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.providers' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.service_settings' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.index' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.new_password' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.user_profile' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.feedback' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.choose_service' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.templates' imported but unused
./app/main/__init__.py:5:1: F401 'app.main.views.register' imported but unused
./app/main/forms.py:12:1: F401 'wtforms.SelectField' imported but unused
./app/main/views/api_keys.py:37:29: E241 multiple spaces after ':'
./app/main/views/feedback.py:3:1: F401 'flask.flash' imported but unused
./app/main/views/feedback.py:122:17: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/inbound_number.py:1:1: F401 'flask.url_for' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.session' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.redirect' imported but unused
./app/main/views/inbound_number.py:1:1: F401 'flask.request' imported but unused
./app/main/views/inbound_number.py:13:1: F401 'flask.jsonify' imported but unused
./app/main/views/jobs.py:31:1: F401 'app.utils.get_template' imported but unused
./app/main/views/letter_jobs.py:1:1: F401 'datetime' imported but unused
./app/main/views/letter_jobs.py:6:1: F401 'app.format_datetime_24h' imported but unused
./app/main/views/manage_users.py:111:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/notifications.py:121:5: F841 local variable 'status_args' is assigned to but never used
./app/main/views/organisations.py:1:1: F401 'flask.request' imported but unused
./app/main/views/service_settings.py:77:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/service_settings.py:82:9: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/service_settings.py:420:13: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/sign_in.py:12:1: F401 'flask_login.confirm_login' imported but unused
./app/main/views/sign_in.py:17:1: F401 'app.service_api_client' imported but unused
./app/main/views/sign_in.py:62:13: E123 closing bracket does not match indentation of opening bracket's line
./app/main/views/templates.py:4:1: F401 'flask.json' imported but unused
./app/main/views/templates.py:17:1: F401 'notifications_utils.formatters.escape_html' imported but unused
./app/main/views/templates.py:23:1: F401 'app.utils.get_help_argument' imported but unused
./app/main/views/templates.py:64:13: E123 closing bracket does not match indentation of opening bracket's line
./app/notify_client/service_api_client.py:6:1: F401 '.notification_api_client' imported but unused
./app/notify_client/user_api_client.py:1:1: F401 'uuid' imported but unused
./app/notify_client/user_api_client.py:3:1: F401 'flask.session' imported but unused
./tests/__init__.py:1:1: F401 'csv' imported but unused
./tests/app/main/test_asset_fingerprinter.py:2:1: F401 'os' imported but unused
./tests/app/main/test_asset_fingerprinter.py:4:1: F401 'unittest.mock' imported but unused
./tests/app/main/test_asset_fingerprinter.py:98:9: F841 local variable 'string_with_unicode_character' is assigned to but never used
./tests/app/main/test_errorhandlers.py:2:1: F401 'flask.url_for' imported but unused
./tests/app/main/test_permissions.py:26:13: F841 local variable 'response' is assigned to but never used
./tests/app/main/test_placeholder_form.py:3:1: F401 'wtforms.Label' imported but unused
./tests/app/main/test_placeholder_form.py:11:10: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:10:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:23:65: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:37:48: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:51:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/test_two_factor_form.py:65:67: F841 local variable 'req' is assigned to but never used
./tests/app/main/views/test_accept_invite.py:356:5: F841 local variable 'element' is assigned to but never used
./tests/app/main/views/test_activity.py:11:1: F811 redefinition of unused 'mock_get_notifications' from line 11
./tests/app/main/views/test_activity.py:18:1: F401 'datetime.datetime' imported but unused
./tests/app/main/views/test_activity.py:102:5: F841 local variable 'content' is assigned to but never used
./tests/app/main/views/test_activity.py:104:5: F841 local variable 'notification' is assigned to but never used
./tests/app/main/views/test_activity.py:337:5: F841 local variable '_notifications_mock' is assigned to but never used
./tests/app/main/views/test_activity.py:373:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_activity.py:378:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_activity.py:404:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_activity.py:407:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_api_keys.py:354:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_conversation.py:5:1: F401 'bs4.BeautifulSoup' imported but unused
./tests/app/main/views/test_conversation.py:198:5: F841 local variable 'mock_get_inbound_sms' is assigned to but never used
./tests/app/main/views/test_dashboard.py:53:5: F841 local variable 'mock_template_stats' is assigned to but never used
./tests/app/main/views/test_dashboard.py:72:5: F841 local variable 'mock_template_stats' is assigned to but never used
./tests/app/main/views/test_jobs.py:2:1: F401 'uuid' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.urlparse' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.quote' imported but unused
./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.parse_qs' imported but unused
./tests/app/main/views/test_jobs.py:9:1: F401 'app.main.views.jobs.get_status_filters' imported but unused
./tests/app/main/views/test_jobs.py:10:1: F401 'tests.notification_json' imported but unused
./tests/app/main/views/test_letters.py:6:1: F401 'tests.service_json' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.REQUESTED_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.DELIVERED_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.SENDING_STATUSES' imported but unused
./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.FAILURE_STATUSES' imported but unused
./tests/app/main/views/test_platform_admin.py:242:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_platform_admin.py:247:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:3:1: F401 'unittest.mock.Mock' imported but unused
./tests/app/main/views/test_send.py:18:1: F811 redefinition of unused 'mock_get_service' from line 18
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_letter_contact_blocks' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_sms_senders' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_sms_senders' imported but unused
./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_letter_contact_blocks' imported but unused
./tests/app/main/views/test_send.py:102:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_send.py:870:5: F841 local variable 'response' is assigned to but never used
./tests/app/main/views/test_send.py:1367:5: F841 local variable 'service_id' is assigned to but never used
./tests/app/main/views/test_send.py:1451:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:1620:80: E226 missing whitespace around arithmetic operator
./tests/app/main/views/test_send.py:1909:13: E126 continuation line over-indented for hanging indent
./tests/app/main/views/test_send.py:1912:9: E121 continuation line under-indented for hanging indent
./tests/app/main/views/test_service_settings.py:13:1: F811 redefinition of unused 'no_reply_to_email_addresses' from line 13
./tests/app/main/views/test_service_settings.py:13:1: F401 'tests.conftest.single_reply_to_email_address' imported but unused
./tests/app/main/views/test_service_settings.py:28:5: E123 closing bracket does not match indentation of opening bracket's line
./tests/app/main/views/test_service_settings.py:104:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:166:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:186:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:217:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:237:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:257:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:307:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:340:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:466:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:555:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:615:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:719:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:874:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:902:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:954:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:986:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1101:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1121:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1271:1: F811 redefinition of unused 'test_set_letter_contact_block_saves' from line 1189
./tests/app/main/views/test_service_settings.py:1433:5: F841 local variable 'page' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1495:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1540:5: F841 local variable 'mocked_get_fn' is assigned to but never used
./tests/app/main/views/test_service_settings.py:1570:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1589:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1621:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1641:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1658:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1676:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1697:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1759:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_service_settings.py:1775:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13
./tests/app/main/views/test_templates.py:3:1: F401 'uuid' imported but unused
./tests/app/main/views/test_templates.py:11:1: F401 'tests.conftest.mock_get_user' imported but unused
./tests/app/main/views/test_templates.py:514:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:672:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:795:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_templates.py:835:1: F811 redefinition of unused 'mock_get_user' from line 11
./tests/app/main/views/test_two_factor.py:67:13: E126 continuation line over-indented for hanging indent
./tests/app/notify_client/test_notification_client.py:79:5: F841 local variable 'mock_post' is assigned to but never used
```
1. https://gds-way.cloudapps.digital/manuals/programming-languages/python/linting.html#how-to-use-flake8
2. d5ab8afef4/.flake8
579 lines
18 KiB
Python
579 lines
18 KiB
Python
import datetime
|
||
|
||
from flask import url_for
|
||
import pytest
|
||
from bs4 import BeautifulSoup
|
||
|
||
from tests.conftest import mock_get_user, normalize_spaces
|
||
from tests import service_json
|
||
|
||
from app.main.views.platform_admin import format_stats_by_service, create_global_stats, sum_service_usage
|
||
|
||
from unittest.mock import ANY
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint', [
|
||
'main.platform_admin',
|
||
'main.live_services',
|
||
'main.trial_services',
|
||
])
|
||
def test_should_redirect_if_not_logged_in(
|
||
client,
|
||
endpoint
|
||
):
|
||
response = client.get(url_for(endpoint))
|
||
assert response.status_code == 302
|
||
assert response.location == url_for('main.sign_in', next=url_for(endpoint), _external=True)
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint', [
|
||
'main.platform_admin',
|
||
'main.live_services',
|
||
'main.trial_services',
|
||
])
|
||
def test_should_403_if_not_platform_admin(
|
||
client,
|
||
active_user_with_permissions,
|
||
mocker,
|
||
endpoint,
|
||
):
|
||
mock_get_user(mocker, user=active_user_with_permissions)
|
||
client.login(active_user_with_permissions)
|
||
response = client.get(url_for(endpoint))
|
||
|
||
assert response.status_code == 403
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, restricted, research_mode, displayed', [
|
||
('main.trial_services', True, False, ''),
|
||
('main.live_services', False, False, 'Live'),
|
||
('main.live_services', False, True, 'research mode'),
|
||
('main.trial_services', True, True, 'research mode')
|
||
])
|
||
def test_should_show_research_and_restricted_mode(
|
||
endpoint,
|
||
restricted,
|
||
research_mode,
|
||
displayed,
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
fake_uuid,
|
||
):
|
||
services = [service_json(fake_uuid, 'My Service', [], restricted=restricted, research_mode=research_mode)]
|
||
services[0]['statistics'] = create_stats()
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
|
||
assert response.status_code == 200
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'include_from_test_key': True,
|
||
'only_active': False})
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
# get first column in second row, which contains flags as text.
|
||
table_body = page.find_all('table')[0].find_all('tbody')[0]
|
||
service_mode = table_body.find_all('tbody')[0].find_all('tr')[1].find_all('td')[0].text.strip()
|
||
assert service_mode == displayed
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, expected_services_shown', [
|
||
('main.live_services', 1),
|
||
('main.trial_services', 1),
|
||
])
|
||
def test_should_render_platform_admin_page(
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
endpoint,
|
||
expected_services_shown
|
||
):
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
assert response.status_code == 200
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
assert len(page.select('tbody tr')) == expected_services_shown * 2 # one row for SMS, one for email
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'include_from_test_key': True,
|
||
'only_active': False})
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint', [
|
||
('main.platform_admin'),
|
||
('main.live_services'),
|
||
('main.trial_services'),
|
||
])
|
||
@pytest.mark.parametrize('include_from_test_key, inc', [
|
||
("Y", True),
|
||
("N", False)
|
||
])
|
||
def test_platform_admin_toggle_including_from_test_key(
|
||
include_from_test_key,
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
endpoint,
|
||
inc
|
||
):
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint, include_from_test_key=include_from_test_key))
|
||
|
||
assert response.status_code == 200
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'only_active': False,
|
||
'include_from_test_key': inc})
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint', [
|
||
'main.platform_admin',
|
||
'main.live_services',
|
||
'main.trial_services'
|
||
])
|
||
def test_platform_admin_with_date_filter(
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
endpoint
|
||
):
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint, start_date='2016-12-20', end_date='2016-12-28'))
|
||
|
||
assert response.status_code == 200
|
||
resp_data = response.get_data(as_text=True)
|
||
assert 'Platform admin' in resp_data
|
||
mock_get_detailed_services.assert_called_once_with({
|
||
'include_from_test_key': False,
|
||
'end_date': datetime.date(2016, 12, 28),
|
||
'start_date': datetime.date(2016, 12, 20),
|
||
'detailed': True,
|
||
'only_active': False,
|
||
})
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, expected_big_numbers', [
|
||
(
|
||
'main.platform_admin', (
|
||
'61 emails sent 6 failed – 5.5%',
|
||
'121 text messages sent 11 failed – 5.0%',
|
||
'45 letters sent 13 failed – 28.9%'
|
||
),
|
||
),
|
||
(
|
||
'main.live_services', (
|
||
'55 emails sent 5 failed – 5.0%',
|
||
'110 text messages sent 10 failed – 5.0%',
|
||
'15 letters sent 3 failed – 20.0%'
|
||
),
|
||
),
|
||
(
|
||
'main.trial_services', (
|
||
'6 emails sent 1 failed – 10.0%',
|
||
'11 text messages sent 1 failed – 5.0%',
|
||
'30 letters sent 10 failed – 33.3%'
|
||
),
|
||
),
|
||
])
|
||
def test_should_show_total_on_platform_admin_pages(
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
endpoint,
|
||
fake_uuid,
|
||
expected_big_numbers,
|
||
):
|
||
services = [
|
||
service_json(fake_uuid, 'My Service 1', [], restricted=False),
|
||
service_json(fake_uuid, 'My Service 2', [], restricted=True),
|
||
]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=100,
|
||
emails_delivered=50,
|
||
emails_failed=5,
|
||
sms_requested=200,
|
||
sms_delivered=100,
|
||
sms_failed=10,
|
||
letters_requested=15,
|
||
letters_delivered=12,
|
||
letters_failed=3
|
||
)
|
||
|
||
services[1]['statistics'] = create_stats(
|
||
emails_requested=10,
|
||
emails_delivered=5,
|
||
emails_failed=1,
|
||
sms_requested=20,
|
||
sms_delivered=10,
|
||
sms_failed=1,
|
||
letters_requested=30,
|
||
letters_delivered=20,
|
||
letters_failed=10
|
||
)
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
assert response.status_code == 200
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
assert (
|
||
normalize_spaces(page.select('.big-number-with-status')[0].text),
|
||
normalize_spaces(page.select('.big-number-with-status')[1].text),
|
||
normalize_spaces(page.select('.big-number-with-status')[2].text),
|
||
) == expected_big_numbers
|
||
|
||
|
||
def test_create_global_stats_sets_failure_rates(fake_uuid):
|
||
services = [
|
||
service_json(fake_uuid, 'a', []),
|
||
service_json(fake_uuid, 'b', [])
|
||
]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=1,
|
||
emails_delivered=1,
|
||
emails_failed=0,
|
||
)
|
||
services[1]['statistics'] = create_stats(
|
||
emails_requested=2,
|
||
emails_delivered=1,
|
||
emails_failed=1,
|
||
)
|
||
|
||
stats = create_global_stats(services)
|
||
assert stats == {
|
||
'email': {
|
||
'delivered': 2,
|
||
'failed': 1,
|
||
'requested': 3,
|
||
'failure_rate': '33.3'
|
||
},
|
||
'sms': {
|
||
'delivered': 0,
|
||
'failed': 0,
|
||
'requested': 0,
|
||
'failure_rate': '0'
|
||
},
|
||
'letter': {
|
||
'delivered': 0,
|
||
'failed': 0,
|
||
'requested': 0,
|
||
'failure_rate': '0'
|
||
}
|
||
}
|
||
|
||
|
||
def create_stats(
|
||
emails_requested=0,
|
||
emails_delivered=0,
|
||
emails_failed=0,
|
||
sms_requested=0,
|
||
sms_delivered=0,
|
||
sms_failed=0,
|
||
letters_requested=0,
|
||
letters_delivered=0,
|
||
letters_failed=0
|
||
):
|
||
return {
|
||
'sms': {
|
||
'requested': sms_requested,
|
||
'delivered': sms_delivered,
|
||
'failed': sms_failed,
|
||
},
|
||
'email': {
|
||
'requested': emails_requested,
|
||
'delivered': emails_delivered,
|
||
'failed': emails_failed,
|
||
},
|
||
'letter': {
|
||
'requested': letters_requested,
|
||
'delivered': letters_delivered,
|
||
'failed': letters_failed,
|
||
},
|
||
}
|
||
|
||
|
||
def test_format_stats_by_service_returns_correct_values(fake_uuid):
|
||
services = [service_json(fake_uuid, 'a', [])]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=10,
|
||
emails_delivered=3,
|
||
emails_failed=5,
|
||
sms_requested=50,
|
||
sms_delivered=7,
|
||
sms_failed=11,
|
||
letters_requested=40,
|
||
letters_delivered=20,
|
||
letters_failed=7
|
||
)
|
||
|
||
ret = list(format_stats_by_service(services))
|
||
assert len(ret) == 1
|
||
|
||
assert ret[0]['stats']['email']['sending'] == 2
|
||
assert ret[0]['stats']['email']['delivered'] == 3
|
||
assert ret[0]['stats']['email']['failed'] == 5
|
||
|
||
assert ret[0]['stats']['sms']['sending'] == 32
|
||
assert ret[0]['stats']['sms']['delivered'] == 7
|
||
assert ret[0]['stats']['sms']['failed'] == 11
|
||
|
||
assert ret[0]['stats']['letter']['sending'] == 13
|
||
assert ret[0]['stats']['letter']['delivered'] == 20
|
||
assert ret[0]['stats']['letter']['failed'] == 7
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, restricted, research_mode', [
|
||
('main.trial_services', True, False),
|
||
('main.live_services', False, False)
|
||
])
|
||
def test_should_show_email_and_sms_stats_for_all_service_types(
|
||
endpoint,
|
||
restricted,
|
||
research_mode,
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
fake_uuid,
|
||
):
|
||
services = [service_json(fake_uuid, 'My Service', [], restricted=restricted, research_mode=research_mode)]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=10,
|
||
emails_delivered=3,
|
||
emails_failed=5,
|
||
sms_requested=50,
|
||
sms_delivered=7,
|
||
sms_failed=11
|
||
)
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
|
||
assert response.status_code == 200
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'include_from_test_key': True,
|
||
'only_active': ANY})
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
|
||
table_body = page.find_all('table')[0].find_all('tbody')[0]
|
||
service_row_group = table_body.find_all('tbody')[0].find_all('tr')
|
||
email_stats = service_row_group[0].find_all('div', class_='big-number-number')
|
||
sms_stats = service_row_group[1].find_all('div', class_='big-number-number')
|
||
email_sending, email_delivered, email_failed = [int(x.text.strip()) for x in email_stats]
|
||
sms_sending, sms_delivered, sms_failed = [int(x.text.strip()) for x in sms_stats]
|
||
|
||
assert email_sending == 2
|
||
assert email_delivered == 3
|
||
assert email_failed == 5
|
||
assert sms_sending == 32
|
||
assert sms_delivered == 7
|
||
assert sms_failed == 11
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, restricted', [
|
||
('main.live_services', False),
|
||
('main.trial_services', True)
|
||
], ids=['live', 'trial'])
|
||
def test_should_show_archived_services_last(
|
||
endpoint,
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
restricted,
|
||
):
|
||
services = [
|
||
service_json(name='C', restricted=restricted, active=False, created_at='2002-02-02 12:00:00'),
|
||
service_json(name='B', restricted=restricted, active=True, created_at='2001-01-01 12:00:00'),
|
||
service_json(name='A', restricted=restricted, active=True, created_at='2003-03-03 12:00:00'),
|
||
]
|
||
services[0]['statistics'] = create_stats()
|
||
services[1]['statistics'] = create_stats()
|
||
services[2]['statistics'] = create_stats()
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
|
||
assert response.status_code == 200
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'include_from_test_key': True,
|
||
'only_active': ANY})
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
|
||
table_body = page.find_all('table')[0].find_all('tbody')[0]
|
||
services = [service.tr for service in table_body.find_all('tbody')]
|
||
assert len(services) == 3
|
||
assert services[0].td.text.strip() == 'A'
|
||
assert services[1].td.text.strip() == 'B'
|
||
assert services[2].td.text.strip() == 'C'
|
||
|
||
|
||
@pytest.mark.parametrize('research_mode', (True, False))
|
||
def test_shows_archived_label_instead_of_live_or_research_mode_label(
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
research_mode,
|
||
):
|
||
services = [
|
||
service_json(restricted=False, research_mode=research_mode, active=False)
|
||
]
|
||
services[0]['statistics'] = create_stats()
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for('main.live_services'))
|
||
|
||
assert response.status_code == 200
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
|
||
table_body = page.find_all('table')[0].find_all('tbody')[0]
|
||
service_mode = table_body.find_all('tbody')[0].find_all('tr')[1].td.text.strip()
|
||
# get second column, which contains flags as text.
|
||
assert service_mode == 'archived'
|
||
|
||
|
||
def test_should_show_correct_sent_totals_for_platform_admin(
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
fake_uuid,
|
||
):
|
||
services = [service_json(fake_uuid, 'My Service', [])]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=100,
|
||
emails_delivered=20,
|
||
emails_failed=40,
|
||
sms_requested=100,
|
||
sms_delivered=10,
|
||
sms_failed=30,
|
||
letters_requested=60,
|
||
letters_delivered=40,
|
||
letters_failed=5
|
||
)
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for('main.platform_admin'))
|
||
|
||
assert response.status_code == 200
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
|
||
totals = page.find_all('div', 'big-number-with-status')
|
||
email_total = int(totals[0].find_all('div', 'big-number-number')[0].text.strip())
|
||
sms_total = int(totals[1].find_all('div', 'big-number-number')[0].text.strip())
|
||
letter_total = int(totals[2].find_all('div', 'big-number-number')[0].text.strip())
|
||
|
||
assert email_total == 60
|
||
assert sms_total == 40
|
||
assert letter_total == 45
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint, restricted, research_mode', [
|
||
('main.trial_services', True, False),
|
||
('main.live_services', False, False)
|
||
])
|
||
def test_should_order_services_by_usage_with_inactive_last(
|
||
endpoint,
|
||
restricted,
|
||
research_mode,
|
||
client,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_detailed_services,
|
||
fake_uuid,
|
||
):
|
||
services = [
|
||
service_json(fake_uuid, 'My Service 1', [], restricted=restricted, research_mode=research_mode),
|
||
service_json(fake_uuid, 'My Service 2', [], restricted=restricted, research_mode=research_mode),
|
||
service_json(fake_uuid, 'My Service 3', [], restricted=restricted, research_mode=research_mode, active=False)
|
||
]
|
||
services[0]['statistics'] = create_stats(
|
||
emails_requested=100,
|
||
emails_delivered=25,
|
||
emails_failed=25,
|
||
sms_requested=100,
|
||
sms_delivered=25,
|
||
sms_failed=25
|
||
)
|
||
|
||
services[1]['statistics'] = create_stats(
|
||
emails_requested=200,
|
||
emails_delivered=50,
|
||
emails_failed=50,
|
||
sms_requested=200,
|
||
sms_delivered=50,
|
||
sms_failed=50
|
||
)
|
||
|
||
services[2]['statistics'] = create_stats(
|
||
emails_requested=200,
|
||
emails_delivered=50,
|
||
emails_failed=50,
|
||
sms_requested=200,
|
||
sms_delivered=50,
|
||
sms_failed=50
|
||
)
|
||
|
||
mock_get_detailed_services.return_value = {'data': services}
|
||
mock_get_user(mocker, user=platform_admin_user)
|
||
client.login(platform_admin_user)
|
||
response = client.get(url_for(endpoint))
|
||
|
||
assert response.status_code == 200
|
||
mock_get_detailed_services.assert_called_once_with({'detailed': True,
|
||
'include_from_test_key': True,
|
||
'only_active': ANY})
|
||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||
|
||
table_body = page.find_all('table')[0].find_all('tbody')[0]
|
||
services = [service.tr for service in table_body.find_all('tbody')]
|
||
assert len(services) == 3
|
||
assert services[0].td.text.strip() == 'My Service 2'
|
||
assert services[1].td.text.strip() == 'My Service 1'
|
||
assert services[2].td.text.strip() == 'My Service 3'
|
||
|
||
|
||
def test_sum_service_usage_is_sum_of_all_activity(fake_uuid):
|
||
service = service_json(fake_uuid, 'My Service 1')
|
||
service['statistics'] = create_stats(
|
||
emails_requested=100,
|
||
emails_delivered=25,
|
||
emails_failed=25,
|
||
sms_requested=100,
|
||
sms_delivered=25,
|
||
sms_failed=25
|
||
)
|
||
assert sum_service_usage(service) == 200
|
||
|
||
|
||
def test_sum_service_usage_with_zeros(fake_uuid):
|
||
service = service_json(fake_uuid, 'My Service 1')
|
||
service['statistics'] = create_stats(
|
||
emails_requested=0,
|
||
emails_delivered=0,
|
||
emails_failed=25,
|
||
sms_requested=0,
|
||
sms_delivered=0,
|
||
sms_failed=0
|
||
)
|
||
assert sum_service_usage(service) == 0
|