Change fulldbtests to use py.test

This commit is contained in:
Joseph Schorr 2017-04-24 15:52:50 -04:00
parent 6ba7ed4cd6
commit a1a4b68306
3 changed files with 79 additions and 15 deletions

View file

@ -20,7 +20,7 @@ from data.database import (db, all_models, beta_classes, Role, TeamRole, Visibil
ExternalNotificationEvent, ExternalNotificationMethod, NotificationKind,
QuayRegion, QuayService, UserRegion, OAuthAuthorizationCode,
ServiceKeyApprovalType, MediaType, LabelSourceType, UserPromptKind,
RepositoryKind, TagKind, BlobPlacementLocation)
RepositoryKind, TagKind, BlobPlacementLocation, User)
from data import model
from data.queue import WorkQueue
from app import app, storage as store, tf
@ -440,6 +440,15 @@ def wipe_database():
def populate_database(minimal=False, with_storage=False):
logger.debug('Populating the DB with test data.')
# Check if the data already exists. If so, we skip. This can happen between calls from the
# "old style" tests and the new py.test's.
try:
User.get(username='devtable')
logger.debug('DB already populated')
return
except User.DoesNotExist:
pass
# Note: databases set up with "real" schema (via Alembic) will not have these types
# type, so we it here it necessary.
try:

View file

@ -1,10 +1,12 @@
import os
from cachetools import lru_cache
import pytest
import shutil
from flask import Flask, jsonify
from flask_login import LoginManager
from peewee import SqliteDatabase
from peewee import SqliteDatabase, savepoint, InternalError
from app import app as application
from data import model
@ -14,30 +16,56 @@ 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")
@lru_cache(maxsize=1) # Important! pytest is calling this multiple times (despite it being 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)
if os.environ.get('TEST_DATABASE_URI'):
return _init_db_path_real_db(os.environ.get('TEST_DATABASE_URI'))
return _init_db_path_sqlite(tmpdir_factory)
def _init_db_path_real_db(db_uri):
""" Initializes a real database for testing by populating it from scratch. Note that this does
*not* add the tables (merely data). Callers must have migrated the database before calling
the test suite.
"""
configure({
"DB_URI": db_uri,
"DB_CONNECTION_ARGS": {
'threadlocals': True,
'autorollback': True,
},
"DB_TRANSACTION_FACTORY": _create_transaction,
})
populate_database()
return db_uri
def _init_db_path_sqlite(tmpdir_factory):
""" Initializes a SQLite database for testing by populating it from scratch and placing it into
a temp directory file.
"""
sqlitedbfile = str(tmpdir_factory.mktemp("data").join("test.db"))
sqlitedb = 'sqlite:///{0}'.format(sqlitedbfile)
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))
db.initialize(SqliteDatabase(sqlitedbfile))
application.config.update(conf)
application.config.update({"DB_URI": sqlitedb})
initialize_database()
populate_database()
close_db_filter(None)
return str(sqlitedb_file)
return str(sqlitedbfile)
@pytest.fixture()
@ -47,6 +75,11 @@ def database_uri(monkeypatch, init_db_path, sqlitedb_file):
on a per-test basis. In the non-SQLite case, a reference to the existing database URI is
returned.
"""
if os.environ.get('TEST_DATABASE_URI'):
db_uri = os.environ['TEST_DATABASE_URI']
monkeypatch.setenv("DB_URI", db_uri)
return db_uri
# Copy the golden database file to a new path.
shutil.copy2(init_db_path, sqlitedb_file)
@ -84,8 +117,28 @@ def appconfig(database_uri):
@pytest.fixture()
def initialized_db(appconfig):
""" Configures the database for the database found in the appconfig. """
# Configure the database.
configure(appconfig)
# If under a test *real* database, setup a savepoint.
under_test_real_database = bool(os.environ.get('TEST_DATABASE_URI'))
if under_test_real_database:
test_savepoint = savepoint(db)
test_savepoint.__enter__()
yield # Run the test.
try:
test_savepoint.__exit__(None, None, None)
except InternalError:
# If postgres fails with an exception (like IntegrityError) mid-transaction, it terminates
# it immediately, so when we go to remove the savepoint, it complains. We can safely ignore
# this case.
pass
else:
yield
@pytest.fixture()
def app(appconfig, initialized_db):
""" Used by pytest-flask plugin to inject a custom app instance for testing. """

View file

@ -13,8 +13,8 @@ up_mysql() {
}
down_mysql() {
docker kill mysql
docker rm -v mysql
docker kill mysql || true
docker rm -v mysql || true
}
up_postgres() {
@ -30,8 +30,8 @@ up_postgres() {
}
down_postgres() {
docker kill postgres
docker rm -v postgres
docker kill postgres || true
docker rm -v postgres || true
}
run_tests() {
@ -39,7 +39,7 @@ run_tests() {
PYTHONPATH=. TEST_DATABASE_URI=$1 TEST=true alembic upgrade head
# Run the full test suite.
SKIP_DB_SCHEMA=true TEST_DATABASE_URI=$1 TEST=true python -m unittest discover -f
PYTHONPATH=. SKIP_DB_SCHEMA=true TEST_DATABASE_URI=$1 TEST=true py.test ${2:-.} --ignore=endpoints/appr/test/
}
CIP=${CONTAINERIP-'127.0.0.1'}
@ -48,20 +48,22 @@ echo "> Using container IP address $CIP"
# NOTE: MySQL is currently broken on setup.
# Test (and generate, if requested) via MySQL.
echo '> Starting MySQL'
down_mysql
up_mysql
echo '> Running Full Test Suite (mysql)'
set +e
run_tests "mysql+pymysql://root:password@$CIP/genschema"
run_tests "mysql+pymysql://root:password@$CIP/genschema" $1
set -e
down_mysql
# Test via Postgres.
echo '> Starting Postgres'
down_postgres
up_postgres
echo '> Running Full Test Suite (postgres)'
set +e
run_tests "postgresql://postgres@$CIP/genschema"
run_tests "postgresql://postgres@$CIP/genschema" $1
set -e
down_postgres