Add external lock fixture

This was requested by consumers of the library so they don't have
to enable external locks globally with the OSLO_LOCK_PATH env var,
which can mask bugs in unit tests that have interdependencies
because it makes every lock in any unit test shared.  The new
fixture allows a separate lock directory to be created for each
test, and allows external locking to only be enabled for tests
that need it.

Change-Id: Iae7ce302e1a3a5ad90ca5310f5ac7a6164867637
This commit is contained in:
Ben Nemec 2014-10-28 17:43:30 +00:00
parent 19f07c600c
commit 54c84da50a
2 changed files with 49 additions and 0 deletions

View File

@ -14,6 +14,7 @@
# under the License.
import fixtures
from oslo.config import fixture as config
from oslo_concurrency import lockutils
@ -49,3 +50,27 @@ class LockFixture(fixtures.Fixture):
super(LockFixture, self).setUp()
self.addCleanup(self.mgr.__exit__, None, None, None)
self.lock = self.mgr.__enter__()
class ExternalLockFixture(fixtures.Fixture):
"""Configure lock_path so external locks can be used in unit tests.
Creates a temporary directory to hold file locks and sets the oslo.config
lock_path opt to use it. This can be used to enable external locking
on a per-test basis, rather than globally with the OSLO_LOCK_PATH
environment variable.
Example::
def test_method(self):
self.useFixture(ExternalLockFixture())
something_that_needs_external_locks()
Alternatively, the useFixture call could be placed in a test class's
setUp method to provide this functionality to all tests in the class.
"""
def setUp(self):
super(ExternalLockFixture, self).setUp()
temp_dir = self.useFixture(fixtures.TempDir())
conf = self.useFixture(config.Config(lockutils.CONF)).config
conf(lock_path=temp_dir.path, group='oslo_concurrency')

View File

@ -549,3 +549,27 @@ class TestLockFixture(test_base.BaseTestCase):
fixture = fixtures.LockFixture('test-lock')
self.useFixture(fixture)
self.lock = fixture.lock
class TestExternalLockFixture(test_base.BaseTestCase):
def test_fixture(self):
# NOTE(bnemec): This test case is only valid if lockutils-wrapper is
# _not_ in use. Otherwise lock_path will be set on lockutils import
# and this test will pass regardless of whether the fixture is used.
self.useFixture(fixtures.ExternalLockFixture())
# This will raise an exception if lock_path is not set
with lockutils.external_lock('foo'):
pass
def test_with_existing_config_fixture(self):
# Make sure the config fixture in the ExternalLockFixture doesn't
# cause any issues for tests using their own config fixture.
conf = self.useFixture(config.Config())
self.useFixture(fixtures.ExternalLockFixture())
with lockutils.external_lock('bar'):
conf.register_opt(cfg.StrOpt('foo'))
conf.config(foo='bar')
self.assertEqual(cfg.CONF.foo, 'bar')
# Due to config filter, lock_path should still not be present in
# the global config opt.
self.assertFalse(hasattr(cfg.CONF, 'lock_path'))