Merge branch 'master' into do-not-write-test-data-to-the-history-table

Conflicts:
	app/dao/notifications_dao.py
This commit is contained in:
Rebecca Law
2016-12-21 09:57:17 +00:00
13 changed files with 269 additions and 181 deletions

View File

@@ -43,15 +43,13 @@ def deliver_sms(self, notification_id):
send_to_providers.send_sms_to_provider(notification) send_to_providers.send_sms_to_provider(notification)
except Exception as e: except Exception as e:
try: try:
current_app.logger.error( current_app.logger.exception(
"RETRY: SMS notification {} failed".format(notification_id) "RETRY: SMS notification {} failed".format(notification_id)
) )
current_app.logger.exception(e)
self.retry(queue="retry", countdown=retry_iteration_to_delay(self.request.retries)) self.retry(queue="retry", countdown=retry_iteration_to_delay(self.request.retries))
except self.MaxRetriesExceededError: except self.MaxRetriesExceededError:
current_app.logger.error( current_app.logger.exception(
"RETRY FAILED: task send_sms_to_provider failed for notification {}".format(notification_id), "RETRY FAILED: task send_sms_to_provider failed for notification {}".format(notification_id),
e
) )
update_notification_status_by_id(notification_id, 'technical-failure') update_notification_status_by_id(notification_id, 'technical-failure')
@@ -69,14 +67,12 @@ def deliver_email(self, notification_id):
update_notification_status_by_id(notification_id, 'technical-failure') update_notification_status_by_id(notification_id, 'technical-failure')
except Exception as e: except Exception as e:
try: try:
current_app.logger.error( current_app.logger.exception(
"RETRY: Email notification {} failed".format(notification_id) "RETRY: Email notification {} failed".format(notification_id)
) )
current_app.logger.exception(e)
self.retry(queue="retry", countdown=retry_iteration_to_delay(self.request.retries)) self.retry(queue="retry", countdown=retry_iteration_to_delay(self.request.retries))
except self.MaxRetriesExceededError: except self.MaxRetriesExceededError:
current_app.logger.error( current_app.logger.error(
"RETRY FAILED: task send_email_to_provider failed for notification {}".format(notification_id), "RETRY FAILED: task send_email_to_provider failed for notification {}".format(notification_id)
e
) )
update_notification_status_by_id(notification_id, 'technical-failure') update_notification_status_by_id(notification_id, 'technical-failure')

View File

@@ -132,7 +132,7 @@ def dao_create_notification(notification):
db.session.add(notification) db.session.add(notification)
if _should_record_notification_in_history_table(notification): if _should_record_notification_in_history_table(notification):
db.session.add(NotificationHistory.from_notification(notification)) db.session.add(NotificationHistory.from_original(notification))
def _should_record_notification_in_history_table(notification): def _should_record_notification_in_history_table(notification):
@@ -200,7 +200,7 @@ def dao_update_notification(notification):
db.session.add(notification) db.session.add(notification)
if _should_record_notification_in_history_table(notification): if _should_record_notification_in_history_table(notification):
notification_history = NotificationHistory.query.get(notification.id) notification_history = NotificationHistory.query.get(notification.id)
notification_history.update_from_notification(notification) notification_history.update_from_original(notification)
db.session.add(notification_history) db.session.add(notification_history)
db.session.commit() db.session.commit()

View File

@@ -1,6 +1,8 @@
from datetime import datetime
from sqlalchemy import asc from sqlalchemy import asc
from app.dao.dao_utils import transactional from app.dao.dao_utils import transactional
from app.models import ProviderDetails from app.models import ProviderDetails, ProviderDetailsHistory
from app import db from app import db
@@ -20,4 +22,8 @@ def get_provider_details_by_notification_type(notification_type):
@transactional @transactional
def dao_update_provider_details(provider_details): def dao_update_provider_details(provider_details):
provider_details.version += 1
provider_details.updated_at = datetime.utcnow()
history = ProviderDetailsHistory.from_original(provider_details)
db.session.add(provider_details) db.session.add(provider_details)
db.session.add(history)

View File

@@ -35,6 +35,18 @@ def filter_null_value_fields(obj):
) )
class HistoryModel:
@classmethod
def from_original(cls, original):
history = cls()
history.update_from_original(original)
return history
def update_from_original(self, original):
for c in self.__table__.columns:
setattr(self, c.name, getattr(original, c.name))
class User(db.Model): class User(db.Model):
__tablename__ = 'users' __tablename__ = 'users'
@@ -354,7 +366,22 @@ class ProviderDetails(db.Model):
identifier = db.Column(db.String, nullable=False) identifier = db.Column(db.String, nullable=False)
priority = db.Column(db.Integer, nullable=False) priority = db.Column(db.Integer, nullable=False)
notification_type = db.Column(notification_types, nullable=False) notification_type = db.Column(notification_types, nullable=False)
active = db.Column(db.Boolean, default=False) active = db.Column(db.Boolean, default=False, nullable=False)
version = db.Column(db.Integer, default=1, nullable=False)
updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow)
class ProviderDetailsHistory(db.Model, HistoryModel):
__tablename__ = 'provider_details_history'
id = db.Column(UUID(as_uuid=True), primary_key=True, nullable=False)
display_name = db.Column(db.String, nullable=False)
identifier = db.Column(db.String, nullable=False)
priority = db.Column(db.Integer, nullable=False)
notification_type = db.Column(notification_types, nullable=False)
active = db.Column(db.Boolean, nullable=False)
version = db.Column(db.Integer, primary_key=True, nullable=False)
updated_at = db.Column(db.DateTime, nullable=True, onupdate=datetime.datetime.utcnow)
JOB_STATUS_PENDING = 'pending' JOB_STATUS_PENDING = 'pending'
@@ -654,7 +681,7 @@ class Notification(db.Model):
return serialized return serialized
class NotificationHistory(db.Model): class NotificationHistory(db.Model, HistoryModel):
__tablename__ = 'notification_history' __tablename__ = 'notification_history'
id = db.Column(UUID(as_uuid=True), primary_key=True) id = db.Column(UUID(as_uuid=True), primary_key=True)
@@ -680,14 +707,10 @@ class NotificationHistory(db.Model):
client_reference = db.Column(db.String, nullable=True) client_reference = db.Column(db.String, nullable=True)
@classmethod @classmethod
def from_notification(cls, notification): def from_original(cls, notification):
history = cls(**{c.name: getattr(notification, c.name) for c in cls.__table__.columns}) history = super().from_original(notification)
return history return history
def update_from_notification(self, notification):
for c in self.__table__.columns:
setattr(self, c.name, getattr(notification, c.name))
INVITED_USER_STATUS_TYPES = ['pending', 'accepted', 'cancelled'] INVITED_USER_STATUS_TYPES = ['pending', 'accepted', 'cancelled']

View File

@@ -37,9 +37,10 @@ def update_provider_details(provider_details_id):
current_data.update(request.get_json()) current_data.update(request.get_json())
update_dict = provider_details_schema.load(current_data).data update_dict = provider_details_schema.load(current_data).data
if "identifier" in request.get_json().keys(): invalid_keys = {'identifier', 'version', 'updated_at'} & set(key for key in request.get_json().keys())
if invalid_keys:
message = "Not permitted to be updated" message = "Not permitted to be updated"
errors = {'identifier': [message]} errors = {key: [message] for key in invalid_keys}
raise InvalidRequest(errors, status_code=400) raise InvalidRequest(errors, status_code=400)
dao_update_provider_details(update_dict) dao_update_provider_details(update_dict)

View File

@@ -137,7 +137,7 @@ class Config(object):
REDIS_ENABLED = False REDIS_ENABLED = False
SENDING_NOTIFICATIONS_TIMEOUT_PERIOD = 259200 SENDING_NOTIFICATIONS_TIMEOUT_PERIOD = 259200 # 3 days
SIMULATED_EMAIL_ADDRESSES = ('simulate-delivered@notifications.service.gov.uk', SIMULATED_EMAIL_ADDRESSES = ('simulate-delivered@notifications.service.gov.uk',
'simulate-permanent-failure@notifications.service.gov.uk', 'simulate-permanent-failure@notifications.service.gov.uk',

View File

@@ -9,7 +9,7 @@ ENV PYTHONUNBUFFERED=1 \
RUN \ RUN \
echo "Install base packages" \ echo "Install base packages" \
&& ([ -z "$HTTP_PROXY" ] || echo "Acquire::http::Proxy \"${HTTP_PROXY}\";\n" > /etc/apt/apt.conf.d/99HttpProxy) \ && ([ -z "$HTTP_PROXY" ] || echo "Acquire::http::Proxy \"${HTTP_PROXY}\";" > /etc/apt/apt.conf.d/99HttpProxy) \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
make \ make \

View File

@@ -0,0 +1,54 @@
"""
* add version and updated_at to provider_details
* set active to not nullable (any existing null is set to false)
* create provider_details_history table, mimicking provider_details
Revision ID: 0062_provider_details_history
Revises: 0061_add_client_reference
Create Date: 2016-12-14 13:00:24.226990
"""
# revision identifiers, used by Alembic.
revision = '0062_provider_details_history'
down_revision = '0061_add_client_reference'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
def upgrade():
op.get_bind()
op.add_column('provider_details', sa.Column('updated_at', sa.DateTime()))
op.execute('UPDATE provider_details SET active = false WHERE active is null')
op.alter_column('provider_details', 'active', nullable=False)
op.add_column('provider_details', sa.Column('version', sa.Integer(), nullable=True))
op.execute('UPDATE provider_details SET version = 1')
op.alter_column('provider_details', 'version', nullable=False)
op.create_table('provider_details_history',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('display_name', sa.String(), nullable=False),
sa.Column('identifier', sa.String(), nullable=False),
sa.Column('priority', sa.Integer(), nullable=False),
sa.Column('notification_type', postgresql.ENUM('email', 'sms', 'letter', name='notification_type', create_type=False), nullable=False),
sa.Column('active', sa.Boolean(), nullable=False),
sa.Column('version', sa.Integer(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id', 'version')
)
op.execute(
'INSERT INTO provider_details_history' +
' (id, display_name, identifier, priority, notification_type, active, version)' +
' SELECT id, display_name, identifier, priority, notification_type, active, version FROM provider_details'
)
def downgrade():
op.drop_table('provider_details_history')
op.alter_column('provider_details', 'active', existing_type=sa.BOOLEAN(), nullable=True)
op.drop_column('provider_details', 'version')
op.drop_column('provider_details', 'updated_at')

View File

@@ -98,7 +98,7 @@ def test_send_sms_raises_if_firetext_rejects(mocker, mock_firetext_client):
assert '"code": 1' in exc.value.text assert '"code": 1' in exc.value.text
def test_send_sms_raises_if_firetext_rejects(mocker, mock_firetext_client): def test_send_sms_raises_if_firetext_rejects_with_unexpected_data(mocker, mock_firetext_client):
to = content = reference = 'foo' to = content = reference = 'foo'
response_dict = {"something": "gone bad"} response_dict = {"something": "gone bad"}

View File

@@ -1,6 +1,7 @@
import uuid import uuid
from datetime import (datetime, date, timedelta) from datetime import (datetime, date, timedelta)
from sqlalchemy.orm.session import make_transient
import requests_mock import requests_mock
import pytest import pytest
from flask import current_app from flask import current_app
@@ -18,6 +19,8 @@ from app.models import (
Permission, Permission,
ProviderStatistics, ProviderStatistics,
ProviderDetails, ProviderDetails,
ProviderDetailsHistory,
ProviderRates,
NotificationStatistics, NotificationStatistics,
ServiceWhitelist, ServiceWhitelist,
KEY_TYPE_NORMAL, KEY_TYPE_TEST, KEY_TYPE_TEAM, KEY_TYPE_NORMAL, KEY_TYPE_TEST, KEY_TYPE_TEAM,
@@ -857,3 +860,33 @@ def sample_provider_rate(notify_db, notify_db_session, valid_from=None, rate=Non
valid_from=valid_from if valid_from is not None else datetime.utcnow(), valid_from=valid_from if valid_from is not None else datetime.utcnow(),
rate=rate if rate is not None else 1, rate=rate if rate is not None else 1,
) )
@pytest.fixture
def restore_provider_details(notify_db, notify_db_session):
"""
We view ProviderDetails as a static in notify_db_session, since we don't modify it... except we do, we updated
priority. This fixture is designed to be used in tests that will knowingly touch provider details, to restore them
to previous state.
Note: This doesn't technically require notify_db_session (only notify_db), but kept as a requirement to encourage
good usage - if you're modifying ProviderDetails' state then it's good to clear down the rest of the DB too
"""
existing_provider_details = ProviderDetails.query.all()
existing_provider_details_history = ProviderDetailsHistory.query.all()
# make transient removes the objects from the session - since we'll want to delete them later
for epd in existing_provider_details:
make_transient(epd)
for epdh in existing_provider_details_history:
make_transient(epdh)
yield
# also delete these as they depend on provider_details
ProviderRates.query.delete()
ProviderDetails.query.delete()
ProviderDetailsHistory.query.delete()
notify_db.session.commit()
notify_db.session.add_all(existing_provider_details)
notify_db.session.add_all(existing_provider_details_history)
notify_db.session.commit()

View File

@@ -1,22 +1,27 @@
from app.models import ProviderDetails from datetime import datetime
from freezegun import freeze_time
from app.models import ProviderDetails, ProviderDetailsHistory
from app import clients from app import clients
from app.dao.provider_details_dao import ( from app.dao.provider_details_dao import (
get_provider_details, get_provider_details,
get_provider_details_by_notification_type get_provider_details_by_notification_type,
dao_update_provider_details
) )
def test_can_get_all_providers(notify_db, notify_db_session): def test_can_get_all_providers(restore_provider_details):
assert len(get_provider_details()) == 4 assert len(get_provider_details()) == 4
def test_can_get_sms_providers(notify_db, notify_db_session): def test_can_get_sms_providers(restore_provider_details):
assert len(get_provider_details_by_notification_type('sms')) == 3 sms_providers = get_provider_details_by_notification_type('sms')
types = [provider.notification_type for provider in get_provider_details_by_notification_type('sms')] assert len(sms_providers) == 3
assert all('sms' == notification_type for notification_type in types) assert all('sms' == prov.notification_type for prov in sms_providers)
def test_can_get_sms_providers_in_order(notify_db, notify_db_session): def test_can_get_sms_providers_in_order(restore_provider_details):
providers = get_provider_details_by_notification_type('sms') providers = get_provider_details_by_notification_type('sms')
assert providers[0].identifier == "mmg" assert providers[0].identifier == "mmg"
@@ -24,35 +29,52 @@ def test_can_get_sms_providers_in_order(notify_db, notify_db_session):
assert providers[2].identifier == "loadtesting" assert providers[2].identifier == "loadtesting"
def test_can_get_email_providers_in_order(notify_db, notify_db_session): def test_can_get_email_providers_in_order(restore_provider_details):
providers = get_provider_details_by_notification_type('email') providers = get_provider_details_by_notification_type('email')
assert providers[0].identifier == "ses" assert providers[0].identifier == "ses"
def test_can_get_email_providers(notify_db, notify_db_session): def test_can_get_email_providers(restore_provider_details):
assert len(get_provider_details_by_notification_type('email')) == 1 assert len(get_provider_details_by_notification_type('email')) == 1
types = [provider.notification_type for provider in get_provider_details_by_notification_type('email')] types = [provider.notification_type for provider in get_provider_details_by_notification_type('email')]
assert all('email' == notification_type for notification_type in types) assert all('email' == notification_type for notification_type in types)
def test_should_error_if_any_provider_in_database_not_in_code(notify_db, notify_db_session, notify_api): def test_should_not_error_if_any_provider_in_code_not_in_database(restore_provider_details):
providers = ProviderDetails.query.all()
for provider in providers:
if provider.notification_type == 'sms':
assert clients.get_sms_client(provider.identifier)
if provider.notification_type == 'email':
assert clients.get_email_client(provider.identifier)
def test_should_not_error_if_any_provider_in_code_not_in_database(notify_db, notify_db_session, notify_api):
providers = ProviderDetails.query.all() providers = ProviderDetails.query.all()
ProviderDetails.query.filter_by(identifier='mmg').delete() ProviderDetails.query.filter_by(identifier='mmg').delete()
for provider in providers: assert clients.get_sms_client('mmg')
if provider.notification_type == 'sms':
assert clients.get_sms_client(provider.identifier)
if provider.notification_type == 'email': @freeze_time('2000-01-01T00:00:00')
assert clients.get_email_client(provider.identifier) def test_update_adds_history(restore_provider_details):
ses = ProviderDetails.query.filter(ProviderDetails.identifier == 'ses').one()
ses_history = ProviderDetailsHistory.query.filter(ProviderDetailsHistory.id == ses.id).one()
assert ses.version == 1
assert ses_history.version == 1
assert ses.updated_at is None
ses.active = False
dao_update_provider_details(ses)
assert not ses.active
assert ses.updated_at == datetime(2000, 1, 1, 0, 0, 0)
ses_history = ProviderDetailsHistory.query.filter(
ProviderDetailsHistory.id == ses.id
).order_by(
ProviderDetailsHistory.version
).all()
assert ses_history[0].active
assert ses_history[0].version == 1
assert ses_history[0].updated_at is None
assert not ses_history[1].active
assert ses_history[1].version == 2
assert ses_history[1].updated_at == datetime(2000, 1, 1, 0, 0, 0)

View File

@@ -1,150 +1,103 @@
import pytest
from flask import json from flask import json
from app.models import ProviderDetails
from tests import create_authorization_header from tests import create_authorization_header
def test_get_provider_details_in_type_and_identifier_order(notify_db, notify_db_session, notify_api): def test_get_provider_details_in_type_and_identifier_order(client, notify_db):
with notify_api.test_request_context(): response = client.get(
with notify_api.test_client() as client: '/provider-details',
auth_header = create_authorization_header() headers=[create_authorization_header()]
response = client.get( )
'/provider-details', assert response.status_code == 200
headers=[auth_header] json_resp = json.loads(response.get_data(as_text=True))['provider_details']
) assert len(json_resp) == 4
assert response.status_code == 200
json_resp = json.loads(response.get_data(as_text=True))['provider_details']
assert len(json_resp) == 4
assert json_resp[0]['identifier'] == 'ses' assert json_resp[0]['identifier'] == 'ses'
assert json_resp[1]['identifier'] == 'mmg' assert json_resp[1]['identifier'] == 'mmg'
assert json_resp[2]['identifier'] == 'firetext' assert json_resp[2]['identifier'] == 'firetext'
assert json_resp[3]['identifier'] == 'loadtesting' assert json_resp[3]['identifier'] == 'loadtesting'
def test_get_provider_details_by_id(notify_db, notify_db_session, notify_api): def test_get_provider_details_by_id(client, notify_db):
with notify_api.test_request_context(): response = client.get(
with notify_api.test_client() as client: '/provider-details',
auth_header = create_authorization_header() headers=[create_authorization_header()]
response = client.get( )
'/provider-details', json_resp = json.loads(response.get_data(as_text=True))['provider_details']
headers=[auth_header]
)
json_resp = json.loads(response.get_data(as_text=True))['provider_details']
provider_resp = client.get( provider_resp = client.get(
'/provider-details/{}'.format(json_resp[0]['id']), '/provider-details/{}'.format(json_resp[0]['id']),
headers=[auth_header] headers=[create_authorization_header()]
) )
provider = json.loads(provider_resp.get_data(as_text=True))['provider_details'] provider = json.loads(provider_resp.get_data(as_text=True))['provider_details']
assert provider['identifier'] == json_resp[0]['identifier'] assert provider['identifier'] == json_resp[0]['identifier']
def test_get_provider_details_contains_correct_fields(notify_db, notify_db_session, notify_api): def test_get_provider_details_contains_correct_fields(client, notify_db):
with notify_api.test_request_context(): response = client.get(
with notify_api.test_client() as client: '/provider-details',
auth_header = create_authorization_header() headers=[create_authorization_header()]
response = client.get( )
'/provider-details', json_resp = json.loads(response.get_data(as_text=True))['provider_details']
headers=[auth_header] allowed_keys = {
) "id", "display_name", "identifier", "priority", 'notification_type', "active", "version", "updated_at"
json_resp = json.loads(response.get_data(as_text=True))['provider_details'] }
allowed_keys = {"id", "display_name", "identifier", "priority", 'notification_type', "active"} assert allowed_keys == set(json_resp[0].keys())
assert \
allowed_keys == \
set(json_resp[0].keys())
def test_should_be_able_to_update_priority(notify_db, notify_db_session, notify_api): def test_should_be_able_to_update_priority(client, restore_provider_details):
with notify_api.test_request_context(): provider = ProviderDetails.query.first()
with notify_api.test_client() as client:
auth_header = create_authorization_header()
response = client.get(
'/provider-details',
headers=[auth_header]
)
fetch_resp = json.loads(response.get_data(as_text=True))['provider_details']
provider_id = fetch_resp[2]['id'] update_resp = client.post(
'/provider-details/{}'.format(provider.id),
update_resp = client.post( headers=[('Content-Type', 'application/json'), create_authorization_header()],
'/provider-details/{}'.format(provider_id), data=json.dumps({
headers=[('Content-Type', 'application/json'), auth_header], 'priority': 5
data=json.dumps({ })
'priority': 5 )
}) assert update_resp.status_code == 200
) update_json = json.loads(update_resp.get_data(as_text=True))['provider_details']
assert update_resp.status_code == 200 assert update_json['identifier'] == provider.identifier
update_json = json.loads(update_resp.get_data(as_text=True))['provider_details'] assert update_json['priority'] == 5
assert update_json['identifier'] == 'firetext' assert provider.priority == 5
assert update_json['priority'] == 5
update_resp = client.post(
'/provider-details/{}'.format(provider_id),
headers=[('Content-Type', 'application/json'), auth_header],
data=json.dumps({
'priority': 20
})
)
assert update_resp.status_code == 200
def test_should_be_able_to_update_status(notify_db, notify_db_session, notify_api): def test_should_be_able_to_update_status(client, restore_provider_details):
with notify_api.test_request_context(): provider = ProviderDetails.query.first()
with notify_api.test_client() as client:
auth_header = create_authorization_header()
response = client.get(
'/provider-details',
headers=[auth_header]
)
fetch_resp = json.loads(response.get_data(as_text=True))['provider_details']
firetext = next(x for x in fetch_resp if x['identifier'] == 'firetext') update_resp_1 = client.post(
'/provider-details/{}'.format(provider.id),
update_resp_1 = client.post( headers=[('Content-Type', 'application/json'), create_authorization_header()],
'/provider-details/{}'.format(firetext['id']), data=json.dumps({
headers=[('Content-Type', 'application/json'), auth_header], 'active': False
data=json.dumps({ })
'active': False )
}) assert update_resp_1.status_code == 200
) update_resp_1 = json.loads(update_resp_1.get_data(as_text=True))['provider_details']
assert update_resp_1.status_code == 200 assert update_resp_1['identifier'] == provider.identifier
update_resp_1 = json.loads(update_resp_1.get_data(as_text=True))['provider_details'] assert not update_resp_1['active']
assert update_resp_1['identifier'] == 'firetext' assert not provider.active
assert not update_resp_1['active']
update_resp_2 = client.post(
'/provider-details/{}'.format(firetext['id']),
headers=[('Content-Type', 'application/json'), auth_header],
data=json.dumps({
'active': True
})
)
assert update_resp_2.status_code == 200
update_resp_2 = json.loads(update_resp_2.get_data(as_text=True))['provider_details']
assert update_resp_2['identifier'] == 'firetext'
assert update_resp_2['active']
def test_should_not_be_able_to_update_identifier(notify_db, notify_db_session, notify_api): @pytest.mark.parametrize('field,value', [
with notify_api.test_request_context(): ('identifier', 'new'),
with notify_api.test_client() as client: ('version', 7),
auth_header = create_authorization_header() ('updated_at', None)
response = client.get( ])
'/provider-details', def test_should_not_be_able_to_update_disallowed_fields(client, restore_provider_details, field, value):
headers=[auth_header] provider = ProviderDetails.query.first()
)
fetch_resp = json.loads(response.get_data(as_text=True))['provider_details']
provider_id = fetch_resp[2]['id'] update_resp = client.post(
'/provider-details/{}'.format(provider.id),
update_resp = client.post( headers=[('Content-Type', 'application/json'), create_authorization_header()],
'/provider-details/{}'.format(provider_id), data=json.dumps({field: value})
headers=[('Content-Type', 'application/json'), auth_header], )
data=json.dumps({ assert update_resp.status_code == 400
'identifier': "new" update_resp = json.loads(update_resp.get_data(as_text=True))
}) print(update_resp)
) assert update_resp['message'][field][0] == 'Not permitted to be updated'
assert update_resp.status_code == 400 assert update_resp['result'] == 'error'
update_resp = json.loads(update_resp.get_data(as_text=True))
assert update_resp['message']['identifier'][0] == 'Not permitted to be updated'
assert update_resp['result'] == 'error'

View File

@@ -70,7 +70,7 @@ def notify_db_session(notify_db):
notify_db.session.remove() notify_db.session.remove()
for tbl in reversed(notify_db.metadata.sorted_tables): for tbl in reversed(notify_db.metadata.sorted_tables):
if tbl.name not in ["provider_details", "key_types", "branding_type", "job_status"]: if tbl.name not in ["provider_details", "key_types", "branding_type", "job_status", "provider_details_history"]:
notify_db.engine.execute(tbl.delete()) notify_db.engine.execute(tbl.delete())
notify_db.session.commit() notify_db.session.commit()