diff options
author | Eric Fried <efried@us.ibm.com> | 2018-08-21 08:00:54 -0500 |
---|---|---|
committer | Eric Fried <efried@us.ibm.com> | 2018-08-28 12:55:33 +0000 |
commit | 63d7649ed5e0252cbaf6bc1f0a02542f458b221f (patch) | |
tree | 5707d79b0087b66b48a47fe061fc9c0d4a63086c | |
parent | e49586e458ca4b673a9f2abbd317c39436bf8d95 (diff) | |
download | oslo-utils-63d7649ed5e0252cbaf6bc1f0a02542f458b221f.tar.gz |
UUID sentinel
Add a private _UUIDSentinels() class to oslo_utils.fixture that behaves
like a mock.sentinel, but returns specifically UUIDs. Expose a
(singleton) instance of it called uuidsentinel. This is mostly copied
from [1], with the following differences:
- We don't do the enforced-singleton thing [2]. But importing the
uuidsentinel global yields the same behavior.
- We don't do the local import thing [3][4], because we're already in
the right lib, so no issues with circular imports.
- Locking is added to make this threadsafe. (See discussion at [5])
Note that there is some question as to whether it is more appropriate
for this to live here or in oslotest [6]. This has been discussed on the
dev ML [7] and it was concluded [8] that it should live here.
[1] https://github.com/openstack/nova/blob/722d5b477219f0a2435a9f4ad4d54c61b83219f1/nova/tests/uuidsentinel.py
[2] https://github.com/openstack/nova/blob/722d5b477219f0a2435a9f4ad4d54c61b83219f1/nova/tests/uuidsentinel.py#L30
[3] https://github.com/openstack/nova/blob/722d5b477219f0a2435a9f4ad4d54c61b83219f1/nova/tests/uuidsentinel.py#L18-L19
[4] https://github.com/openstack/nova/blob/722d5b477219f0a2435a9f4ad4d54c61b83219f1/nova/tests/uuidsentinel.py#L26
[5] http://eavesdrop.openstack.org/irclogs/%23openstack-oslo/%23openstack-oslo.2018-08-20.log.html#t2018-08-20T20:10:33
[6] https://review.openstack.org/#/c/594068/
[7] http://lists.openstack.org/pipermail/openstack-dev/2018-August/133670.html
[8] http://lists.openstack.org/pipermail/openstack-dev/2018-August/133861.html
Change-Id: I214ff21b461fa1ca4b83476e1d0a763efe986217
-rw-r--r-- | oslo_utils/fixture.py | 41 | ||||
-rw-r--r-- | oslo_utils/tests/test_fixture.py | 21 |
2 files changed, 62 insertions, 0 deletions
diff --git a/oslo_utils/fixture.py b/oslo_utils/fixture.py index 9526154..1872c70 100644 --- a/oslo_utils/fixture.py +++ b/oslo_utils/fixture.py @@ -20,9 +20,12 @@ Test fixtures. .. versionadded:: 1.3 """ +import threading + import fixtures from oslo_utils import timeutils +from oslo_utils import uuidutils class TimeFixture(fixtures.Fixture): @@ -49,3 +52,41 @@ class TimeFixture(fixtures.Fixture): def advance_time_seconds(self, seconds): """Advance overridden time by seconds.""" timeutils.advance_time_seconds(seconds) + + +class _UUIDSentinels(object): + """Registry of dynamically created, named, random UUID strings. + + An instance of this class will dynamically generate attributes as they are + referenced, associating a random UUID string with each. Thereafter, + referring to the same attribute will give the same UUID for the life of the + instance. Plan accordingly. + + Usage: + + from oslo_utils.fixture import uuidsentinel as uuids + ... + foo = uuids.foo + do_a_thing(foo) + # Referencing the same sentinel again gives the same value + assert foo == uuids.foo + # But a different one will be different + assert foo != uuids.bar + """ + def __init__(self): + self._sentinels = {} + self._lock = threading.Lock() + + def __getattr__(self, name): + if name.startswith('_'): + raise ValueError('Sentinels must not start with _') + with self._lock: + if name not in self._sentinels: + self._sentinels[name] = uuidutils.generate_uuid() + return self._sentinels[name] + + +# Singleton sentinel instance. Caveat emptor: using this multiple times in the +# same process (including across multiple modules) will result in the same +# values +uuidsentinel = _UUIDSentinels() diff --git a/oslo_utils/tests/test_fixture.py b/oslo_utils/tests/test_fixture.py index 3e0898a..dafac2f 100644 --- a/oslo_utils/tests/test_fixture.py +++ b/oslo_utils/tests/test_fixture.py @@ -17,9 +17,12 @@ import datetime from oslotest import base as test_base +import six from oslo_utils import fixture +from oslo_utils.fixture import uuidsentinel as uuids from oslo_utils import timeutils +from oslo_utils import uuidutils class TimeFixtureTest(test_base.BaseTestCase): @@ -61,3 +64,21 @@ class TimeFixtureTest(test_base.BaseTestCase): time_fixture.advance_time_seconds(2) expected_time = datetime.datetime(2015, 1, 2, 3, 4, 8, 7) self.assertEqual(expected_time, timeutils.utcnow()) + + +class UUIDSentinelsTest(test_base.BaseTestCase): + + def test_different_sentinel(self): + uuid1 = uuids.foobar + uuid2 = uuids.barfoo + self.assertNotEqual(uuid1, uuid2) + + def test_returns_uuid(self): + self.assertTrue(uuidutils.is_uuid_like(uuids.foo)) + + def test_returns_string(self): + self.assertIsInstance(uuids.foo, str) + + def test_with_underline_prefix(self): + ex = self.assertRaises(ValueError, getattr, uuids, '_foo') + self.assertIn("Sentinels must not start with _", six.text_type(ex)) |