Merge "Add test helpers to enginefacade"
This commit is contained in:
commit
8b20916310
@ -287,6 +287,15 @@ class _TransactionFactory(object):
|
||||
else:
|
||||
return self._writer_maker(**kw)
|
||||
|
||||
def _create_factory_copy(self):
|
||||
factory = _TransactionFactory()
|
||||
factory._url_cfg.update(self._url_cfg)
|
||||
factory._engine_cfg.update(self._engine_cfg)
|
||||
factory._maker_cfg.update(self._maker_cfg)
|
||||
factory._transaction_ctx_cfg.update(self._transaction_ctx_cfg)
|
||||
factory._facade_cfg.update(self._facade_cfg)
|
||||
return factory
|
||||
|
||||
def _args_for_conf(self, default_cfg, conf):
|
||||
if conf is None:
|
||||
return dict(
|
||||
@ -308,7 +317,9 @@ class _TransactionFactory(object):
|
||||
return self._args_for_conf(self._engine_cfg, conf)
|
||||
|
||||
def _maker_args_for_conf(self, conf):
|
||||
return self._args_for_conf(self._maker_cfg, conf)
|
||||
maker_args = self._args_for_conf(self._maker_cfg, conf)
|
||||
maker_args['autocommit'] = maker_args.pop('__autocommit')
|
||||
return maker_args
|
||||
|
||||
def dispose_pool(self):
|
||||
"""Call engine.pool.dispose() on underlying Engine objects."""
|
||||
@ -345,7 +356,6 @@ class _TransactionFactory(object):
|
||||
url_args['slave_connection'] = slave_connection
|
||||
engine_args = self._engine_args_for_conf(conf)
|
||||
maker_args = self._maker_args_for_conf(conf)
|
||||
maker_args['autocommit'] = maker_args.pop('__autocommit')
|
||||
|
||||
self._writer_engine, self._writer_maker = \
|
||||
self._setup_for_connection(
|
||||
@ -660,6 +670,81 @@ class _TransactionContextManager(object):
|
||||
"""Call engine.pool.dispose() on underlying Engine objects."""
|
||||
self._factory.dispose_pool()
|
||||
|
||||
def make_new_manager(self):
|
||||
"""Create a new, independent _TransactionContextManager from this one.
|
||||
|
||||
Copies the underlying _TransactionFactory to a new one, so that
|
||||
it can be further configured with new options.
|
||||
|
||||
Used for test environments where the application-wide
|
||||
_TransactionContextManager may be used as a factory for test-local
|
||||
managers.
|
||||
|
||||
"""
|
||||
new = self._clone()
|
||||
new._root = new
|
||||
new._root_factory = self._root_factory._create_factory_copy()
|
||||
assert not new._factory._started
|
||||
return new
|
||||
|
||||
def patch_factory(self, factory_or_manager):
|
||||
"""Patch a _TransactionFactory into this manager.
|
||||
|
||||
Replaces this manager's factory with the given one, and returns
|
||||
a callable that will reset the factory back to what we
|
||||
started with.
|
||||
|
||||
Only works for root factories. Is intended for test suites
|
||||
that need to patch in alternate database configurations.
|
||||
|
||||
The given argument may be a _TransactionContextManager or a
|
||||
_TransactionFactory.
|
||||
|
||||
"""
|
||||
|
||||
if isinstance(factory_or_manager, _TransactionContextManager):
|
||||
factory = factory_or_manager._factory
|
||||
elif isinstance(factory_or_manager, _TransactionFactory):
|
||||
factory = factory_or_manager
|
||||
else:
|
||||
raise ValueError(
|
||||
"_TransactionContextManager or "
|
||||
"_TransactionFactory expected.")
|
||||
assert self._root is self
|
||||
existing_factory = self._root_factory
|
||||
self._root_factory = factory
|
||||
|
||||
def reset():
|
||||
self._root_factory = existing_factory
|
||||
|
||||
return reset
|
||||
|
||||
def patch_engine(self, engine):
|
||||
"""Patch an Engine into this manager.
|
||||
|
||||
Replaces this manager's factory with a _TestTransactionFactory
|
||||
that will use the given Engine, and returns
|
||||
a callable that will reset the factory back to what we
|
||||
started with.
|
||||
|
||||
Only works for root factories. Is intended for test suites
|
||||
that need to patch in alternate database configurations.
|
||||
|
||||
"""
|
||||
|
||||
existing_factory = self._factory
|
||||
maker = existing_factory._writer_maker
|
||||
maker_kwargs = existing_factory._maker_args_for_conf(cfg.CONF)
|
||||
maker = orm.get_maker(engine=engine, **maker_kwargs)
|
||||
|
||||
factory = _TestTransactionFactory(
|
||||
engine, maker,
|
||||
apply_global=False,
|
||||
synchronous_reader=existing_factory.
|
||||
_facade_cfg['synchronous_reader']
|
||||
)
|
||||
return self.patch_factory(factory)
|
||||
|
||||
@property
|
||||
def replace(self):
|
||||
"""Modifier to replace the global transaction factory with this one."""
|
||||
|
@ -1076,6 +1076,154 @@ class MockFacadeTest(oslo_test_base.BaseTestCase):
|
||||
session.execute("test")
|
||||
|
||||
|
||||
class PatchFactoryTest(oslo_test_base.BaseTestCase):
|
||||
|
||||
def test_patch_manager(self):
|
||||
normal_mgr = enginefacade.transaction_context()
|
||||
normal_mgr.configure(connection="sqlite:///foo.db")
|
||||
alt_mgr = enginefacade.transaction_context()
|
||||
alt_mgr.configure(connection="sqlite:///bar.db")
|
||||
|
||||
@normal_mgr.writer
|
||||
def go1(context):
|
||||
s1 = context.session
|
||||
self.assertEqual(
|
||||
s1.bind.url, "sqlite:///foo.db")
|
||||
self.assertIs(
|
||||
s1.bind,
|
||||
normal_mgr._factory._writer_engine)
|
||||
|
||||
@normal_mgr.writer
|
||||
def go2(context):
|
||||
s1 = context.session
|
||||
|
||||
self.assertEqual(
|
||||
s1.bind.url,
|
||||
"sqlite:///bar.db")
|
||||
|
||||
self.assertIs(
|
||||
normal_mgr._factory._writer_engine,
|
||||
alt_mgr._factory._writer_engine
|
||||
)
|
||||
|
||||
def create_engine(sql_connection, **kw):
|
||||
return mock.Mock(url=sql_connection)
|
||||
|
||||
with mock.patch(
|
||||
"oslo_db.sqlalchemy.engines.create_engine", create_engine):
|
||||
context = oslo_context.RequestContext()
|
||||
go1(context)
|
||||
reset = normal_mgr.patch_factory(alt_mgr)
|
||||
go2(context)
|
||||
reset()
|
||||
go1(context)
|
||||
|
||||
def test_patch_factory(self):
|
||||
normal_mgr = enginefacade.transaction_context()
|
||||
normal_mgr.configure(connection="sqlite:///foo.db")
|
||||
alt_mgr = enginefacade.transaction_context()
|
||||
alt_mgr.configure(connection="sqlite:///bar.db")
|
||||
|
||||
@normal_mgr.writer
|
||||
def go1(context):
|
||||
s1 = context.session
|
||||
self.assertEqual(
|
||||
s1.bind.url, "sqlite:///foo.db")
|
||||
self.assertIs(
|
||||
s1.bind,
|
||||
normal_mgr._factory._writer_engine)
|
||||
|
||||
@normal_mgr.writer
|
||||
def go2(context):
|
||||
s1 = context.session
|
||||
|
||||
self.assertEqual(
|
||||
s1.bind.url,
|
||||
"sqlite:///bar.db")
|
||||
|
||||
self.assertIs(
|
||||
normal_mgr._factory._writer_engine,
|
||||
alt_mgr._factory._writer_engine
|
||||
)
|
||||
|
||||
def create_engine(sql_connection, **kw):
|
||||
return mock.Mock(url=sql_connection)
|
||||
|
||||
with mock.patch(
|
||||
"oslo_db.sqlalchemy.engines.create_engine", create_engine):
|
||||
context = oslo_context.RequestContext()
|
||||
go1(context)
|
||||
reset = normal_mgr.patch_factory(alt_mgr._factory)
|
||||
go2(context)
|
||||
reset()
|
||||
go1(context)
|
||||
|
||||
def test_patch_engine(self):
|
||||
normal_mgr = enginefacade.transaction_context()
|
||||
normal_mgr.configure(connection="sqlite:///foo.db")
|
||||
|
||||
@normal_mgr.writer
|
||||
def go1(context):
|
||||
s1 = context.session
|
||||
self.assertEqual(
|
||||
s1.bind.url, "sqlite:///foo.db")
|
||||
self.assertIs(
|
||||
s1.bind,
|
||||
normal_mgr._factory._writer_engine)
|
||||
|
||||
@normal_mgr.writer
|
||||
def go2(context):
|
||||
s1 = context.session
|
||||
|
||||
self.assertEqual(
|
||||
s1.bind.url,
|
||||
"sqlite:///bar.db")
|
||||
|
||||
def create_engine(sql_connection, **kw):
|
||||
return mock.Mock(url=sql_connection)
|
||||
|
||||
with mock.patch(
|
||||
"oslo_db.sqlalchemy.engines.create_engine", create_engine):
|
||||
mock_engine = create_engine("sqlite:///bar.db")
|
||||
|
||||
context = oslo_context.RequestContext()
|
||||
go1(context)
|
||||
reset = normal_mgr.patch_engine(mock_engine)
|
||||
go2(context)
|
||||
self.assertIs(
|
||||
normal_mgr._factory._writer_engine, mock_engine)
|
||||
reset()
|
||||
go1(context)
|
||||
|
||||
def test_new_manager_from_config(self):
|
||||
normal_mgr = enginefacade.transaction_context()
|
||||
normal_mgr.configure(
|
||||
connection="sqlite://",
|
||||
sqlite_fk=True,
|
||||
mysql_sql_mode="FOOBAR",
|
||||
max_overflow=38
|
||||
)
|
||||
|
||||
normal_mgr._factory._start()
|
||||
|
||||
copied_mgr = normal_mgr.make_new_manager()
|
||||
|
||||
self.assertTrue(normal_mgr._factory._started)
|
||||
self.assertIsNotNone(normal_mgr._factory._writer_engine)
|
||||
|
||||
self.assertIsNot(copied_mgr._factory, normal_mgr._factory)
|
||||
self.assertFalse(copied_mgr._factory._started)
|
||||
copied_mgr._factory._start()
|
||||
self.assertIsNot(
|
||||
normal_mgr._factory._writer_engine,
|
||||
copied_mgr._factory._writer_engine)
|
||||
|
||||
engine_args = copied_mgr._factory._engine_args_for_conf(None)
|
||||
self.assertTrue(engine_args['sqlite_fk'])
|
||||
self.assertEqual("FOOBAR", engine_args["mysql_sql_mode"])
|
||||
self.assertEqual(38, engine_args["max_overflow"])
|
||||
|
||||
|
||||
class SynchronousReaderWSlaveMockFacadeTest(MockFacadeTest):
|
||||
synchronous_reader = True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user