From 54c84da50a7dcda327c01047846294c77516ca38 Mon Sep 17 00:00:00 2001 From: Ben Nemec Date: Tue, 28 Oct 2014 17:43:30 +0000 Subject: [PATCH] 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 --- oslo_concurrency/fixture/lockutils.py | 25 +++++++++++++++++++++++++ tests/test_lockutils.py | 24 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/oslo_concurrency/fixture/lockutils.py b/oslo_concurrency/fixture/lockutils.py index 01cec72..9639e40 100644 --- a/oslo_concurrency/fixture/lockutils.py +++ b/oslo_concurrency/fixture/lockutils.py @@ -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') diff --git a/tests/test_lockutils.py b/tests/test_lockutils.py index 0bde4a8..1788be2 100644 --- a/tests/test_lockutils.py +++ b/tests/test_lockutils.py @@ -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'))