import os import pytest import shutil from flask import Flask, jsonify from flask_login import LoginManager from peewee import SqliteDatabase from app import app as application from data import model from data.database import close_db_filter, db, configure from data.model.user import LoginWrappedDBUser from endpoints.api import api_bp from endpoints.web import web from initdb import initialize_database, populate_database from path_converters import APIRepositoryPathConverter, RegexConverter, RepositoryPathConverter from test.testconfig import FakeTransaction @pytest.fixture(scope="session") def init_db_path(tmpdir_factory): """ Creates a new database and appropriate configuration. Note that the initial database is created *once* per session. In the non-full-db-test case, the database_uri fixture makes a copy of the SQLite database file on disk and passes a new copy to each test. """ sqlitedb_file = str(tmpdir_factory.mktemp("data").join("test.db")) sqlitedb = 'sqlite:///{0}'.format(sqlitedb_file) conf = {"TESTING": True, "DEBUG": True, "DB_URI": sqlitedb} os.environ['TEST_DATABASE_URI'] = str(sqlitedb) os.environ['DB_URI'] = str(sqlitedb) db.initialize(SqliteDatabase(sqlitedb_file)) application.config.update(conf) application.config.update({"DB_URI": sqlitedb}) initialize_database() populate_database() close_db_filter(None) return str(sqlitedb_file) @pytest.fixture() def database_uri(monkeypatch, init_db_path, sqlitedb_file): """ Returns the database URI to use for testing. In the SQLite case, a new, distinct copy of the SQLite database is created by copying the initialized database file (sqlitedb_file) on a per-test basis. In the non-SQLite case, a reference to the existing database URI is returned. """ # Copy the golden database file to a new path. shutil.copy2(init_db_path, sqlitedb_file) # Monkeypatch the DB_URI. db_path = 'sqlite:///{0}'.format(sqlitedb_file) monkeypatch.setenv("DB_URI", db_path) return db_path @pytest.fixture() def sqlitedb_file(tmpdir): """ Returns the path at which the initialized, golden SQLite database file will be placed. """ test_db_file = tmpdir.mkdir("quaydb").join("test.db") return str(test_db_file) def _create_transaction(db): return FakeTransaction() @pytest.fixture() def appconfig(database_uri): """ Returns application configuration for testing that references the proper database URI. """ conf = { "TESTING": True, "DEBUG": True, "DB_URI": database_uri, "SECRET_KEY": 'superdupersecret!!!1', "DB_CONNECTION_ARGS": { 'threadlocals': True, 'autorollback': True, }, "DB_TRANSACTION_FACTORY": _create_transaction, } return conf @pytest.fixture() def initialized_db(appconfig): """ Configures the database for the database found in the appconfig. """ configure(appconfig) @pytest.fixture() def app(appconfig, initialized_db): """ Used by pytest-flask plugin to inject a custom app instance for testing. """ app = Flask(__name__) login_manager = LoginManager(app) @app.errorhandler(model.DataModelException) def handle_dme(ex): response = jsonify({'message': ex.message}) response.status_code = 400 return response @login_manager.user_loader def load_user(user_uuid): return LoginWrappedDBUser(user_uuid) app.url_map.converters['regex'] = RegexConverter app.url_map.converters['apirepopath'] = APIRepositoryPathConverter app.url_map.converters['repopath'] = RepositoryPathConverter app.register_blueprint(api_bp, url_prefix='/api') app.register_blueprint(web, url_prefix='/') app.config.update(appconfig) return app