4 # Copyright (C) 2006, 2007 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the locking module"""
30 from ganeti import locking
31 from ganeti import errors
32 from threading import Thread
35 # This is used to test the ssynchronize decorator.
36 # Since it's passed as input to a decorator it must be declared as a global.
37 _decoratorlock = locking.SharedLock()
39 #: List for looping tests
43 """Decorator for executing a function many times"""
44 def wrapper(*args, **kwargs):
49 class _ThreadedTestCase(unittest.TestCase):
50 """Test class that supports adding/waiting on threads"""
52 unittest.TestCase.setUp(self)
55 def _addThread(self, *args, **kwargs):
56 """Create and remember a new thread"""
57 t = Thread(*args, **kwargs)
58 self.threads.append(t)
62 def _waitThreads(self):
63 """Wait for all our threads to finish"""
64 for t in self.threads:
66 self.failIf(t.isAlive())
70 class TestSharedLock(_ThreadedTestCase):
71 """SharedLock tests"""
74 _ThreadedTestCase.setUp(self)
75 self.sl = locking.SharedLock()
76 # helper threads use the 'done' queue to tell the master they finished.
77 self.done = Queue.Queue(0)
79 def testSequenceAndOwnership(self):
80 self.assert_(not self.sl._is_owned())
81 self.sl.acquire(shared=1)
82 self.assert_(self.sl._is_owned())
83 self.assert_(self.sl._is_owned(shared=1))
84 self.assert_(not self.sl._is_owned(shared=0))
86 self.assert_(not self.sl._is_owned())
88 self.assert_(self.sl._is_owned())
89 self.assert_(not self.sl._is_owned(shared=1))
90 self.assert_(self.sl._is_owned(shared=0))
92 self.assert_(not self.sl._is_owned())
93 self.sl.acquire(shared=1)
94 self.assert_(self.sl._is_owned())
95 self.assert_(self.sl._is_owned(shared=1))
96 self.assert_(not self.sl._is_owned(shared=0))
98 self.assert_(not self.sl._is_owned())
100 def testBooleanValue(self):
101 # semaphores are supposed to return a true value on a successful acquire
102 self.assert_(self.sl.acquire(shared=1))
104 self.assert_(self.sl.acquire())
107 def testDoubleLockingStoE(self):
108 self.sl.acquire(shared=1)
109 self.assertRaises(AssertionError, self.sl.acquire)
111 def testDoubleLockingEtoS(self):
113 self.assertRaises(AssertionError, self.sl.acquire, shared=1)
115 def testDoubleLockingStoS(self):
116 self.sl.acquire(shared=1)
117 self.assertRaises(AssertionError, self.sl.acquire, shared=1)
119 def testDoubleLockingEtoE(self):
121 self.assertRaises(AssertionError, self.sl.acquire)
123 # helper functions: called in a separate thread they acquire the lock, send
124 # their identifier on the done queue, then release it.
125 def _doItSharer(self):
127 self.sl.acquire(shared=1)
130 except errors.LockError:
133 def _doItExclusive(self):
138 except errors.LockError:
141 def _doItDelete(self):
145 except errors.LockError:
148 def testSharersCanCoexist(self):
149 self.sl.acquire(shared=1)
150 Thread(target=self._doItSharer).start()
151 self.assert_(self.done.get(True, 1))
155 def testExclusiveBlocksExclusive(self):
157 self._addThread(target=self._doItExclusive)
158 self.assertRaises(Queue.Empty, self.done.get_nowait)
161 self.failUnlessEqual(self.done.get_nowait(), 'EXC')
164 def testExclusiveBlocksDelete(self):
166 self._addThread(target=self._doItDelete)
167 self.assertRaises(Queue.Empty, self.done.get_nowait)
170 self.failUnlessEqual(self.done.get_nowait(), 'DEL')
171 self.sl = locking.SharedLock()
174 def testExclusiveBlocksSharer(self):
176 self._addThread(target=self._doItSharer)
177 self.assertRaises(Queue.Empty, self.done.get_nowait)
180 self.failUnlessEqual(self.done.get_nowait(), 'SHR')
183 def testSharerBlocksExclusive(self):
184 self.sl.acquire(shared=1)
185 self._addThread(target=self._doItExclusive)
186 self.assertRaises(Queue.Empty, self.done.get_nowait)
189 self.failUnlessEqual(self.done.get_nowait(), 'EXC')
192 def testSharerBlocksDelete(self):
193 self.sl.acquire(shared=1)
194 self._addThread(target=self._doItDelete)
195 self.assertRaises(Queue.Empty, self.done.get_nowait)
198 self.failUnlessEqual(self.done.get_nowait(), 'DEL')
199 self.sl = locking.SharedLock()
202 def testWaitingExclusiveBlocksSharer(self):
203 """SKIPPED testWaitingExclusiveBlockSharer"""
206 self.sl.acquire(shared=1)
207 # the lock is acquired in shared mode...
208 self._addThread(target=self._doItExclusive)
209 # ...but now an exclusive is waiting...
210 self._addThread(target=self._doItSharer)
211 # ...so the sharer should be blocked as well
212 self.assertRaises(Queue.Empty, self.done.get_nowait)
215 # The exclusive passed before
216 self.failUnlessEqual(self.done.get_nowait(), 'EXC')
217 self.failUnlessEqual(self.done.get_nowait(), 'SHR')
220 def testWaitingSharerBlocksExclusive(self):
221 """SKIPPED testWaitingSharerBlocksExclusive"""
225 # the lock is acquired in exclusive mode...
226 self._addThread(target=self._doItSharer)
227 # ...but now a sharer is waiting...
228 self._addThread(target=self._doItExclusive)
229 # ...the exclusive is waiting too...
230 self.assertRaises(Queue.Empty, self.done.get_nowait)
233 # The sharer passed before
234 self.assertEqual(self.done.get_nowait(), 'SHR')
235 self.assertEqual(self.done.get_nowait(), 'EXC')
237 def testNoNonBlocking(self):
238 self.assertRaises(NotImplementedError, self.sl.acquire, blocking=0)
239 self.assertRaises(NotImplementedError, self.sl.delete, blocking=0)
241 self.sl.delete(blocking=0) # Fine, because the lock is already acquired
243 def testDelete(self):
245 self.assertRaises(errors.LockError, self.sl.acquire)
246 self.assertRaises(errors.LockError, self.sl.acquire, shared=1)
247 self.assertRaises(errors.LockError, self.sl.delete)
249 def testNoDeleteIfSharer(self):
250 self.sl.acquire(shared=1)
251 self.assertRaises(AssertionError, self.sl.delete)
254 def testDeletePendingSharersExclusiveDelete(self):
256 self._addThread(target=self._doItSharer)
257 self._addThread(target=self._doItSharer)
258 self._addThread(target=self._doItExclusive)
259 self._addThread(target=self._doItDelete)
262 # The threads who were pending return ERR
264 self.assertEqual(self.done.get_nowait(), 'ERR')
265 self.sl = locking.SharedLock()
268 def testDeletePendingDeleteExclusiveSharers(self):
270 self._addThread(target=self._doItDelete)
271 self._addThread(target=self._doItExclusive)
272 self._addThread(target=self._doItSharer)
273 self._addThread(target=self._doItSharer)
276 # The two threads who were pending return both ERR
277 self.assertEqual(self.done.get_nowait(), 'ERR')
278 self.assertEqual(self.done.get_nowait(), 'ERR')
279 self.assertEqual(self.done.get_nowait(), 'ERR')
280 self.assertEqual(self.done.get_nowait(), 'ERR')
281 self.sl = locking.SharedLock()
284 class TestSSynchronizedDecorator(_ThreadedTestCase):
285 """Shared Lock Synchronized decorator test"""
288 _ThreadedTestCase.setUp(self)
289 # helper threads use the 'done' queue to tell the master they finished.
290 self.done = Queue.Queue(0)
292 @locking.ssynchronized(_decoratorlock)
293 def _doItExclusive(self):
294 self.assert_(_decoratorlock._is_owned())
297 @locking.ssynchronized(_decoratorlock, shared=1)
298 def _doItSharer(self):
299 self.assert_(_decoratorlock._is_owned(shared=1))
302 def testDecoratedFunctions(self):
303 self._doItExclusive()
304 self.assert_(not _decoratorlock._is_owned())
306 self.assert_(not _decoratorlock._is_owned())
308 def testSharersCanCoexist(self):
309 _decoratorlock.acquire(shared=1)
310 Thread(target=self._doItSharer).start()
311 self.assert_(self.done.get(True, 1))
312 _decoratorlock.release()
315 def testExclusiveBlocksExclusive(self):
316 _decoratorlock.acquire()
317 self._addThread(target=self._doItExclusive)
318 # give it a bit of time to check that it's not actually doing anything
319 self.assertRaises(Queue.Empty, self.done.get_nowait)
320 _decoratorlock.release()
322 self.failUnlessEqual(self.done.get_nowait(), 'EXC')
325 def testExclusiveBlocksSharer(self):
326 _decoratorlock.acquire()
327 self._addThread(target=self._doItSharer)
328 self.assertRaises(Queue.Empty, self.done.get_nowait)
329 _decoratorlock.release()
331 self.failUnlessEqual(self.done.get_nowait(), 'SHR')
334 def testSharerBlocksExclusive(self):
335 _decoratorlock.acquire(shared=1)
336 self._addThread(target=self._doItExclusive)
337 self.assertRaises(Queue.Empty, self.done.get_nowait)
338 _decoratorlock.release()
340 self.failUnlessEqual(self.done.get_nowait(), 'EXC')
343 class TestLockSet(_ThreadedTestCase):
347 _ThreadedTestCase.setUp(self)
349 # helper threads use the 'done' queue to tell the master they finished.
350 self.done = Queue.Queue(0)
353 """Helper to (re)initialize the lock set"""
354 self.resources = ['one', 'two', 'three']
355 self.ls = locking.LockSet(members=self.resources)
358 def testResources(self):
359 self.assertEquals(self.ls._names(), set(self.resources))
360 newls = locking.LockSet()
361 self.assertEquals(newls._names(), set())
363 def testAcquireRelease(self):
364 self.assert_(self.ls.acquire('one'))
365 self.assertEquals(self.ls._list_owned(), set(['one']))
367 self.assertEquals(self.ls._list_owned(), set())
368 self.assertEquals(self.ls.acquire(['one']), set(['one']))
369 self.assertEquals(self.ls._list_owned(), set(['one']))
371 self.assertEquals(self.ls._list_owned(), set())
372 self.ls.acquire(['one', 'two', 'three'])
373 self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
374 self.ls.release('one')
375 self.assertEquals(self.ls._list_owned(), set(['two', 'three']))
376 self.ls.release(['three'])
377 self.assertEquals(self.ls._list_owned(), set(['two']))
379 self.assertEquals(self.ls._list_owned(), set())
380 self.assertEquals(self.ls.acquire(['one', 'three']), set(['one', 'three']))
381 self.assertEquals(self.ls._list_owned(), set(['one', 'three']))
383 self.assertEquals(self.ls._list_owned(), set())
385 def testNoDoubleAcquire(self):
386 self.ls.acquire('one')
387 self.assertRaises(AssertionError, self.ls.acquire, 'one')
388 self.assertRaises(AssertionError, self.ls.acquire, ['two'])
389 self.assertRaises(AssertionError, self.ls.acquire, ['two', 'three'])
391 self.ls.acquire(['one', 'three'])
392 self.ls.release('one')
393 self.assertRaises(AssertionError, self.ls.acquire, ['two'])
394 self.ls.release('three')
396 def testNoWrongRelease(self):
397 self.assertRaises(AssertionError, self.ls.release)
398 self.ls.acquire('one')
399 self.assertRaises(AssertionError, self.ls.release, 'two')
401 def testAddRemove(self):
403 self.assertEquals(self.ls._list_owned(), set())
404 self.assert_('four' in self.ls._names())
405 self.ls.add(['five', 'six', 'seven'], acquired=1)
406 self.assert_('five' in self.ls._names())
407 self.assert_('six' in self.ls._names())
408 self.assert_('seven' in self.ls._names())
409 self.assertEquals(self.ls._list_owned(), set(['five', 'six', 'seven']))
410 self.assertEquals(self.ls.remove(['five', 'six']), ['five', 'six'])
411 self.assert_('five' not in self.ls._names())
412 self.assert_('six' not in self.ls._names())
413 self.assertEquals(self.ls._list_owned(), set(['seven']))
414 self.assertRaises(AssertionError, self.ls.add, 'eight', acquired=1)
415 self.ls.remove('seven')
416 self.assert_('seven' not in self.ls._names())
417 self.assertEquals(self.ls._list_owned(), set([]))
418 self.ls.acquire(None, shared=1)
419 self.assertRaises(AssertionError, self.ls.add, 'eight')
421 self.ls.acquire(None)
422 self.ls.add('eight', acquired=1)
423 self.assert_('eight' in self.ls._names())
424 self.assert_('eight' in self.ls._list_owned())
426 self.assert_('nine' in self.ls._names())
427 self.assert_('nine' not in self.ls._list_owned())
429 self.ls.remove(['two'])
430 self.assert_('two' not in self.ls._names())
431 self.ls.acquire('three')
432 self.assertEquals(self.ls.remove(['three']), ['three'])
433 self.assert_('three' not in self.ls._names())
434 self.assertEquals(self.ls.remove('three'), [])
435 self.assertEquals(self.ls.remove(['one', 'three', 'six']), ['one'])
436 self.assert_('one' not in self.ls._names())
438 def testRemoveNonBlocking(self):
439 self.assertRaises(NotImplementedError, self.ls.remove, 'one', blocking=0)
440 self.ls.acquire('one')
441 self.assertEquals(self.ls.remove('one', blocking=0), ['one'])
442 self.ls.acquire(['two', 'three'])
443 self.assertEquals(self.ls.remove(['two', 'three'], blocking=0),
446 def testNoDoubleAdd(self):
447 self.assertRaises(errors.LockError, self.ls.add, 'two')
449 self.assertRaises(errors.LockError, self.ls.add, 'four')
451 def testNoWrongRemoves(self):
452 self.ls.acquire(['one', 'three'], shared=1)
453 # Cannot remove 'two' while holding something which is not a superset
454 self.assertRaises(AssertionError, self.ls.remove, 'two')
455 # Cannot remove 'three' as we are sharing it
456 self.assertRaises(AssertionError, self.ls.remove, 'three')
458 def testAcquireSetLock(self):
459 # acquire the set-lock exclusively
460 self.assertEquals(self.ls.acquire(None), set(['one', 'two', 'three']))
461 self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
462 self.assertEquals(self.ls._is_owned(), True)
463 self.assertEquals(self.ls._names(), set(['one', 'two', 'three']))
464 # I can still add/remove elements...
465 self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
466 self.assert_(self.ls.add('six'))
469 self.assertEquals(self.ls.acquire(None, shared=1), set(['one', 'six']))
470 # adding new elements is not possible
471 self.assertRaises(AssertionError, self.ls.add, 'five')
474 def testAcquireWithRepetitions(self):
475 self.assertEquals(self.ls.acquire(['two', 'two', 'three'], shared=1),
476 set(['two', 'two', 'three']))
477 self.ls.release(['two', 'two'])
478 self.assertEquals(self.ls._list_owned(), set(['three']))
480 def testEmptyAcquire(self):
481 # Acquire an empty list of locks...
482 self.assertEquals(self.ls.acquire([]), set())
483 self.assertEquals(self.ls._list_owned(), set())
484 # New locks can still be addded
485 self.assert_(self.ls.add('six'))
486 # "re-acquiring" is not an issue, since we had really acquired nothing
487 self.assertEquals(self.ls.acquire([], shared=1), set())
488 self.assertEquals(self.ls._list_owned(), set())
489 # We haven't really acquired anything, so we cannot release
490 self.assertRaises(AssertionError, self.ls.release)
492 def _doLockSet(self, set, shared):
494 self.ls.acquire(set, shared=shared)
495 self.done.put('DONE')
497 except errors.LockError:
500 def _doAddSet(self, set):
502 self.ls.add(set, acquired=1)
503 self.done.put('DONE')
505 except errors.LockError:
508 def _doRemoveSet(self, set):
509 self.done.put(self.ls.remove(set))
512 def testConcurrentSharedAcquire(self):
513 self.ls.acquire(['one', 'two'], shared=1)
514 self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
516 self.assertEqual(self.done.get_nowait(), 'DONE')
517 self._addThread(target=self._doLockSet, args=(['one', 'two', 'three'], 1))
519 self.assertEqual(self.done.get_nowait(), 'DONE')
520 self._addThread(target=self._doLockSet, args=('three', 1))
522 self.assertEqual(self.done.get_nowait(), 'DONE')
523 self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
524 self._addThread(target=self._doLockSet, args=(['two', 'three'], 0))
525 self.assertRaises(Queue.Empty, self.done.get_nowait)
528 self.assertEqual(self.done.get_nowait(), 'DONE')
529 self.assertEqual(self.done.get_nowait(), 'DONE')
532 def testConcurrentExclusiveAcquire(self):
533 self.ls.acquire(['one', 'two'])
534 self._addThread(target=self._doLockSet, args=('three', 1))
536 self.assertEqual(self.done.get_nowait(), 'DONE')
537 self._addThread(target=self._doLockSet, args=('three', 0))
539 self.assertEqual(self.done.get_nowait(), 'DONE')
540 self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
541 self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
542 self._addThread(target=self._doLockSet, args=('one', 0))
543 self._addThread(target=self._doLockSet, args=('one', 1))
544 self._addThread(target=self._doLockSet, args=(['two', 'three'], 0))
545 self._addThread(target=self._doLockSet, args=(['two', 'three'], 1))
546 self.assertRaises(Queue.Empty, self.done.get_nowait)
550 self.failUnlessEqual(self.done.get_nowait(), 'DONE')
553 def testConcurrentRemove(self):
555 self.ls.acquire(['one', 'two', 'four'])
556 self._addThread(target=self._doLockSet, args=(['one', 'four'], 0))
557 self._addThread(target=self._doLockSet, args=(['one', 'four'], 1))
558 self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
559 self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
560 self.assertRaises(Queue.Empty, self.done.get_nowait)
561 self.ls.remove('one')
565 self.failUnlessEqual(self.done.get_nowait(), 'ERR')
566 self.ls.add(['five', 'six'], acquired=1)
567 self._addThread(target=self._doLockSet, args=(['three', 'six'], 1))
568 self._addThread(target=self._doLockSet, args=(['three', 'six'], 0))
569 self._addThread(target=self._doLockSet, args=(['four', 'six'], 1))
570 self._addThread(target=self._doLockSet, args=(['four', 'six'], 0))
571 self.ls.remove('five')
575 self.failUnlessEqual(self.done.get_nowait(), 'DONE')
576 self.ls.acquire(['three', 'four'])
577 self._addThread(target=self._doRemoveSet, args=(['four', 'six'], ))
578 self.assertRaises(Queue.Empty, self.done.get_nowait)
579 self.ls.remove('four')
581 self.assertEqual(self.done.get_nowait(), ['six'])
582 self._addThread(target=self._doRemoveSet, args=(['two']))
584 self.assertEqual(self.done.get_nowait(), ['two'])
590 def testConcurrentSharedSetLock(self):
591 # share the set-lock...
592 self.ls.acquire(None, shared=1)
593 # ...another thread can share it too
594 self._addThread(target=self._doLockSet, args=(None, 1))
596 self.assertEqual(self.done.get_nowait(), 'DONE')
597 # ...or just share some elements
598 self._addThread(target=self._doLockSet, args=(['one', 'three'], 1))
600 self.assertEqual(self.done.get_nowait(), 'DONE')
601 # ...but not add new ones or remove any
602 t = self._addThread(target=self._doAddSet, args=(['nine']))
603 self._addThread(target=self._doRemoveSet, args=(['two'], ))
604 self.assertRaises(Queue.Empty, self.done.get_nowait)
605 # this just releases the set-lock
608 self.assertEqual(self.done.get_nowait(), 'DONE')
609 # release the lock on the actual elements so remove() can proceed too
612 self.failUnlessEqual(self.done.get_nowait(), ['two'])
617 def testConcurrentExclusiveSetLock(self):
618 # acquire the set-lock...
619 self.ls.acquire(None, shared=0)
620 # ...no one can do anything else
621 self._addThread(target=self._doLockSet, args=(None, 1))
622 self._addThread(target=self._doLockSet, args=(None, 0))
623 self._addThread(target=self._doLockSet, args=(['three'], 0))
624 self._addThread(target=self._doLockSet, args=(['two'], 1))
625 self._addThread(target=self._doAddSet, args=(['nine']))
626 self.assertRaises(Queue.Empty, self.done.get_nowait)
630 self.assertEqual(self.done.get(True, 1), 'DONE')
635 def testConcurrentSetLockAdd(self):
636 self.ls.acquire('one')
637 # Another thread wants the whole SetLock
638 self._addThread(target=self._doLockSet, args=(None, 0))
639 self._addThread(target=self._doLockSet, args=(None, 1))
640 self.assertRaises(Queue.Empty, self.done.get_nowait)
641 self.assertRaises(AssertionError, self.ls.add, 'four')
644 self.assertEqual(self.done.get_nowait(), 'DONE')
645 self.assertEqual(self.done.get_nowait(), 'DONE')
646 self.ls.acquire(None)
647 self._addThread(target=self._doLockSet, args=(None, 0))
648 self._addThread(target=self._doLockSet, args=(None, 1))
649 self.assertRaises(Queue.Empty, self.done.get_nowait)
651 self.ls.add('five', acquired=1)
652 self.ls.add('six', acquired=1, shared=1)
653 self.assertEquals(self.ls._list_owned(),
654 set(['one', 'two', 'three', 'five', 'six']))
655 self.assertEquals(self.ls._is_owned(), True)
656 self.assertEquals(self.ls._names(),
657 set(['one', 'two', 'three', 'four', 'five', 'six']))
660 self.assertEqual(self.done.get_nowait(), 'DONE')
661 self.assertEqual(self.done.get_nowait(), 'DONE')
665 def testEmptyLockSet(self):
667 self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
669 self.ls.remove(['one', 'two', 'three'])
670 # and adds/locks by another thread still wait
671 self._addThread(target=self._doAddSet, args=(['nine']))
672 self._addThread(target=self._doLockSet, args=(None, 1))
673 self._addThread(target=self._doLockSet, args=(None, 0))
674 self.assertRaises(Queue.Empty, self.done.get_nowait)
678 self.assertEqual(self.done.get_nowait(), 'DONE')
680 self.assertEqual(self.ls.remove(['nine']), ['nine'])
682 self.assertEqual(self.ls.acquire(None, shared=1), set())
683 # other sharers can go, adds still wait
684 self._addThread(target=self._doLockSet, args=(None, 1))
686 self.assertEqual(self.done.get_nowait(), 'DONE')
687 self._addThread(target=self._doAddSet, args=(['nine']))
688 self.assertRaises(Queue.Empty, self.done.get_nowait)
691 self.assertEqual(self.done.get_nowait(), 'DONE')
695 class TestGanetiLockManager(_ThreadedTestCase):
698 _ThreadedTestCase.setUp(self)
699 self.nodes=['n1', 'n2']
700 self.instances=['i1', 'i2', 'i3']
701 self.GL = locking.GanetiLockManager(nodes=self.nodes,
702 instances=self.instances)
703 self.done = Queue.Queue(0)
706 # Don't try this at home...
707 locking.GanetiLockManager._instance = None
709 def testLockingConstants(self):
710 # The locking library internally cheats by assuming its constants have some
711 # relationships with each other. Check those hold true.
712 # This relationship is also used in the Processor to recursively acquire
713 # the right locks. Again, please don't break it.
714 for i in range(len(locking.LEVELS)):
715 self.assertEqual(i, locking.LEVELS[i])
717 def testDoubleGLFails(self):
718 self.assertRaises(AssertionError, locking.GanetiLockManager)
720 def testLockNames(self):
721 self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
722 self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
723 self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
726 def testInitAndResources(self):
727 locking.GanetiLockManager._instance = None
728 self.GL = locking.GanetiLockManager()
729 self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
730 self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
731 self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
733 locking.GanetiLockManager._instance = None
734 self.GL = locking.GanetiLockManager(nodes=self.nodes)
735 self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
736 self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
737 self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
739 locking.GanetiLockManager._instance = None
740 self.GL = locking.GanetiLockManager(instances=self.instances)
741 self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
742 self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
743 self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
746 def testAcquireRelease(self):
747 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
748 self.assertEquals(self.GL._list_owned(locking.LEVEL_CLUSTER), set(['BGL']))
749 self.GL.acquire(locking.LEVEL_INSTANCE, ['i1'])
750 self.GL.acquire(locking.LEVEL_NODE, ['n1', 'n2'], shared=1)
751 self.GL.release(locking.LEVEL_NODE, ['n2'])
752 self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
753 self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
754 self.GL.release(locking.LEVEL_NODE)
755 self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set())
756 self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
757 self.GL.release(locking.LEVEL_INSTANCE)
758 self.assertRaises(errors.LockError, self.GL.acquire,
759 locking.LEVEL_INSTANCE, ['i5'])
760 self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
761 self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i3']))
763 def testAcquireWholeSets(self):
764 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
765 self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
767 self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
769 self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, None, shared=1),
771 self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
773 self.GL.release(locking.LEVEL_NODE)
774 self.GL.release(locking.LEVEL_INSTANCE)
775 self.GL.release(locking.LEVEL_CLUSTER)
777 def testAcquireWholeAndPartial(self):
778 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
779 self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
781 self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
783 self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, ['n2'], shared=1),
785 self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
787 self.GL.release(locking.LEVEL_NODE)
788 self.GL.release(locking.LEVEL_INSTANCE)
789 self.GL.release(locking.LEVEL_CLUSTER)
791 def testBGLDependency(self):
792 self.assertRaises(AssertionError, self.GL.acquire,
793 locking.LEVEL_NODE, ['n1', 'n2'])
794 self.assertRaises(AssertionError, self.GL.acquire,
795 locking.LEVEL_INSTANCE, ['i3'])
796 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
797 self.GL.acquire(locking.LEVEL_NODE, ['n1'])
798 self.assertRaises(AssertionError, self.GL.release,
799 locking.LEVEL_CLUSTER, ['BGL'])
800 self.assertRaises(AssertionError, self.GL.release,
801 locking.LEVEL_CLUSTER)
802 self.GL.release(locking.LEVEL_NODE)
803 self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
804 self.assertRaises(AssertionError, self.GL.release,
805 locking.LEVEL_CLUSTER, ['BGL'])
806 self.assertRaises(AssertionError, self.GL.release,
807 locking.LEVEL_CLUSTER)
808 self.GL.release(locking.LEVEL_INSTANCE)
810 def testWrongOrder(self):
811 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
812 self.GL.acquire(locking.LEVEL_NODE, ['n2'])
813 self.assertRaises(AssertionError, self.GL.acquire,
814 locking.LEVEL_NODE, ['n1'])
815 self.assertRaises(AssertionError, self.GL.acquire,
816 locking.LEVEL_INSTANCE, ['i2'])
818 # Helper function to run as a thread that shared the BGL and then acquires
819 # some locks at another level.
820 def _doLock(self, level, names, shared):
822 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
823 self.GL.acquire(level, names, shared=shared)
824 self.done.put('DONE')
825 self.GL.release(level)
826 self.GL.release(locking.LEVEL_CLUSTER)
827 except errors.LockError:
831 def testConcurrency(self):
832 self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
833 self._addThread(target=self._doLock,
834 args=(locking.LEVEL_INSTANCE, 'i1', 1))
836 self.assertEqual(self.done.get_nowait(), 'DONE')
837 self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
838 self._addThread(target=self._doLock,
839 args=(locking.LEVEL_INSTANCE, 'i1', 1))
841 self.assertEqual(self.done.get_nowait(), 'DONE')
842 self._addThread(target=self._doLock,
843 args=(locking.LEVEL_INSTANCE, 'i3', 1))
844 self.assertRaises(Queue.Empty, self.done.get_nowait)
845 self.GL.release(locking.LEVEL_INSTANCE)
847 self.assertEqual(self.done.get_nowait(), 'DONE')
848 self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)
849 self._addThread(target=self._doLock,
850 args=(locking.LEVEL_INSTANCE, 'i2', 1))
852 self.assertEqual(self.done.get_nowait(), 'DONE')
853 self._addThread(target=self._doLock,
854 args=(locking.LEVEL_INSTANCE, 'i2', 0))
855 self.assertRaises(Queue.Empty, self.done.get_nowait)
856 self.GL.release(locking.LEVEL_INSTANCE)
858 self.assertEqual(self.done.get(True, 1), 'DONE')
859 self.GL.release(locking.LEVEL_CLUSTER, ['BGL'])
862 if __name__ == '__main__':
864 #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
865 #unittest.TextTestRunner(verbosity=2).run(suite)