mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-01 07:35:34 -05:00
@@ -3,7 +3,7 @@ from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from freezegun import freeze_time
|
||||
from mock import ANY
|
||||
from unittest.mock import ANY
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import requests_mock
|
||||
import pytest
|
||||
import uuid
|
||||
from datetime import (datetime, date)
|
||||
|
||||
import requests_mock
|
||||
import pytest
|
||||
from flask import current_app
|
||||
|
||||
from app import db
|
||||
@@ -28,7 +28,6 @@ from app.dao.jobs_dao import dao_create_job
|
||||
from app.dao.notifications_dao import dao_create_notification
|
||||
from app.dao.invited_user_dao import save_invited_user
|
||||
from app.clients.sms.firetext import FiretextClient
|
||||
from app.clients.sms.mmg import MMGClient
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@@ -276,9 +275,9 @@ def sample_job(notify_db,
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def sample_job_with_placeholdered_template(
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
service=None
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
service=None
|
||||
):
|
||||
return sample_job(
|
||||
notify_db,
|
||||
@@ -374,6 +373,41 @@ def sample_notification(notify_db,
|
||||
return notification
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def sample_email_notification(notify_db, notify_db_session):
|
||||
created_at = datetime.utcnow()
|
||||
service = sample_service(notify_db, notify_db_session)
|
||||
template = sample_email_template(notify_db, notify_db_session, service=service)
|
||||
job = sample_job(notify_db, notify_db_session, service=service, template=template)
|
||||
|
||||
notification_id = uuid.uuid4()
|
||||
|
||||
to = 'foo@bar.com'
|
||||
|
||||
data = {
|
||||
'id': notification_id,
|
||||
'to': to,
|
||||
'job_id': job.id,
|
||||
'job': job,
|
||||
'service_id': service.id,
|
||||
'service': service,
|
||||
'template': template,
|
||||
'template_version': template.version,
|
||||
'status': 'created',
|
||||
'reference': None,
|
||||
'created_at': created_at,
|
||||
'billable_units': 0,
|
||||
'personalisation': None,
|
||||
'notification_type': template.template_type,
|
||||
'api_key_id': None,
|
||||
'key_type': KEY_TYPE_NORMAL,
|
||||
'job_row_number': 1
|
||||
}
|
||||
notification = Notification(**data)
|
||||
dao_create_notification(notification)
|
||||
return notification
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def mock_statsd_inc(mocker):
|
||||
return mocker.patch('app.statsd_client.incr')
|
||||
|
||||
@@ -624,44 +624,6 @@ def test_get_notifications_for_service_returns_merged_template_content(notify_ap
|
||||
}
|
||||
|
||||
|
||||
def test_get_notification_public_api_format_is_not_changed(notify_api, sample_notification):
|
||||
with notify_api.test_request_context(), notify_api.test_client() as client:
|
||||
auth_header = create_authorization_header(service_id=sample_notification.service_id)
|
||||
|
||||
response = client.get(
|
||||
'/notifications/{}'.format(sample_notification.id),
|
||||
headers=[auth_header])
|
||||
|
||||
assert response.status_code == 200
|
||||
notification = json.loads(response.get_data(as_text=True))['data']['notification']
|
||||
# you should never remove things from this list!
|
||||
assert set(notification.keys()) == {
|
||||
# straight from db
|
||||
'id',
|
||||
'to',
|
||||
'job_row_number',
|
||||
'template_version',
|
||||
'billable_units',
|
||||
'notification_type',
|
||||
'created_at',
|
||||
'sent_at',
|
||||
'sent_by',
|
||||
'updated_at',
|
||||
'status',
|
||||
'reference',
|
||||
|
||||
# relationships
|
||||
'template',
|
||||
'service',
|
||||
'job',
|
||||
'api_key',
|
||||
|
||||
# other
|
||||
'body',
|
||||
'content_char_count'
|
||||
}
|
||||
|
||||
|
||||
def test_get_notification_selects_correct_template_for_personalisation(notify_api,
|
||||
notify_db,
|
||||
notify_db_session,
|
||||
|
||||
16
tests/app/public_contracts/__init__.py
Normal file
16
tests/app/public_contracts/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import os
|
||||
|
||||
from flask import json
|
||||
import jsonschema
|
||||
|
||||
|
||||
def validate(json_string, schema_filename):
|
||||
schema_dir = os.path.join(os.path.dirname(__file__), 'schemas')
|
||||
resolver = jsonschema.RefResolver('file://' + schema_dir + '/', None)
|
||||
with open(os.path.join(schema_dir, schema_filename)) as schema:
|
||||
jsonschema.validate(
|
||||
json.loads(json_string),
|
||||
json.load(schema),
|
||||
format_checker=jsonschema.FormatChecker(),
|
||||
resolver=resolver
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "GET notification return schema - for email notifications",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notification": {"$ref": "email_notification.json"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["notification"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["data"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "GET notification return schema - for sms notifications",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notification": {"$ref": "sms_notification.json"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["notification"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["data"]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "GET notification return schema - for sms notifications",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"notifications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{"$ref": "sms_notification.json"},
|
||||
{"$ref": "email_notification.json"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"additionalProperties": false
|
||||
},
|
||||
"page_size": {"type": "number"},
|
||||
"total": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"notifications", "links", "page_size", "total"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "POST notification return schema - for email notifications",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id"]
|
||||
},
|
||||
"body": {"type": "string"},
|
||||
"template_version": {"type": "number"},
|
||||
"subject": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["notification", "body", "template_version", "subject"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["data"]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "POST notification return schema - for sms notifications",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"notification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id"]
|
||||
},
|
||||
"body": {"type": "string"},
|
||||
"template_version": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["notification", "body", "template_version"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["data"]
|
||||
}
|
||||
12
tests/app/public_contracts/schemas/definitions.json
Normal file
12
tests/app/public_contracts/schemas/definitions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Common definitions - usage example: {'$ref': 'definitions.json#/uuid'} (swap quotes for double quotes)",
|
||||
"uuid": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
|
||||
},
|
||||
"datetime": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
106
tests/app/public_contracts/schemas/email_notification.json
Normal file
106
tests/app/public_contracts/schemas/email_notification.json
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"description": "Single email notification schema - as returned by GET /notification and GET /notification/{}",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"to": {"type": "string", "format": "email"},
|
||||
"job_row_number": {"oneOf":[
|
||||
{"type": "number"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"template_version": {"type": "number"},
|
||||
"billable_units": {"type": "number"},
|
||||
"notification_type": {
|
||||
"type": "string",
|
||||
"enum": ["email"]
|
||||
},
|
||||
"created_at": {"$ref": "definitions.json#/datetime"},
|
||||
"sent_at": {"oneOf":[
|
||||
{"$ref": "definitions.json#/datetime"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"sent_by": {"oneOf":[
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"updated_at": {"oneOf":[
|
||||
{"$ref": "definitions.json#/datetime"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"created",
|
||||
"sending",
|
||||
"delivered",
|
||||
"pending",
|
||||
"failed",
|
||||
"technical-failure",
|
||||
"temporary-failure",
|
||||
"permanent-failure"
|
||||
]
|
||||
},
|
||||
"reference": {"oneOf":[
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"template": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"name": {"type": "string"},
|
||||
"template_type": {
|
||||
"type": "string",
|
||||
"enum": ["email"]
|
||||
},
|
||||
"version": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "name", "template_type", "version"]
|
||||
},
|
||||
"service": {"$ref": "definitions.json#/uuid"},
|
||||
"job": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"original_file_name": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "original_file_name"]
|
||||
},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"api_key": {"oneOf":[
|
||||
{"$ref": "definitions.json#/uuid"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"body": {"type": "string"},
|
||||
"content_char_count": {"type": "null"},
|
||||
"subject": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id",
|
||||
"to",
|
||||
"job_row_number",
|
||||
"template_version",
|
||||
"billable_units",
|
||||
"notification_type",
|
||||
"created_at",
|
||||
"sent_at",
|
||||
"sent_by",
|
||||
"updated_at",
|
||||
"status",
|
||||
"reference",
|
||||
"template",
|
||||
"service",
|
||||
"job",
|
||||
"api_key",
|
||||
"body",
|
||||
"content_char_count",
|
||||
"subject"
|
||||
]
|
||||
}
|
||||
104
tests/app/public_contracts/schemas/sms_notification.json
Normal file
104
tests/app/public_contracts/schemas/sms_notification.json
Normal file
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"description": "Single sms notification schema - as returned by GET /notification and GET /notification/{}",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"to": {"type": "string"},
|
||||
"job_row_number": {"oneOf":[
|
||||
{"type": "number"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"template_version": {"type": "number"},
|
||||
"billable_units": {"type": "number"},
|
||||
"notification_type": {
|
||||
"type": "string",
|
||||
"enum": ["sms"]
|
||||
},
|
||||
"created_at": {"$ref": "definitions.json#/datetime"},
|
||||
"sent_at": {"oneOf":[
|
||||
{"$ref": "definitions.json#/datetime"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"sent_by": {"oneOf":[
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"updated_at": {"oneOf":[
|
||||
{"$ref": "definitions.json#/datetime"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"created",
|
||||
"sending",
|
||||
"delivered",
|
||||
"pending",
|
||||
"failed",
|
||||
"technical-failure",
|
||||
"temporary-failure",
|
||||
"permanent-failure"
|
||||
]
|
||||
},
|
||||
"reference": {"oneOf":[
|
||||
{"type": "string"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"template": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"name": {"type": "string"},
|
||||
"template_type": {
|
||||
"type": "string",
|
||||
"enum": ["sms"]
|
||||
},
|
||||
"version": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "name", "template_type", "version"]
|
||||
},
|
||||
"service": {"$ref": "definitions.json#/uuid"},
|
||||
"job": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"$ref": "definitions.json#/uuid"},
|
||||
"original_file_name": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "original_file_name"]
|
||||
},
|
||||
{"type": "null"}
|
||||
]
|
||||
},
|
||||
"api_key": {"oneOf":[
|
||||
{"$ref": "definitions.json#/uuid"},
|
||||
{"type": "null"}
|
||||
]},
|
||||
"body": {"type": "string"},
|
||||
"content_char_count": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id",
|
||||
"to",
|
||||
"job_row_number",
|
||||
"template_version",
|
||||
"billable_units",
|
||||
"notification_type",
|
||||
"created_at",
|
||||
"sent_at",
|
||||
"sent_by",
|
||||
"updated_at",
|
||||
"status",
|
||||
"reference",
|
||||
"template",
|
||||
"service",
|
||||
"job",
|
||||
"api_key",
|
||||
"body",
|
||||
"content_char_count"
|
||||
]
|
||||
}
|
||||
59
tests/app/public_contracts/test_GET_notification.py
Normal file
59
tests/app/public_contracts/test_GET_notification.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from . import validate
|
||||
from app.models import ApiKey, KEY_TYPE_NORMAL
|
||||
from app.dao.notifications_dao import dao_update_notification
|
||||
from app.dao.api_key_dao import save_model_api_key
|
||||
from tests import create_authorization_header
|
||||
|
||||
|
||||
def test_get_api_sms_contract(client, sample_notification):
|
||||
api_key = ApiKey(service=sample_notification.service,
|
||||
name='api_key',
|
||||
created_by=sample_notification.service.created_by,
|
||||
key_type=KEY_TYPE_NORMAL)
|
||||
save_model_api_key(api_key)
|
||||
sample_notification.job = None
|
||||
sample_notification.api_key = api_key
|
||||
sample_notification.key_type = KEY_TYPE_NORMAL
|
||||
dao_update_notification(sample_notification)
|
||||
auth_header = create_authorization_header(service_id=sample_notification.service_id)
|
||||
response = client.get('/notifications/{}'.format(sample_notification.id), headers=[auth_header])
|
||||
|
||||
validate(response.get_data(as_text=True), 'GET_notification_return_sms.json')
|
||||
|
||||
|
||||
def test_get_api_email_contract(client, sample_email_notification):
|
||||
api_key = ApiKey(service=sample_email_notification.service,
|
||||
name='api_key',
|
||||
created_by=sample_email_notification.service.created_by,
|
||||
key_type=KEY_TYPE_NORMAL)
|
||||
save_model_api_key(api_key)
|
||||
sample_email_notification.job = None
|
||||
sample_email_notification.api_key = api_key
|
||||
sample_email_notification.key_type = KEY_TYPE_NORMAL
|
||||
dao_update_notification(sample_email_notification)
|
||||
|
||||
auth_header = create_authorization_header(service_id=sample_email_notification.service_id)
|
||||
response = client.get('/notifications/{}'.format(sample_email_notification.id), headers=[auth_header])
|
||||
|
||||
validate(response.get_data(as_text=True), 'GET_notification_return_email.json')
|
||||
|
||||
|
||||
def test_get_job_sms_contract(client, sample_notification):
|
||||
auth_header = create_authorization_header(service_id=sample_notification.service_id)
|
||||
response = client.get('/notifications/{}'.format(sample_notification.id), headers=[auth_header])
|
||||
|
||||
validate(response.get_data(as_text=True), 'GET_notification_return_sms.json')
|
||||
|
||||
|
||||
def test_get_job_email_contract(client, sample_email_notification):
|
||||
auth_header = create_authorization_header(service_id=sample_email_notification.service_id)
|
||||
response = client.get('/notifications/{}'.format(sample_email_notification.id), headers=[auth_header])
|
||||
|
||||
validate(response.get_data(as_text=True), 'GET_notification_return_email.json')
|
||||
|
||||
|
||||
def test_get_notifications_contract(client, sample_notification, sample_email_notification):
|
||||
auth_header = create_authorization_header(service_id=sample_notification.service_id)
|
||||
response = client.get('/notifications', headers=[auth_header])
|
||||
|
||||
validate(response.get_data(as_text=True), 'GET_notifications_return.json')
|
||||
44
tests/app/public_contracts/test_POST_notification.py
Normal file
44
tests/app/public_contracts/test_POST_notification.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from flask import json
|
||||
|
||||
from . import validate
|
||||
from tests import create_authorization_header
|
||||
|
||||
|
||||
def test_post_sms_contract(client, mocker, sample_template):
|
||||
mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
mocker.patch('app.encryption.encrypt', return_value="something_encrypted")
|
||||
|
||||
data = {
|
||||
'to': '07700 900 855',
|
||||
'template': str(sample_template.id)
|
||||
}
|
||||
|
||||
auth_header = create_authorization_header(service_id=sample_template.service_id)
|
||||
|
||||
response = client.post(
|
||||
path='/notifications/sms',
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), auth_header]
|
||||
)
|
||||
|
||||
validate(response.get_data(as_text=True), 'POST_notification_return_sms.json')
|
||||
|
||||
|
||||
def test_post_email_contract(client, mocker, sample_email_template):
|
||||
mocker.patch('app.celery.tasks.send_sms.apply_async')
|
||||
mocker.patch('app.encryption.encrypt', return_value="something_encrypted")
|
||||
|
||||
data = {
|
||||
'to': 'foo@bar.com',
|
||||
'template': str(sample_email_template.id)
|
||||
}
|
||||
|
||||
auth_header = create_authorization_header(service_id=sample_email_template.service_id)
|
||||
|
||||
response = client.post(
|
||||
path='/notifications/email',
|
||||
data=json.dumps(data),
|
||||
headers=[('Content-Type', 'application/json'), auth_header]
|
||||
)
|
||||
|
||||
validate(response.get_data(as_text=True), 'POST_notification_return_email.json')
|
||||
@@ -1,4 +1,4 @@
|
||||
from mock import ANY
|
||||
from unittest.mock import ANY
|
||||
|
||||
from app.statsd_decorators import statsd
|
||||
import app
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
import boto3
|
||||
import mock
|
||||
from unittest import mock
|
||||
import pytest
|
||||
from alembic.command import upgrade
|
||||
from alembic.config import Config
|
||||
@@ -24,6 +24,12 @@ def notify_api(request):
|
||||
return app
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def client(notify_api):
|
||||
with notify_api.test_request_context(), notify_api.test_client() as client:
|
||||
yield client
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def notify_db(notify_api, request):
|
||||
Migrate(notify_api, db)
|
||||
|
||||
Reference in New Issue
Block a user