Locking: remove LEVEL_CONFIG lockset
[ganeti-local] / test / ganeti.locking_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2006, 2007 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 0.0510-1301, USA.
20
21
22 """Script for unittesting the locking module"""
23
24
25 import os
26 import unittest
27 import time
28 import Queue
29
30 from ganeti import locking
31 from ganeti import errors
32 from threading import Thread
33
34
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()
38
39
40 class TestSharedLock(unittest.TestCase):
41   """SharedLock tests"""
42
43   def setUp(self):
44     self.sl = locking.SharedLock()
45     # helper threads use the 'done' queue to tell the master they finished.
46     self.done = Queue.Queue(0)
47
48   def testSequenceAndOwnership(self):
49     self.assert_(not self.sl._is_owned())
50     self.sl.acquire(shared=1)
51     self.assert_(self.sl._is_owned())
52     self.assert_(self.sl._is_owned(shared=1))
53     self.assert_(not self.sl._is_owned(shared=0))
54     self.sl.release()
55     self.assert_(not self.sl._is_owned())
56     self.sl.acquire()
57     self.assert_(self.sl._is_owned())
58     self.assert_(not self.sl._is_owned(shared=1))
59     self.assert_(self.sl._is_owned(shared=0))
60     self.sl.release()
61     self.assert_(not self.sl._is_owned())
62     self.sl.acquire(shared=1)
63     self.assert_(self.sl._is_owned())
64     self.assert_(self.sl._is_owned(shared=1))
65     self.assert_(not self.sl._is_owned(shared=0))
66     self.sl.release()
67     self.assert_(not self.sl._is_owned())
68
69   def testBooleanValue(self):
70     # semaphores are supposed to return a true value on a successful acquire
71     self.assert_(self.sl.acquire(shared=1))
72     self.sl.release()
73     self.assert_(self.sl.acquire())
74     self.sl.release()
75
76   def testDoubleLockingStoE(self):
77     self.sl.acquire(shared=1)
78     self.assertRaises(AssertionError, self.sl.acquire)
79
80   def testDoubleLockingEtoS(self):
81     self.sl.acquire()
82     self.assertRaises(AssertionError, self.sl.acquire, shared=1)
83
84   def testDoubleLockingStoS(self):
85     self.sl.acquire(shared=1)
86     self.assertRaises(AssertionError, self.sl.acquire, shared=1)
87
88   def testDoubleLockingEtoE(self):
89     self.sl.acquire()
90     self.assertRaises(AssertionError, self.sl.acquire)
91
92   # helper functions: called in a separate thread they acquire the lock, send
93   # their identifier on the done queue, then release it.
94   def _doItSharer(self):
95     try:
96       self.sl.acquire(shared=1)
97       self.done.put('SHR')
98       self.sl.release()
99     except errors.LockError:
100       self.done.put('ERR')
101
102   def _doItExclusive(self):
103     try:
104       self.sl.acquire()
105       self.done.put('EXC')
106       self.sl.release()
107     except errors.LockError:
108       self.done.put('ERR')
109
110   def _doItDelete(self):
111     try:
112       self.sl.delete()
113       self.done.put('DEL')
114     except errors.LockError:
115       self.done.put('ERR')
116
117   def testSharersCanCoexist(self):
118     self.sl.acquire(shared=1)
119     Thread(target=self._doItSharer).start()
120     self.assert_(self.done.get(True, 1))
121     self.sl.release()
122
123   def testExclusiveBlocksExclusive(self):
124     self.sl.acquire()
125     Thread(target=self._doItExclusive).start()
126     # give it a bit of time to check that it's not actually doing anything
127     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
128     self.sl.release()
129     self.assert_(self.done.get(True, 1))
130
131   def testExclusiveBlocksDelete(self):
132     self.sl.acquire()
133     Thread(target=self._doItDelete).start()
134     # give it a bit of time to check that it's not actually doing anything
135     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
136     self.sl.release()
137     self.assert_(self.done.get(True, 1))
138
139   def testExclusiveBlocksSharer(self):
140     self.sl.acquire()
141     Thread(target=self._doItSharer).start()
142     time.sleep(0.05)
143     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
144     self.sl.release()
145     self.assert_(self.done.get(True, 1))
146
147   def testSharerBlocksExclusive(self):
148     self.sl.acquire(shared=1)
149     Thread(target=self._doItExclusive).start()
150     time.sleep(0.05)
151     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
152     self.sl.release()
153     self.assert_(self.done.get(True, 1))
154
155   def testSharerBlocksDelete(self):
156     self.sl.acquire(shared=1)
157     Thread(target=self._doItDelete).start()
158     time.sleep(0.05)
159     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
160     self.sl.release()
161     self.assert_(self.done.get(True, 1))
162
163   def testWaitingExclusiveBlocksSharer(self):
164     self.sl.acquire(shared=1)
165     # the lock is acquired in shared mode...
166     Thread(target=self._doItExclusive).start()
167     # ...but now an exclusive is waiting...
168     time.sleep(0.05)
169     Thread(target=self._doItSharer).start()
170     # ...so the sharer should be blocked as well
171     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
172     self.sl.release()
173     # The exclusive passed before
174     self.assertEqual(self.done.get(True, 1), 'EXC')
175     self.assertEqual(self.done.get(True, 1), 'SHR')
176
177   def testWaitingSharerBlocksExclusive(self):
178     self.sl.acquire()
179     # the lock is acquired in exclusive mode...
180     Thread(target=self._doItSharer).start()
181     # ...but now a sharer is waiting...
182     time.sleep(0.05)
183     Thread(target=self._doItExclusive).start()
184     # ...the exclusive is waiting too...
185     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
186     self.sl.release()
187     # The sharer passed before
188     self.assertEqual(self.done.get(True, 1), 'SHR')
189     self.assertEqual(self.done.get(True, 1), 'EXC')
190
191   def testNoNonBlocking(self):
192     self.assertRaises(NotImplementedError, self.sl.acquire, blocking=0)
193     self.assertRaises(NotImplementedError, self.sl.delete, blocking=0)
194     self.sl.acquire()
195     self.sl.delete(blocking=0) # Fine, because the lock is already acquired
196
197   def testDelete(self):
198     self.sl.delete()
199     self.assertRaises(errors.LockError, self.sl.acquire)
200     self.assertRaises(errors.LockError, self.sl.acquire, shared=1)
201     self.assertRaises(errors.LockError, self.sl.delete)
202
203   def testNoDeleteIfSharer(self):
204     self.sl.acquire(shared=1)
205     self.assertRaises(AssertionError, self.sl.delete)
206
207   def testDeletePendingSharersExclusiveDelete(self):
208     self.sl.acquire()
209     Thread(target=self._doItSharer).start()
210     Thread(target=self._doItSharer).start()
211     time.sleep(0.05)
212     Thread(target=self._doItExclusive).start()
213     Thread(target=self._doItDelete).start()
214     time.sleep(0.05)
215     self.sl.delete()
216     # The two threads who were pending return both ERR
217     self.assertEqual(self.done.get(True, 1), 'ERR')
218     self.assertEqual(self.done.get(True, 1), 'ERR')
219     self.assertEqual(self.done.get(True, 1), 'ERR')
220     self.assertEqual(self.done.get(True, 1), 'ERR')
221
222   def testDeletePendingDeleteExclusiveSharers(self):
223     self.sl.acquire()
224     Thread(target=self._doItDelete).start()
225     Thread(target=self._doItExclusive).start()
226     time.sleep(0.05)
227     Thread(target=self._doItSharer).start()
228     Thread(target=self._doItSharer).start()
229     time.sleep(0.05)
230     self.sl.delete()
231     # The two threads who were pending return both ERR
232     self.assertEqual(self.done.get(True, 1), 'ERR')
233     self.assertEqual(self.done.get(True, 1), 'ERR')
234     self.assertEqual(self.done.get(True, 1), 'ERR')
235     self.assertEqual(self.done.get(True, 1), 'ERR')
236
237
238 class TestSSynchronizedDecorator(unittest.TestCase):
239   """Shared Lock Synchronized decorator test"""
240
241   def setUp(self):
242     # helper threads use the 'done' queue to tell the master they finished.
243     self.done = Queue.Queue(0)
244
245   @locking.ssynchronized(_decoratorlock)
246   def _doItExclusive(self):
247     self.assert_(_decoratorlock._is_owned())
248     self.done.put('EXC')
249
250   @locking.ssynchronized(_decoratorlock, shared=1)
251   def _doItSharer(self):
252     self.assert_(_decoratorlock._is_owned(shared=1))
253     self.done.put('SHR')
254
255   def testDecoratedFunctions(self):
256     self._doItExclusive()
257     self.assert_(not _decoratorlock._is_owned())
258     self._doItSharer()
259     self.assert_(not _decoratorlock._is_owned())
260
261   def testSharersCanCoexist(self):
262     _decoratorlock.acquire(shared=1)
263     Thread(target=self._doItSharer).start()
264     self.assert_(self.done.get(True, 1))
265     _decoratorlock.release()
266
267   def testExclusiveBlocksExclusive(self):
268     _decoratorlock.acquire()
269     Thread(target=self._doItExclusive).start()
270     # give it a bit of time to check that it's not actually doing anything
271     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
272     _decoratorlock.release()
273     self.assert_(self.done.get(True, 1))
274
275   def testExclusiveBlocksSharer(self):
276     _decoratorlock.acquire()
277     Thread(target=self._doItSharer).start()
278     time.sleep(0.05)
279     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
280     _decoratorlock.release()
281     self.assert_(self.done.get(True, 1))
282
283   def testSharerBlocksExclusive(self):
284     _decoratorlock.acquire(shared=1)
285     Thread(target=self._doItExclusive).start()
286     time.sleep(0.05)
287     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
288     _decoratorlock.release()
289     self.assert_(self.done.get(True, 1))
290
291
292 class TestLockSet(unittest.TestCase):
293   """LockSet tests"""
294
295   def setUp(self):
296     self.resources = ['one', 'two', 'three']
297     self.ls = locking.LockSet(members=self.resources)
298     # helper threads use the 'done' queue to tell the master they finished.
299     self.done = Queue.Queue(0)
300
301   def testResources(self):
302     self.assertEquals(self.ls._names(), set(self.resources))
303     newls = locking.LockSet()
304     self.assertEquals(newls._names(), set())
305
306   def testAcquireRelease(self):
307     self.assert_(self.ls.acquire('one'))
308     self.assertEquals(self.ls._list_owned(), set(['one']))
309     self.ls.release()
310     self.assertEquals(self.ls._list_owned(), set())
311     self.assertEquals(self.ls.acquire(['one']), set(['one']))
312     self.assertEquals(self.ls._list_owned(), set(['one']))
313     self.ls.release()
314     self.assertEquals(self.ls._list_owned(), set())
315     self.ls.acquire(['one', 'two', 'three'])
316     self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
317     self.ls.release('one')
318     self.assertEquals(self.ls._list_owned(), set(['two', 'three']))
319     self.ls.release(['three'])
320     self.assertEquals(self.ls._list_owned(), set(['two']))
321     self.ls.release()
322     self.assertEquals(self.ls._list_owned(), set())
323     self.assertEquals(self.ls.acquire(['one', 'three']), set(['one', 'three']))
324     self.assertEquals(self.ls._list_owned(), set(['one', 'three']))
325     self.ls.release()
326     self.assertEquals(self.ls._list_owned(), set())
327
328   def testNoDoubleAcquire(self):
329     self.ls.acquire('one')
330     self.assertRaises(AssertionError, self.ls.acquire, 'one')
331     self.assertRaises(AssertionError, self.ls.acquire, ['two'])
332     self.assertRaises(AssertionError, self.ls.acquire, ['two', 'three'])
333     self.ls.release()
334     self.ls.acquire(['one', 'three'])
335     self.ls.release('one')
336     self.assertRaises(AssertionError, self.ls.acquire, ['two'])
337     self.ls.release('three')
338
339   def testNoWrongRelease(self):
340     self.assertRaises(AssertionError, self.ls.release)
341     self.ls.acquire('one')
342     self.assertRaises(AssertionError, self.ls.release, 'two')
343
344   def testAddRemove(self):
345     self.ls.add('four')
346     self.assertEquals(self.ls._list_owned(), set())
347     self.assert_('four' in self.ls._names())
348     self.ls.add(['five', 'six', 'seven'], acquired=1)
349     self.assert_('five' in self.ls._names())
350     self.assert_('six' in self.ls._names())
351     self.assert_('seven' in self.ls._names())
352     self.assertEquals(self.ls._list_owned(), set(['five', 'six', 'seven']))
353     self.assertEquals(self.ls.remove(['five', 'six']), ['five', 'six'])
354     self.assert_('five' not in self.ls._names())
355     self.assert_('six' not in self.ls._names())
356     self.assertEquals(self.ls._list_owned(), set(['seven']))
357     self.ls.add('eight', acquired=1, shared=1)
358     self.assert_('eight' in self.ls._names())
359     self.assertEquals(self.ls._list_owned(), set(['seven', 'eight']))
360     self.ls.remove('seven')
361     self.assert_('seven' not in self.ls._names())
362     self.assertEquals(self.ls._list_owned(), set(['eight']))
363     self.ls.release()
364     self.ls.remove(['two'])
365     self.assert_('two' not in self.ls._names())
366     self.ls.acquire('three')
367     self.assertEquals(self.ls.remove(['three']), ['three'])
368     self.assert_('three' not in self.ls._names())
369     self.assertEquals(self.ls.remove('three'), [])
370     self.assertEquals(self.ls.remove(['one', 'three', 'six']), ['one'])
371     self.assert_('one' not in self.ls._names())
372
373   def testRemoveNonBlocking(self):
374     self.assertRaises(NotImplementedError, self.ls.remove, 'one', blocking=0)
375     self.ls.acquire('one')
376     self.assertEquals(self.ls.remove('one', blocking=0), ['one'])
377     self.ls.acquire(['two', 'three'])
378     self.assertEquals(self.ls.remove(['two', 'three'], blocking=0),
379                       ['two', 'three'])
380
381   def testNoDoubleAdd(self):
382     self.assertRaises(errors.LockError, self.ls.add, 'two')
383     self.ls.add('four')
384     self.assertRaises(errors.LockError, self.ls.add, 'four')
385
386   def testNoWrongRemoves(self):
387     self.ls.acquire(['one', 'three'], shared=1)
388     # Cannot remove 'two' while holding something which is not a superset
389     self.assertRaises(AssertionError, self.ls.remove, 'two')
390     # Cannot remove 'three' as we are sharing it
391     self.assertRaises(AssertionError, self.ls.remove, 'three')
392
393   def testAcquireSetLock(self):
394     # acquire the set-lock exclusively
395     self.assertEquals(self.ls.acquire(None), set(['one', 'two', 'three']))
396     # I can still add/remove elements...
397     self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
398     self.assert_(self.ls.add('six'))
399     self.ls.release()
400     # share the set-lock
401     self.assertEquals(self.ls.acquire(None, shared=1), set(['one', 'six']))
402     # adding new elements is not possible
403     self.assertRaises(AssertionError, self.ls.add, 'five')
404     self.ls.release()
405
406   def _doLockSet(self, set, shared):
407     try:
408       self.ls.acquire(set, shared=shared)
409       self.done.put('DONE')
410       self.ls.release()
411     except errors.LockError:
412       self.done.put('ERR')
413
414   def _doAddSet(self, set):
415     try:
416       self.ls.add(set, acquired=1)
417       self.done.put('DONE')
418       self.ls.release()
419     except errors.LockError:
420       self.done.put('ERR')
421
422   def _doRemoveSet(self, set):
423     self.done.put(self.ls.remove(set))
424
425   def testConcurrentSharedAcquire(self):
426     self.ls.acquire(['one', 'two'], shared=1)
427     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
428     self.assertEqual(self.done.get(True, 1), 'DONE')
429     Thread(target=self._doLockSet, args=(['one', 'two', 'three'], 1)).start()
430     self.assertEqual(self.done.get(True, 1), 'DONE')
431     Thread(target=self._doLockSet, args=('three', 1)).start()
432     self.assertEqual(self.done.get(True, 1), 'DONE')
433     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
434     Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
435     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
436     self.ls.release()
437     self.assertEqual(self.done.get(True, 1), 'DONE')
438     self.assertEqual(self.done.get(True, 1), 'DONE')
439
440   def testConcurrentExclusiveAcquire(self):
441     self.ls.acquire(['one', 'two'])
442     Thread(target=self._doLockSet, args=('three', 1)).start()
443     self.assertEqual(self.done.get(True, 1), 'DONE')
444     Thread(target=self._doLockSet, args=('three', 0)).start()
445     self.assertEqual(self.done.get(True, 1), 'DONE')
446     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
447     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
448     Thread(target=self._doLockSet, args=('one', 0)).start()
449     Thread(target=self._doLockSet, args=('one', 1)).start()
450     Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
451     Thread(target=self._doLockSet, args=(['two', 'three'], 1)).start()
452     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
453     self.ls.release()
454     self.assertEqual(self.done.get(True, 1), 'DONE')
455     self.assertEqual(self.done.get(True, 1), 'DONE')
456     self.assertEqual(self.done.get(True, 1), 'DONE')
457     self.assertEqual(self.done.get(True, 1), 'DONE')
458     self.assertEqual(self.done.get(True, 1), 'DONE')
459     self.assertEqual(self.done.get(True, 1), 'DONE')
460
461   def testConcurrentRemove(self):
462     self.ls.add('four')
463     self.ls.acquire(['one', 'two', 'four'])
464     Thread(target=self._doLockSet, args=(['one', 'four'], 0)).start()
465     Thread(target=self._doLockSet, args=(['one', 'four'], 1)).start()
466     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
467     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
468     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
469     self.ls.remove('one')
470     self.ls.release()
471     self.assertEqual(self.done.get(True, 1), 'ERR')
472     self.assertEqual(self.done.get(True, 1), 'ERR')
473     self.assertEqual(self.done.get(True, 1), 'ERR')
474     self.assertEqual(self.done.get(True, 1), 'ERR')
475     self.ls.add(['five', 'six'], acquired=1)
476     Thread(target=self._doLockSet, args=(['three', 'six'], 1)).start()
477     Thread(target=self._doLockSet, args=(['three', 'six'], 0)).start()
478     Thread(target=self._doLockSet, args=(['four', 'six'], 1)).start()
479     Thread(target=self._doLockSet, args=(['four', 'six'], 0)).start()
480     self.ls.remove('five')
481     self.ls.release()
482     self.assertEqual(self.done.get(True, 1), 'DONE')
483     self.assertEqual(self.done.get(True, 1), 'DONE')
484     self.assertEqual(self.done.get(True, 1), 'DONE')
485     self.assertEqual(self.done.get(True, 1), 'DONE')
486     self.ls.acquire(['three', 'four'])
487     Thread(target=self._doRemoveSet, args=(['four', 'six'], )).start()
488     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
489     self.ls.remove('four')
490     self.assertEqual(self.done.get(True, 1), ['six'])
491     Thread(target=self._doRemoveSet, args=(['two'])).start()
492     self.assertEqual(self.done.get(True, 1), ['two'])
493     self.ls.release()
494
495   def testConcurrentSharedSetLock(self):
496     # share the set-lock...
497     self.ls.acquire(None, shared=1)
498     # ...another thread can share it too
499     Thread(target=self._doLockSet, args=(None, 1)).start()
500     self.assertEqual(self.done.get(True, 1), 'DONE')
501     # ...or just share some elements
502     Thread(target=self._doLockSet, args=(['one', 'three'], 1)).start()
503     self.assertEqual(self.done.get(True, 1), 'DONE')
504     # ...but not add new ones or remove any
505     Thread(target=self._doAddSet, args=(['nine'])).start()
506     Thread(target=self._doRemoveSet, args=(['two'], )).start()
507     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
508     # this just releases the set-lock
509     self.ls.release([])
510     self.assertEqual(self.done.get(True, 1), 'DONE')
511     # release the lock on the actual elements so remove() can proceed too
512     self.ls.release()
513     self.assertEqual(self.done.get(True, 1), ['two'])
514
515   def testConcurrentExclusiveSetLock(self):
516     # acquire the set-lock...
517     self.ls.acquire(None, shared=0)
518     # ...no one can do anything else
519     Thread(target=self._doLockSet, args=(None, 1)).start()
520     Thread(target=self._doLockSet, args=(None, 0)).start()
521     Thread(target=self._doLockSet, args=(['three'], 0)).start()
522     Thread(target=self._doLockSet, args=(['two'], 1)).start()
523     Thread(target=self._doAddSet, args=(['nine'])).start()
524     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
525     self.ls.release()
526     self.assertEqual(self.done.get(True, 1), 'DONE')
527     self.assertEqual(self.done.get(True, 1), 'DONE')
528     self.assertEqual(self.done.get(True, 1), 'DONE')
529     self.assertEqual(self.done.get(True, 1), 'DONE')
530     self.assertEqual(self.done.get(True, 1), 'DONE')
531
532   def testEmptyLockSet(self):
533     # get the set-lock
534     self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
535     # now empty it...
536     self.ls.remove(['one', 'two', 'three'])
537     # and adds/locks by another thread still wait
538     Thread(target=self._doAddSet, args=(['nine'])).start()
539     Thread(target=self._doLockSet, args=(None, 1)).start()
540     Thread(target=self._doLockSet, args=(None, 0)).start()
541     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
542     self.ls.release()
543     self.assertEqual(self.done.get(True, 1), 'DONE')
544     self.assertEqual(self.done.get(True, 1), 'DONE')
545     self.assertEqual(self.done.get(True, 1), 'DONE')
546     # empty it again...
547     self.assertEqual(self.ls.remove(['nine']), ['nine'])
548     # now share it...
549     self.assertEqual(self.ls.acquire(None, shared=1), set())
550     # other sharers can go, adds still wait
551     Thread(target=self._doLockSet, args=(None, 1)).start()
552     self.assertEqual(self.done.get(True, 1), 'DONE')
553     Thread(target=self._doAddSet, args=(['nine'])).start()
554     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
555     self.ls.release()
556     self.assertEqual(self.done.get(True, 1), 'DONE')
557
558
559 class TestGanetiLockManager(unittest.TestCase):
560
561   def setUp(self):
562     self.nodes=['n1', 'n2']
563     self.instances=['i1', 'i2', 'i3']
564     self.GL = locking.GanetiLockManager(nodes=self.nodes,
565                                         instances=self.instances)
566     self.done = Queue.Queue(0)
567
568   def tearDown(self):
569     # Don't try this at home...
570     locking.GanetiLockManager._instance = None
571
572   def testLockingConstants(self):
573     # The locking library internally cheats by assuming its constants have some
574     # relationships with each other. Check those hold true.
575     for i in range(len(locking.LEVELS)):
576       self.assertEqual(i, locking.LEVELS[i])
577
578   def testDoubleGLFails(self):
579     self.assertRaises(AssertionError, locking.GanetiLockManager)
580
581   def testLockNames(self):
582     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
583     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
584     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
585                      set(self.instances))
586
587   def testInitAndResources(self):
588     locking.GanetiLockManager._instance = None
589     self.GL = locking.GanetiLockManager()
590     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
591     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
592     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
593
594     locking.GanetiLockManager._instance = None
595     self.GL = locking.GanetiLockManager(nodes=self.nodes)
596     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
597     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
598     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
599
600     locking.GanetiLockManager._instance = None
601     self.GL = locking.GanetiLockManager(instances=self.instances)
602     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
603     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
604     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
605                      set(self.instances))
606
607   def testAcquireRelease(self):
608     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
609     self.assertEquals(self.GL._list_owned(locking.LEVEL_CLUSTER), set(['BGL']))
610     self.GL.acquire(locking.LEVEL_NODE, ['n1', 'n2'], shared=1)
611     self.GL.release(locking.LEVEL_NODE)
612     self.GL.acquire(locking.LEVEL_NODE, ['n1'])
613     self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
614     self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
615     self.GL.release(locking.LEVEL_INSTANCE, ['i2'])
616     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
617     self.GL.release(locking.LEVEL_NODE)
618     self.GL.release(locking.LEVEL_INSTANCE)
619     self.assertRaises(errors.LockError, self.GL.acquire,
620                       locking.LEVEL_INSTANCE, ['i5'])
621     self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
622     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i3']))
623
624   def testBGLDependency(self):
625     self.assertRaises(AssertionError, self.GL.acquire,
626                       locking.LEVEL_NODE, ['n1', 'n2'])
627     self.assertRaises(AssertionError, self.GL.acquire,
628                       locking.LEVEL_INSTANCE, ['i3'])
629     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
630     self.GL.acquire(locking.LEVEL_NODE, ['n1'])
631     self.assertRaises(AssertionError, self.GL.release,
632                       locking.LEVEL_CLUSTER, ['BGL'])
633     self.assertRaises(AssertionError, self.GL.release,
634                       locking.LEVEL_CLUSTER)
635     self.GL.release(locking.LEVEL_NODE)
636     self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
637     self.assertRaises(AssertionError, self.GL.release,
638                       locking.LEVEL_CLUSTER, ['BGL'])
639     self.assertRaises(AssertionError, self.GL.release,
640                       locking.LEVEL_CLUSTER)
641     self.GL.release(locking.LEVEL_INSTANCE)
642
643   def testWrongOrder(self):
644     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
645     self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
646     self.assertRaises(AssertionError, self.GL.acquire,
647                       locking.LEVEL_NODE, ['n1'])
648     self.assertRaises(AssertionError, self.GL.acquire,
649                       locking.LEVEL_INSTANCE, ['i2'])
650
651   # Helper function to run as a thread that shared the BGL and then acquires
652   # some locks at another level.
653   def _doLock(self, level, names, shared):
654     try:
655       self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
656       self.GL.acquire(level, names, shared=shared)
657       self.done.put('DONE')
658       self.GL.release(level)
659       self.GL.release(locking.LEVEL_CLUSTER)
660     except errors.LockError:
661       self.done.put('ERR')
662
663   def testConcurrency(self):
664     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
665     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
666     self.assertEqual(self.done.get(True, 1), 'DONE')
667     self.GL.acquire(locking.LEVEL_NODE, ['n1'])
668     self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
669     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
670     self.assertEqual(self.done.get(True, 1), 'DONE')
671     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i3', 1)).start()
672     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
673     self.GL.release(locking.LEVEL_INSTANCE)
674     self.assertEqual(self.done.get(True, 1), 'DONE')
675     self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)
676     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 1)).start()
677     self.assertEqual(self.done.get(True, 1), 'DONE')
678     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 0)).start()
679     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
680     self.GL.release(locking.LEVEL_INSTANCE)
681     self.assertEqual(self.done.get(True, 1), 'DONE')
682
683
684 if __name__ == '__main__':
685   unittest.main()
686   #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
687   #unittest.TextTestRunner(verbosity=2).run(suite)