Moves test database setup/teardown into a fixture

Change-Id: Ic59eb0a6f7d20abfcc2966a7162406cf541306b2
This commit is contained in:
David Stanek 2014-04-07 06:51:19 +00:00
parent 58d71b9ac7
commit 01b0f4cd7d
8 changed files with 131 additions and 66 deletions

View File

@ -45,12 +45,10 @@ from keystone import auth
from keystone.common import dependency
from keystone.common import kvs
from keystone.common.kvs import core as kvs_core
from keystone.common import sql
from keystone.common import utils as common_utils
from keystone import config
from keystone import exception
from keystone import notifications
from keystone.openstack.common.db import options as db_options
from keystone.openstack.common.fixture import config as config_fixture
from keystone.openstack.common.gettextutils import _
from keystone.openstack.common import log
@ -119,19 +117,6 @@ class dirs:
DEFAULT_TEST_DB_FILE = dirs.tmp('test.db')
def _initialize_sql_session():
# Make sure the DB is located in the correct location, in this case set
# the default value, as this should be able to be overridden in some
# test cases.
db_file = DEFAULT_TEST_DB_FILE
db_options.set_defaults(
sql_connection=IN_MEM_DB_CONN_STRING,
sqlite_db=db_file)
_initialize_sql_session()
def checkout_vendor(repo, rev):
# TODO(termie): this function is a good target for some optimizations :PERF
name = repo.split('/')[-1]
@ -459,15 +444,6 @@ class TestCase(BaseTestCase):
setattr(self, manager_name, manager)
self.addCleanup(self.cleanup_instance(*drivers.keys()))
# The credential backend only supports SQL, so we always have to load
# the tables.
self.engine = sql.get_engine()
self.addCleanup(sql.cleanup)
self.addCleanup(self.cleanup_instance('engine'))
sql.ModelBase.metadata.create_all(bind=self.engine)
self.addCleanup(sql.ModelBase.metadata.drop_all, bind=self.engine)
def load_fixtures(self, fixtures):
"""Hacky basic and naive fixture loading based on a python module.

View File

@ -0,0 +1,105 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools
import os
import shutil
import fixtures
from keystone.common import sql
from keystone.common.sql import migration_helpers
from keystone import config
from keystone.openstack.common.db import options as db_options
from keystone.openstack.common.db.sqlalchemy import migration
from keystone import tests
CONF = config.CONF
def run_once(f):
@functools.wraps(f)
def wrapper():
if not wrapper.already_ran:
f()
wrapper.already_ran = True
wrapper.already_ran = False
return wrapper
def _setup_database(extensions=None):
if CONF.database.connection != tests.IN_MEM_DB_CONN_STRING:
db = tests.dirs.tmp('test.db')
pristine = tests.dirs.tmp('test.db.pristine')
if os.path.exists(db):
os.unlink(db)
if not os.path.exists(pristine):
migration.db_sync(sql.get_engine(),
migration_helpers.find_migrate_repo())
for extension in (extensions or []):
migration_helpers.sync_database_to_version(extension=extension)
shutil.copyfile(db, pristine)
else:
shutil.copyfile(pristine, db)
@run_once
def _initialize_sql_session():
# Make sure the DB is located in the correct location, in this case set
# the default value, as this should be able to be overridden in some
# test cases.
db_options.set_defaults(
sql_connection=tests.IN_MEM_DB_CONN_STRING,
sqlite_db=tests.DEFAULT_TEST_DB_FILE)
@run_once
def _load_sqlalchemy_models():
"""Find all modules containing SQLAlchemy models and import them.
This will create more consistent, deterministic test runs because the
database schema will be predictable. The schema is created based on the
models already imported. This can change during the course of a test run.
If all models are imported ahead of time then the schema will always be
the same.
"""
keystone_root = os.path.normpath(os.path.join(
os.path.dirname(__file__), '..', '..'))
for root, dirs, files in os.walk(keystone_root):
if root.endswith('backends') and 'sql.py' in files:
module_name = root.replace(os.sep, '.') + '.sql'
__import__(module_name)
class Database(fixtures.Fixture):
"""A fixture for setting up and tearing down a database.
"""
def __init__(self, extensions=None):
super(Database, self).__init__()
self._extensions = extensions
_initialize_sql_session()
_load_sqlalchemy_models()
def setUp(self):
super(Database, self).setUp()
_setup_database(extensions=self._extensions)
self.engine = sql.get_engine()
sql.ModelBase.metadata.create_all(bind=self.engine)
self.addCleanup(sql.cleanup)
self.addCleanup(sql.ModelBase.metadata.drop_all, bind=self.engine)

View File

@ -27,6 +27,7 @@ from keystone import exception
from keystone.openstack.common import timeutils
from keystone import tests
from keystone.tests import default_fixtures
from keystone.tests.ksfixtures import database
from keystone import token
from keystone import trust
@ -68,6 +69,7 @@ def _build_user_auth(token=None, user_id=None, username=None,
class AuthTest(tests.TestCase):
def setUp(self):
self.useFixture(database.Database())
super(AuthTest, self).setUp()
self.load_backends()

View File

@ -20,11 +20,16 @@ from keystone import exception
from keystone.openstack.common import timeutils
from keystone import tests
from keystone.tests import default_fixtures
from keystone.tests.ksfixtures import database
from keystone.tests import test_backend
class KvsIdentity(tests.TestCase, test_backend.IdentityTests):
def setUp(self):
# NOTE(dstanek): setup the database for subsystems that do not have a
# KVS backend (like credentials)
self.useFixture(database.Database())
super(KvsIdentity, self).setUp()
self.load_backends()
self.load_fixtures(default_fixtures)

View File

@ -32,6 +32,7 @@ from keystone import identity
from keystone import tests
from keystone.tests import default_fixtures
from keystone.tests import fakeldap
from keystone.tests.ksfixtures import database
from keystone.tests import test_backend
@ -592,6 +593,14 @@ class BaseLDAPIdentity(test_backend.IdentityTests):
class LDAPIdentity(BaseLDAPIdentity, tests.TestCase):
def setUp(self):
# NOTE(dstanek): The database must be setup prior to calling the
# parent's setUp. The parent's setUp uses services (like
# credentials) that require a database.
self.useFixture(database.Database())
super(LDAPIdentity, self).setUp()
def test_configurable_allowed_project_actions(self):
tenant = {'id': u'fäké1', 'name': u'fäké1', 'enabled': True}
self.assignment_api.create_project(u'fäké1', tenant)
@ -1332,6 +1341,7 @@ class LdapIdentitySqlAssignment(BaseLDAPIdentity, tests.SQLDriverOverrides,
return config_files
def setUp(self):
self.useFixture(database.Database())
super(LdapIdentitySqlAssignment, self).setUp()
self.clear_database()
self.load_backends()
@ -1416,6 +1426,7 @@ class MultiLDAPandSQLIdentity(BaseLDAPIdentity, tests.SQLDriverOverrides,
"""
def setUp(self):
self.useFixture(database.Database())
super(MultiLDAPandSQLIdentity, self).setUp()
self.load_backends()

View File

@ -26,6 +26,7 @@ from keystone.identity.backends import sql as identity_sql
from keystone.openstack.common.db import exception as db_exception
from keystone import tests
from keystone.tests import default_fixtures
from keystone.tests.ksfixtures import database
from keystone.tests import test_backend
from keystone.token.backends import sql as token_sql
@ -38,6 +39,7 @@ class SqlTests(tests.SQLDriverOverrides, tests.TestCase):
def setUp(self):
super(SqlTests, self).setUp()
self.useFixture(database.Database())
self.load_backends()
# populate the engine with tables & fixtures
@ -52,15 +54,10 @@ class SqlTests(tests.SQLDriverOverrides, tests.TestCase):
class SqlModels(SqlTests):
def setUp(self):
super(SqlModels, self).setUp()
self.metadata = sql.ModelBase.metadata
self.metadata.bind = self.engine
def select_table(self, name):
table = sqlalchemy.Table(name,
self.metadata,
sql.ModelBase.metadata,
autoload=True)
s = sqlalchemy.select([table])
return s

View File

@ -25,6 +25,7 @@ from keystone.openstack.common import timeutils
from keystone import tests
from keystone.tests import default_fixtures
from keystone.tests.ksfixtures import appserver
from keystone.tests.ksfixtures import database
CONF = config.CONF
@ -43,6 +44,7 @@ class CompatTestCase(tests.NoModule, tests.TestCase):
# approach is to ensure we have the correct backing store. The
# credential api makes some very SQL specific assumptions that should
# be addressed allowing for non-SQL based testing to occur.
self.useFixture(database.Database())
self.load_backends()
self.load_fixtures(default_fixtures)

View File

@ -13,8 +13,6 @@
# under the License.
import datetime
import os
import shutil
import uuid
from lxml import etree
@ -25,15 +23,13 @@ from keystone import auth
from keystone.common import authorization
from keystone.common import cache
from keystone.common import serializer
from keystone.common import sql
from keystone.common.sql import migration_helpers
from keystone import config
from keystone import exception
from keystone import middleware
from keystone.openstack.common.db.sqlalchemy import migration
from keystone.openstack.common import timeutils
from keystone.policy.backends import rules
from keystone import tests
from keystone.tests.ksfixtures import database
from keystone.tests import rest
@ -43,27 +39,6 @@ DEFAULT_DOMAIN_ID = 'default'
TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
def _setup_database(extensions=None):
if CONF.database.connection != tests.IN_MEM_DB_CONN_STRING:
db = tests.dirs.tmp('test.db')
pristine = tests.dirs.tmp('test.db.pristine')
if os.path.exists(db):
os.unlink(db)
if not os.path.exists(pristine):
migration.db_sync(sql.get_engine(),
migration_helpers.find_migrate_repo())
for extension in (extensions or []):
migration_helpers.sync_database_to_version(extension=extension)
shutil.copyfile(db, pristine)
else:
shutil.copyfile(pristine, db)
def _teardown_database():
sql.cleanup()
class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
def config_files(self):
config_files = super(RestfulTestCase, self).config_files()
@ -76,12 +51,6 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
extensions.add(self.EXTENSION_NAME)
return extensions
def setup_database(self):
_setup_database(self.get_extensions())
def teardown_database(self):
_teardown_database()
def generate_paste_config(self):
new_paste_file = None
try:
@ -108,6 +77,8 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
if new_paste_file:
app_conf = 'config:%s' % (new_paste_file)
self.useFixture(database.Database(self.get_extensions()))
super(RestfulTestCase, self).setUp(app_conf=app_conf)
self.empty_context = {'environment': {}}
@ -115,11 +86,7 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
# drop the policy rules
self.addCleanup(rules.reset)
self.addCleanup(self.teardown_database)
def load_backends(self):
self.setup_database()
# ensure the cache region instance is setup
cache.configure_cache_region(cache.REGION)