mirror of
https://github.com/GSA/notifications-api.git
synced 2025-12-18 05:11:42 -05:00
Updated test_validators to test the contents of the error messages.
Added some tests to the test_post_notifications. Added a errorhandler for AuthErrors. This endpoint is not being used anywhere, however there is some common code being used in the v1 post endpoint. The only thing that may be affected is the error response, hopefully they are the same.
This commit is contained in:
@@ -25,12 +25,12 @@ def create_content_for_notification(template, personalisation):
|
||||
def check_placeholders(template_object):
|
||||
if template_object.missing_data:
|
||||
message = 'Template missing personalisation: {}'.format(", ".join(template_object.missing_data))
|
||||
raise BadRequestError(message=message)
|
||||
raise BadRequestError(fields=[{'template': message}], message=message)
|
||||
|
||||
if template_object.additional_data:
|
||||
message = 'Template personalisation not needed for template: {}'.format(
|
||||
", ".join(template_object.additional_data))
|
||||
raise BadRequestError(message=message)
|
||||
raise BadRequestError(fields=[{'template': message}], message=message)
|
||||
|
||||
|
||||
def persist_notification(template_id,
|
||||
|
||||
@@ -16,14 +16,15 @@ def check_service_message_limit(key_type, service):
|
||||
|
||||
def check_template_is_for_notification_type(notification_type, template_type):
|
||||
if notification_type != template_type:
|
||||
raise BadRequestError(
|
||||
message = "{0} template is not suitable for {1} notification".format(template_type,
|
||||
notification_type))
|
||||
notification_type)
|
||||
raise BadRequestError(fields=[{'template': message}], message=message)
|
||||
|
||||
|
||||
def check_template_is_active(template):
|
||||
if template.archived:
|
||||
raise BadRequestError(message="Template has been deleted")
|
||||
raise BadRequestError(fields=[{'template': 'Template has been deleted'}],
|
||||
message="Template has been deleted")
|
||||
|
||||
|
||||
def service_can_send_to_recipient(send_to, key_type, service):
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
from flask import jsonify, current_app
|
||||
from sqlalchemy.exc import SQLAlchemyError, DataError
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from app.authentication.auth import AuthError
|
||||
from app.errors import InvalidRequest
|
||||
|
||||
|
||||
@@ -15,11 +19,11 @@ class TooManyRequestsError(InvalidRequest):
|
||||
|
||||
class BadRequestError(InvalidRequest):
|
||||
status_code = 400
|
||||
code = "10400"
|
||||
code = 10400
|
||||
link = "link to documentation"
|
||||
message = "An error occurred"
|
||||
|
||||
def __init__(self, fields=None, message=None):
|
||||
def __init__(self, fields=[], message=None):
|
||||
self.fields = fields
|
||||
self.message = message if message else self.message
|
||||
|
||||
@@ -31,7 +35,20 @@ def register_errors(blueprint):
|
||||
response = jsonify(error.to_dict_v2()), error.status_code
|
||||
return response
|
||||
|
||||
@blueprint.errorhandler(NoResultFound)
|
||||
@blueprint.errorhandler(DataError)
|
||||
def no_result_found(e):
|
||||
current_app.logger.exception(e)
|
||||
return jsonify(message="No result found"), 404
|
||||
|
||||
@blueprint.errorhandler(AuthError)
|
||||
def auth_error(error):
|
||||
return jsonify(status_code=error.code,
|
||||
message=error.message,
|
||||
code=error.code,
|
||||
link='link to docs'), error.code
|
||||
|
||||
@blueprint.errorhandler(Exception)
|
||||
def authentication_error(error):
|
||||
# v2 error format - NOT this
|
||||
return jsonify(result='error', message=error.message), error.code
|
||||
def internal_server_error(error):
|
||||
current_app.logger.exception(error)
|
||||
return jsonify(message='Internal server error'), 500
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from flask import request, jsonify
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from app import api_user
|
||||
from app.dao import services_dao, templates_dao
|
||||
from app.models import SMS_TYPE
|
||||
@@ -11,6 +13,7 @@ from app.notifications.validators import (check_service_message_limit,
|
||||
service_can_send_to_recipient,
|
||||
check_sms_content_char_count)
|
||||
from app.schema_validation import validate
|
||||
from app.v2.errors import BadRequestError
|
||||
from app.v2.notifications import notification_blueprint
|
||||
from app.v2.notifications.notification_schemas import (post_sms_request,
|
||||
create_post_sms_response_from_notification)
|
||||
@@ -52,8 +55,14 @@ def post_email_notification():
|
||||
|
||||
|
||||
def __validate_template(form, service):
|
||||
try:
|
||||
template = templates_dao.dao_get_template_by_id_and_service_id(template_id=form['template_id'],
|
||||
service_id=service.id)
|
||||
except NoResultFound:
|
||||
message = 'Template not found'
|
||||
raise BadRequestError(message=message,
|
||||
fields=[{'template': message}])
|
||||
|
||||
check_template_is_for_notification_type(SMS_TYPE, template.template_type)
|
||||
check_template_is_active(template)
|
||||
template_with_content = create_content_for_notification(template, form.get('personalisation', {}))
|
||||
|
||||
@@ -62,9 +62,11 @@ def test_persist_notification_throws_exception_when_missing_template(sample_temp
|
||||
|
||||
@pytest.mark.parametrize('research_mode, queue, notification_type, key_type',
|
||||
[(True, 'research-mode', 'sms', 'normal'),
|
||||
(False, 'send-sms', 'sms', 'normal'),
|
||||
(True, 'research-mode', 'email', 'normal'),
|
||||
(True, 'research-mode', 'email', 'team'),
|
||||
(False, 'send-sms', 'sms', 'normal'),
|
||||
(False, 'send-email', 'email', 'normal'),
|
||||
(False, 'send-sms', 'sms', 'team'),
|
||||
(False, 'research-mode', 'sms', 'test')])
|
||||
def test_send_notification_to_queue(notify_db, notify_db_session,
|
||||
research_mode, notification_type,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import pytest
|
||||
|
||||
from app.notifications.validators import check_service_message_limit, check_template_is_for_notification_type, \
|
||||
check_template_is_active, service_can_send_to_recipient, check_sms_content_char_count
|
||||
from app.v2.errors import BadRequestError, TooManyRequestsError
|
||||
@@ -26,8 +25,12 @@ def test_check_service_message_limit_over_message_limit_fails(key_type, notify_d
|
||||
service = create_service(notify_db, notify_db_session, restricted=True, limit=4)
|
||||
for x in range(5):
|
||||
create_notification(notify_db, notify_db_session, service=service)
|
||||
with pytest.raises(TooManyRequestsError):
|
||||
with pytest.raises(TooManyRequestsError) as e:
|
||||
check_service_message_limit(key_type, service)
|
||||
assert e.value.status_code == 429
|
||||
assert e.value.code == '10429'
|
||||
assert e.value.message == 'Exceeded send limits (4) for today'
|
||||
assert e.value.fields == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize('template_type, notification_type',
|
||||
@@ -43,9 +46,14 @@ def test_check_template_is_for_notification_type_pass(template_type, notificatio
|
||||
('email', 'sms')])
|
||||
def test_check_template_is_for_notification_type_fails_when_template_type_does_not_match_notification_type(
|
||||
template_type, notification_type):
|
||||
with pytest.raises(BadRequestError):
|
||||
with pytest.raises(BadRequestError) as e:
|
||||
check_template_is_for_notification_type(notification_type=notification_type,
|
||||
template_type=template_type)
|
||||
assert e.value.code == 10400
|
||||
error_message = '{0} template is not suitable for {1} notification'.format(template_type, notification_type)
|
||||
assert e.value.message == error_message
|
||||
assert e.value.link == 'link to documentation'
|
||||
assert e.value.fields == [{'template': error_message}]
|
||||
|
||||
|
||||
def test_check_template_is_active_passes(sample_template):
|
||||
@@ -56,13 +64,13 @@ def test_check_template_is_active_fails(sample_template):
|
||||
sample_template.archived = True
|
||||
from app.dao.templates_dao import dao_update_template
|
||||
dao_update_template(sample_template)
|
||||
try:
|
||||
with pytest.raises(BadRequestError) as e:
|
||||
check_template_is_active(sample_template)
|
||||
except BadRequestError as e:
|
||||
assert e.status_code == 400
|
||||
assert e.code == '10400'
|
||||
assert e.message == 'Template has been deleted'
|
||||
assert e.link == "link to documentation"
|
||||
assert e.value.status_code == 400
|
||||
assert e.value.code == 10400
|
||||
assert e.value.message == 'Template has been deleted'
|
||||
assert e.value.link == "link to documentation"
|
||||
assert e.value.fields == [{'template': 'Template has been deleted'}]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('key_type',
|
||||
@@ -103,26 +111,36 @@ def test_service_can_send_to_recipient_passes_for_whitelisted_recipient_passes(k
|
||||
sample_service) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('key_type',
|
||||
['team', 'normal'])
|
||||
def test_service_can_send_to_recipient_fails_when_recipient_is_not_on_team(key_type, notify_db, notify_db_session):
|
||||
@pytest.mark.parametrize('recipient', ['07513332413', 'some_other_email@test.com'])
|
||||
@pytest.mark.parametrize('key_type, error_message',
|
||||
[('team', 'Can’t send to this recipient using a team-only API key'),
|
||||
('normal',
|
||||
"Can’t send to this recipient when service is in trial mode – see https://www.notifications.service.gov.uk/trial-mode")]) # noqa
|
||||
def test_service_can_send_to_recipient_fails_when_recipient_is_not_on_team(recipient, key_type, error_message,
|
||||
notify_db, notify_db_session):
|
||||
trial_mode_service = create_service(notify_db, notify_db_session, service_name='trial mode', restricted=True)
|
||||
with pytest.raises(BadRequestError):
|
||||
assert service_can_send_to_recipient("some_other_email@test.com",
|
||||
key_type,
|
||||
trial_mode_service) is None
|
||||
with pytest.raises(BadRequestError):
|
||||
assert service_can_send_to_recipient('07513332413',
|
||||
with pytest.raises(BadRequestError) as exec_info:
|
||||
assert service_can_send_to_recipient(recipient,
|
||||
key_type,
|
||||
trial_mode_service) is None
|
||||
assert exec_info.value.status_code == 400
|
||||
assert exec_info.value.code == 10400
|
||||
assert exec_info.value.message == error_message
|
||||
assert exec_info.value.link == 'link to documentation'
|
||||
assert exec_info.value.fields == []
|
||||
|
||||
|
||||
def test_service_can_send_to_recipient_fails_when_mobile_number_is_not_on_team(notify_db, notify_db_session):
|
||||
live_service = create_service(notify_db, notify_db_session, service_name='live mode', restricted=False)
|
||||
with pytest.raises(BadRequestError):
|
||||
with pytest.raises(BadRequestError) as e:
|
||||
assert service_can_send_to_recipient("0758964221",
|
||||
'team',
|
||||
live_service) is None
|
||||
assert e.value.status_code == 400
|
||||
assert e.value.code == 10400
|
||||
assert e.value.message == 'Can’t send to this recipient using a team-only API key'
|
||||
assert e.value.link == 'link to documentation'
|
||||
assert e.value.fields == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize('char_count', [495, 0, 494, 200])
|
||||
@@ -132,5 +150,11 @@ def test_check_sms_content_char_count_passes(char_count, notify_api):
|
||||
|
||||
@pytest.mark.parametrize('char_count', [496, 500, 6000])
|
||||
def test_check_sms_content_char_count_fails(char_count, notify_api):
|
||||
with pytest.raises(BadRequestError):
|
||||
with pytest.raises(BadRequestError) as e:
|
||||
check_sms_content_char_count(char_count)
|
||||
assert e.value.status_code == 400
|
||||
assert e.value.code == 10400
|
||||
assert e.value.message == 'Content for template has a character count greater than the limit of {}'.format(
|
||||
notify_api.config['SMS_CHAR_COUNT_LIMIT'])
|
||||
assert e.value.link == 'link to documentation'
|
||||
assert e.value.fields == []
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import uuid
|
||||
|
||||
from flask import json
|
||||
|
||||
from tests import create_authorization_header
|
||||
@@ -27,14 +29,14 @@ def test_post_sms_notification_returns_201(notify_api, sample_template, mocker):
|
||||
assert mocked.called
|
||||
|
||||
|
||||
def test_post_sms_notification_returns_404_when_template_is_wrong_type(notify_api, sample_email_template):
|
||||
def test_post_sms_notification_returns_404_and_missing_template(notify_api, sample_service):
|
||||
with notify_api.test_request_context():
|
||||
with notify_api.test_client() as client:
|
||||
data = {
|
||||
'phone_number': '+447700900855',
|
||||
'template_id': str(sample_email_template.id)
|
||||
'template_id': str(uuid.uuid4())
|
||||
}
|
||||
auth_header = create_authorization_header(service_id=sample_email_template.service_id)
|
||||
auth_header = create_authorization_header(service_id=sample_service.id)
|
||||
|
||||
response = client.post(
|
||||
path='/v2/notifications/sms',
|
||||
@@ -42,8 +44,31 @@ def test_post_sms_notification_returns_404_when_template_is_wrong_type(notify_ap
|
||||
headers=[('Content-Type', 'application/json'), auth_header])
|
||||
|
||||
assert response.status_code == 400
|
||||
resp_text = json.loads(response.get_data(as_text=True))
|
||||
assert resp_text['code'] == '10400'
|
||||
assert resp_text['message'] == '{0} template is not suitable for {1} notification'.format('email', 'sms')
|
||||
assert resp_text['link'] == 'link to documentation'
|
||||
assert resp_text.get('fields', None) is None
|
||||
assert response.headers['Content-type'] == 'application/json'
|
||||
|
||||
error_json = json.loads(response.get_data(as_text=True))
|
||||
assert error_json['code'] == 10400
|
||||
assert error_json['message'] == 'Template not found'
|
||||
assert error_json['fields'] == [{'template': 'Template not found'}]
|
||||
assert error_json['link'] == 'link to documentation'
|
||||
|
||||
|
||||
def test_post_sms_notification_returns_403_and_well_formed_auth_error(notify_api, sample_template, mocker):
|
||||
with notify_api.test_request_context():
|
||||
with notify_api.test_client() as client:
|
||||
mocked = mocker.patch('app.celery.provider_tasks.deliver_sms.apply_async')
|
||||
data = {
|
||||
'phone_number': '+447700900855',
|
||||
'template_id': str(sample_template.id)
|
||||
}
|
||||
|
||||
response = client.post(
|
||||
path='/v2/notifications/sms',
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json')])
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.headers['Content-type'] == 'application/json'
|
||||
error_resp = json.loads(response.get_data(as_text=True))
|
||||
assert error_resp['code'] == 401
|
||||
assert error_resp['message'] == {'token': ['Unauthorized, authentication token must be provided']}
|
||||
|
||||
Reference in New Issue
Block a user