diff options
author | Michael Still <mikal@stillhq.com> | 2012-10-10 17:28:11 +1100 |
---|---|---|
committer | Michael Still <mikal@stillhq.com> | 2012-10-18 09:09:17 -0700 |
commit | 9a8c1d7e1a537e6580be2be1630baefc910de1de (patch) | |
tree | fe6c40b44c3b9d5b1dcaefc4945bc98e01956698 /tests | |
parent | 7695f967a3c750642504aa60f748111f64880a07 (diff) | |
download | oslo-9a8c1d7e1a537e6580be2be1630baefc910de1de.tar.gz oslo-9a8c1d7e1a537e6580be2be1630baefc910de1de.tar.xz oslo-9a8c1d7e1a537e6580be2be1630baefc910de1de.zip |
Move nova's util.synchronized decorator to openstack common.
In the end I needed to port utils.ensure_tree as well. Resolves
bug 1063230.
Change-Id: I6e6fa8201de2cac3f17e6c60d7b16f7df7c64116
Diffstat (limited to 'tests')
-rw-r--r-- | tests/unit/test_fileutils.py | 37 | ||||
-rw-r--r-- | tests/unit/test_lockutils.py | 165 |
2 files changed, 202 insertions, 0 deletions
diff --git a/tests/unit/test_fileutils.py b/tests/unit/test_fileutils.py new file mode 100644 index 0000000..de5719e --- /dev/null +++ b/tests/unit/test_fileutils.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import os +import shutil +import tempfile + +from openstack.common import fileutils + + +class EnsureTree(unittest.TestCase): + def test_ensure_tree(self): + tmpdir = tempfile.mkdtemp() + try: + testdir = '%s/foo/bar/baz' % (tmpdir,) + fileutils.ensure_tree(testdir) + self.assertTrue(os.path.isdir(testdir)) + + finally: + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir) diff --git a/tests/unit/test_lockutils.py b/tests/unit/test_lockutils.py new file mode 100644 index 0000000..5f50217 --- /dev/null +++ b/tests/unit/test_lockutils.py @@ -0,0 +1,165 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Justin Santa Barbara +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import errno +import os +import select +import shutil +import tempfile +import time +import unittest + +import eventlet +from eventlet import greenthread +from eventlet import greenpool + +from openstack.common import lockutils +from tests import utils as test_utils + + +class TestFileLocks(test_utils.BaseTestCase): + def test_concurrent_green_lock_succeeds(self): + """Verify spawn_n greenthreads with two locks run concurrently.""" + tmpdir = tempfile.mkdtemp() + try: + self.completed = False + + def locka(wait): + a = lockutils.InterProcessLock(os.path.join(tmpdir, 'a')) + with a: + wait.wait() + self.completed = True + + def lockb(wait): + b = lockutils.InterProcessLock(os.path.join(tmpdir, 'b')) + with b: + wait.wait() + + wait1 = eventlet.event.Event() + wait2 = eventlet.event.Event() + pool = greenpool.GreenPool() + pool.spawn_n(locka, wait1) + pool.spawn_n(lockb, wait2) + wait2.send() + eventlet.sleep(0) + wait1.send() + pool.waitall() + + self.assertTrue(self.completed) + + finally: + if os.path.exists(tmpdir): + shutil.rmtree(tmpdir) + + +class LockTestCase(test_utils.BaseTestCase): + def test_synchronized_wrapped_function_metadata(self): + @lockutils.synchronized('whatever', 'test-') + def foo(): + """Bar""" + pass + + self.assertEquals(foo.__doc__, 'Bar', "Wrapped function's docstring " + "got lost") + self.assertEquals(foo.__name__, 'foo', "Wrapped function's name " + "got mangled") + + def test_synchronized_internally(self): + """We can lock across multiple green threads""" + saved_sem_num = len(lockutils._semaphores) + seen_threads = list() + + @lockutils.synchronized('testlock2', 'test-', external=False) + def f(id): + for x in range(10): + seen_threads.append(id) + greenthread.sleep(0) + + threads = [] + pool = greenpool.GreenPool(10) + for i in range(10): + threads.append(pool.spawn(f, i)) + + for thread in threads: + thread.wait() + + self.assertEquals(len(seen_threads), 100) + # Looking at the seen threads, split it into chunks of 10, and verify + # that the last 9 match the first in each chunk. + for i in range(10): + for j in range(9): + self.assertEquals(seen_threads[i * 10], + seen_threads[i * 10 + 1 + j]) + + self.assertEqual(saved_sem_num, len(lockutils._semaphores), + "Semaphore leak detected") + + def test_nested_external_works(self): + """We can nest external syncs""" + tempdir = tempfile.mkdtemp() + try: + self.config(lock_path=tempdir) + sentinel = object() + + @lockutils.synchronized('testlock1', 'test-', external=True) + def outer_lock(): + + @lockutils.synchronized('testlock2', 'test-', external=True) + def inner_lock(): + return sentinel + return inner_lock() + + self.assertEqual(sentinel, outer_lock()) + + finally: + if os.path.exists(tempdir): + shutil.rmtree(tempdir) + + def test_synchronized_externally(self): + """We can lock across multiple processes""" + tempdir = tempfile.mkdtemp() + self.config(lock_path=tempdir) + rpipe1, wpipe1 = os.pipe() + rpipe2, wpipe2 = os.pipe() + + @lockutils.synchronized('testlock1', 'test-', external=True) + def f(rpipe, wpipe): + try: + os.write(wpipe, "foo") + except OSError, e: + self.assertEquals(e.errno, errno.EPIPE) + return + + rfds, _wfds, _efds = select.select([rpipe], [], [], 1) + self.assertEquals(len(rfds), 0, "The other process, which was " + "supposed to be locked, " + "wrote on its end of the " + "pipe") + os.close(rpipe) + + pid = os.fork() + if pid > 0: + os.close(wpipe1) + os.close(rpipe2) + + f(rpipe1, wpipe2) + else: + os.close(rpipe1) + os.close(wpipe2) + + time.sleep(0.1) + f(rpipe2, wpipe1) + os._exit(0) |