Files
notifications-api/tests/conftest.py
T

201 lines
5.9 KiB
Python
Raw Normal View History

import os
2021-03-10 13:55:06 +00:00
from contextlib import contextmanager
2016-02-16 15:25:46 +00:00
2017-08-23 14:46:40 +01:00
import pytest
2017-08-24 13:54:16 +01:00
import sqlalchemy
2021-03-10 13:55:06 +00:00
from alembic.command import upgrade
from alembic.config import Config
2022-10-25 11:53:24 -04:00
from flask import Flask
2016-02-16 15:25:46 +00:00
from app import create_app, db
from app.dao.provider_details_dao import get_provider_details_by_identifier
2015-12-11 16:57:00 +00:00
@pytest.fixture(scope='session')
2022-12-13 08:53:41 -05:00
def notify_app():
2017-11-22 17:54:59 +00:00
app = Flask('test')
create_app(app)
2022-12-13 08:53:41 -05:00
return app
2022-12-13 08:53:41 -05:00
@pytest.fixture(scope='session')
def notify_api(notify_app):
# deattach server-error error handlers - error_handler_spec looks like:
# {'blueprint_name': {
# status_code: [error_handlers],
2017-08-18 15:39:39 +01:00
# None: { ExceptionClass: error_handler }
# }}
2022-12-13 08:53:41 -05:00
for error_handlers in notify_app.error_handler_spec.values():
error_handlers.pop(500, None)
if None in error_handlers:
2017-08-18 15:39:39 +01:00
error_handlers[None] = {
exc_class: error_handler
for exc_class, error_handler in error_handlers[None].items()
if exc_class != Exception
}
if error_handlers[None] == []:
error_handlers.pop(None)
2022-12-13 08:53:41 -05:00
ctx = notify_app.app_context()
2015-12-11 16:57:00 +00:00
ctx.push()
2022-12-13 08:53:41 -05:00
yield notify_app
2015-12-11 16:57:00 +00:00
ctx.pop()
2015-12-11 16:57:00 +00:00
2016-08-30 11:18:30 +01:00
@pytest.fixture(scope='function')
2016-08-30 10:41:23 +01:00
def client(notify_api):
with notify_api.test_request_context(), notify_api.test_client() as client:
yield client
2017-08-23 14:46:40 +01:00
def create_test_db(database_uri):
2017-08-24 13:54:16 +01:00
# get the
db_uri_parts = database_uri.split('/')
postgres_db_uri = '/'.join(db_uri_parts[:-1] + ['postgres'])
2017-08-23 14:46:40 +01:00
2017-08-24 13:54:16 +01:00
postgres_db = sqlalchemy.create_engine(
postgres_db_uri,
echo=False,
isolation_level='AUTOCOMMIT',
client_encoding='utf8'
)
2017-08-23 14:46:40 +01:00
try:
2017-08-24 13:54:16 +01:00
result = postgres_db.execute(sqlalchemy.sql.text('CREATE DATABASE {}'.format(db_uri_parts[-1])))
result.close()
except sqlalchemy.exc.ProgrammingError:
# database "test_notification_api_master" already exists
2017-08-23 14:46:40 +01:00
pass
finally:
2017-08-24 13:54:16 +01:00
postgres_db.dispose()
2017-08-23 14:46:40 +01:00
@pytest.fixture(scope='session')
2022-05-03 17:13:03 +01:00
def _notify_db(notify_api, worker_id):
"""
Manages the connection to the database. Generally this shouldn't be used, instead you should use the
`notify_db_session` fixture which also cleans up any data you've got left over after your test run.
"""
2017-08-23 14:46:40 +01:00
assert 'test_notification_api' in db.engine.url.database, 'dont run tests against main db'
# create a database for this worker thread -
from flask import current_app
current_app.config['SQLALCHEMY_DATABASE_URI'] += '_{}'.format(worker_id)
create_test_db(current_app.config['SQLALCHEMY_DATABASE_URI'])
2016-04-08 16:13:10 +01:00
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
ALEMBIC_CONFIG = os.path.join(BASE_DIR, 'migrations')
config = Config(ALEMBIC_CONFIG + '/alembic.ini')
config.set_main_option("script_location", ALEMBIC_CONFIG)
2016-04-08 16:13:10 +01:00
with notify_api.app_context():
upgrade(config, 'head')
yield db
db.session.remove()
db.get_engine(notify_api).dispose()
@pytest.fixture(scope='function')
2022-05-03 17:13:03 +01:00
def sms_providers(_notify_db):
"""
In production we randomly choose which provider to use based on their priority. To guarantee tests run the same each
2022-12-19 10:48:53 -05:00
time, make sure we always choose sns. You'll need to override them in your tests if you wish to do something
different.
"""
2022-12-19 10:48:53 -05:00
get_provider_details_by_identifier('sns').priority = 100
@pytest.fixture(scope='function')
2022-05-03 17:13:03 +01:00
def notify_db_session(_notify_db, sms_providers):
"""
This fixture clears down all non static data after your test run. It yields the sqlalchemy session variable
so you can manually add, commit, etc if needed.
`notify_db_session.commit()`
"""
2022-05-03 17:13:03 +01:00
yield _notify_db.session
2022-05-03 17:13:03 +01:00
_notify_db.session.remove()
for tbl in reversed(_notify_db.metadata.sorted_tables):
if tbl.name not in ["provider_details",
"key_types",
"branding_type",
"job_status",
"provider_details_history",
"template_process_type",
"notifications_all_time_view",
"notification_status_types",
"organisation_types",
"service_permission_types",
"auth_type",
2018-07-10 11:31:18 +01:00
"invite_status_type",
"service_callback_type"]:
2022-05-03 17:13:03 +01:00
_notify_db.engine.execute(tbl.delete())
_notify_db.session.commit()
2016-12-08 12:12:45 +00:00
@pytest.fixture
def os_environ():
"""
clear os.environ, and restore it after the test runs
"""
# for use whenever you expect code to edit environment variables
old_env = os.environ.copy()
os.environ.clear()
2020-01-06 17:07:06 +00:00
2016-12-08 12:12:45 +00:00
yield
2020-01-06 17:07:06 +00:00
# clear afterwards in case anything extra was added to the environment during the test
os.environ.clear()
for k, v in old_env.items():
os.environ[k] = v
2016-07-18 12:02:27 +01:00
def pytest_generate_tests(metafunc):
# Copied from https://gist.github.com/pfctdayelise/5719730
2018-10-26 17:54:53 +01:00
idparametrize = metafunc.definition.get_closest_marker('idparametrize')
2016-07-18 12:02:27 +01:00
if idparametrize:
argnames, testdata = idparametrize.args
ids, argvalues = zip(*sorted(testdata.items()))
metafunc.parametrize(argnames, argvalues, ids=ids)
2016-09-21 17:13:26 +01:00
@contextmanager
def set_config(app, name, value):
old_val = app.config.get(name)
app.config[name] = value
2018-03-27 17:41:05 +01:00
try:
yield
finally:
app.config[name] = old_val
@contextmanager
def set_config_values(app, dict):
old_values = {}
for key in dict:
old_values[key] = app.config.get(key)
app.config[key] = dict[key]
2018-03-27 17:41:05 +01:00
try:
yield
finally:
for key in dict:
app.config[key] = old_values[key]
class Matcher:
def __init__(self, description, key):
self.description = description
self.key = key
def __eq__(self, other):
return self.key(other)
def __repr__(self):
return '<Matcher: {}>'.format(self.description)