update db fixtures for consumption testing

Today neutron-lib has a SqlFixture that's public, but not used by
anyone else. However, this fixture doesn't contain the same
functionality as the fixture in neutron; so neutron breaks when
using it as-is today.

This patch preps for consumption of the SqlFixture(s) by:
- Moving a few more of SqlFixtures from neutron into lib; these are used
by consumers today.
- Updates the existing SqlFixture to include some functionality that
neutron requires.
- Makes all these SqlFixtures private. This is temporary so that we can
have a little time to test them in neutron and other's gates while
making sure no one uses them from lib. Once we are done testing we
will update them again in lib to be public and consume them. At that
point some UTs can also be added with a release note.

Neutron sample consumption patch:
https://review.openstack.org/#/c/651907/

Change-Id: Iaefc83d852a8dca48569e543f535f7c49f5ad0db
This commit is contained in:
Boden R 2019-04-12 13:35:26 -06:00
parent 62282508fd
commit c58df6994f
3 changed files with 93 additions and 13 deletions

View File

@ -16,6 +16,9 @@ import warnings
import fixtures
import mock
from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import provision
from oslo_db.sqlalchemy import session
from oslo_messaging import conffixture
from neutron_lib.api import attributes
@ -83,25 +86,100 @@ class CallbackRegistryFixture(fixtures.Fixture):
self.patcher.stop()
class SqlFixture(fixtures.Fixture):
class _EnableSQLiteFKsFixture(fixtures.Fixture):
"""Turn SQLite PRAGMA foreign keys on and off for tests.
FIXME(zzzeek): figure out some way to get oslo.db test_base to honor
oslo_db.engines.create_engine() arguments like sqlite_fks as well
as handling that it needs to be turned off during drops.
"""
def __init__(self, engine):
self.engine = engine
def _setUp(self):
if self.engine.name == 'sqlite':
self.engine.execute("PRAGMA foreign_keys=ON")
def disable_fks():
with self.engine.connect() as conn:
conn.connection.rollback()
conn.execute("PRAGMA foreign_keys=OFF")
self.addCleanup(disable_fks)
class _SqlFixture(fixtures.Fixture):
# flag to indicate that the models have been loaded
_TABLES_ESTABLISHED = False
def _setUp(self):
def _init_resources(self):
pass
@classmethod
def generate_schema(cls, engine):
# Register all data models
engine = db_api.get_context_manager().writer.get_engine()
if not SqlFixture._TABLES_ESTABLISHED:
if not _SqlFixture._TABLES_ESTABLISHED:
model_base.BASEV2.metadata.create_all(engine)
SqlFixture._TABLES_ESTABLISHED = True
_SqlFixture._TABLES_ESTABLISHED = True
def clear_tables():
with engine.begin() as conn:
for table in reversed(
model_base.BASEV2.metadata.sorted_tables):
conn.execute(table.delete())
def delete_from_schema(self, engine):
with engine.begin() as conn:
for table in reversed(
model_base.BASEV2.metadata.sorted_tables):
conn.execute(table.delete())
self.addCleanup(clear_tables)
def _setUp(self):
self.engine = db_api.CONTEXT_WRITER.get_engine()
self.generate_schema(self.engine)
self._init_resources()
self.sessionmaker = session.get_maker(self.engine)
_restore_factory = db_api.get_context_manager()._root_factory
self.enginefacade_factory = enginefacade._TestTransactionFactory(
self.engine, self.sessionmaker, from_factory=_restore_factory,
apply_global=False)
db_api.get_context_manager()._root_factory = self.enginefacade_factory
self.addCleanup(lambda: self.delete_from_schema(self.engine))
self.addCleanup(
lambda: setattr(
db_api.get_context_manager(),
"_root_factory", _restore_factory))
self.useFixture(_EnableSQLiteFKsFixture(self.engine))
class _StaticSqlFixture(_SqlFixture):
"""Fixture which keeps a single sqlite memory database at global scope."""
_GLOBAL_RESOURCES = False
@classmethod
def _init_resources(cls):
# this is a classlevel version of what testresources
# does w/ the resources attribute as well as the
# setUpResources() step (which requires a test instance, that
# SqlFixture does not have). Because this is a SQLite memory
# database, we don't actually tear it down, so we can keep
# it running throughout all tests.
if cls._GLOBAL_RESOURCES:
return
else:
cls._GLOBAL_RESOURCES = True
cls.schema_resource = provision.SchemaResource(
provision.DatabaseResource(
"sqlite", db_api.get_context_manager()),
cls.generate_schema, teardown=False)
dependency_resources = {}
for name, resource in cls.schema_resource.resources:
dependency_resources[name] = resource.getResource()
cls.schema_resource.make(dependency_resources)
cls.engine = dependency_resources['database'].engine
class APIDefinitionFixture(fixtures.Fixture):

View File

@ -23,4 +23,4 @@ class SqlTestCase(base.BaseTestCase):
def setUp(self):
super(SqlTestCase, self).setUp()
self.useFixture(fixture.SqlFixture())
self.useFixture(fixture._SqlFixture())

View File

@ -61,10 +61,12 @@ class SqlFixtureTestCase(base.BaseTestCase):
options.set_defaults(
cfg.CONF,
connection='sqlite://')
self.useFixture(fixture.SqlFixture())
self.fixture = fixture._SqlFixture()
self.useFixture(self.fixture)
def test_fixture(self):
self.assertIsNotNone(model_base.BASEV2.metadata.sorted_tables)
self.assertIsNotNone(self.fixture.engine)
class APIDefinitionFixtureTestCase(base.BaseTestCase):