Fix LockSet._names() to work with the set-lock
[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     self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
397     self.assertEquals(self.ls._is_owned(), True)
398     self.assertEquals(self.ls._names(), set(['one', 'two', 'three']))
399     # I can still add/remove elements...
400     self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
401     self.assert_(self.ls.add('six'))
402     self.ls.release()
403     # share the set-lock
404     self.assertEquals(self.ls.acquire(None, shared=1), set(['one', 'six']))
405     # adding new elements is not possible
406     self.assertRaises(AssertionError, self.ls.add, 'five')
407     self.ls.release()
408
409   def testAcquireWithRepetitions(self):
410     self.assertEquals(self.ls.acquire(['two', 'two', 'three'], shared=1),
411                       set(['two', 'two', 'three']))
412     self.ls.release(['two', 'two'])
413     self.assertEquals(self.ls._list_owned(), set(['three']))
414
415   def testEmptyAcquire(self):
416     # Acquire an empty list of locks...
417     self.assertEquals(self.ls.acquire([]), set())
418     self.assertEquals(self.ls._list_owned(), set())
419     # New locks can still be addded
420     self.assert_(self.ls.add('six'))
421     # "re-acquiring" is not an issue, since we had really acquired nothing
422     self.assertEquals(self.ls.acquire([], shared=1), set())
423     self.assertEquals(self.ls._list_owned(), set())
424     # We haven't really acquired anything, so we cannot release
425     self.assertRaises(AssertionError, self.ls.release)
426
427   def _doLockSet(self, set, shared):
428     try:
429       self.ls.acquire(set, shared=shared)
430       self.done.put('DONE')
431       self.ls.release()
432     except errors.LockError:
433       self.done.put('ERR')
434
435   def _doAddSet(self, set):
436     try:
437       self.ls.add(set, acquired=1)
438       self.done.put('DONE')
439       self.ls.release()
440     except errors.LockError:
441       self.done.put('ERR')
442
443   def _doRemoveSet(self, set):
444     self.done.put(self.ls.remove(set))
445
446   def testConcurrentSharedAcquire(self):
447     self.ls.acquire(['one', 'two'], shared=1)
448     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
449     self.assertEqual(self.done.get(True, 1), 'DONE')
450     Thread(target=self._doLockSet, args=(['one', 'two', 'three'], 1)).start()
451     self.assertEqual(self.done.get(True, 1), 'DONE')
452     Thread(target=self._doLockSet, args=('three', 1)).start()
453     self.assertEqual(self.done.get(True, 1), 'DONE')
454     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
455     Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
456     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
457     self.ls.release()
458     self.assertEqual(self.done.get(True, 1), 'DONE')
459     self.assertEqual(self.done.get(True, 1), 'DONE')
460
461   def testConcurrentExclusiveAcquire(self):
462     self.ls.acquire(['one', 'two'])
463     Thread(target=self._doLockSet, args=('three', 1)).start()
464     self.assertEqual(self.done.get(True, 1), 'DONE')
465     Thread(target=self._doLockSet, args=('three', 0)).start()
466     self.assertEqual(self.done.get(True, 1), 'DONE')
467     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
468     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
469     Thread(target=self._doLockSet, args=('one', 0)).start()
470     Thread(target=self._doLockSet, args=('one', 1)).start()
471     Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
472     Thread(target=self._doLockSet, args=(['two', 'three'], 1)).start()
473     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
474     self.ls.release()
475     self.assertEqual(self.done.get(True, 1), 'DONE')
476     self.assertEqual(self.done.get(True, 1), 'DONE')
477     self.assertEqual(self.done.get(True, 1), 'DONE')
478     self.assertEqual(self.done.get(True, 1), 'DONE')
479     self.assertEqual(self.done.get(True, 1), 'DONE')
480     self.assertEqual(self.done.get(True, 1), 'DONE')
481
482   def testConcurrentRemove(self):
483     self.ls.add('four')
484     self.ls.acquire(['one', 'two', 'four'])
485     Thread(target=self._doLockSet, args=(['one', 'four'], 0)).start()
486     Thread(target=self._doLockSet, args=(['one', 'four'], 1)).start()
487     Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
488     Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
489     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
490     self.ls.remove('one')
491     self.ls.release()
492     self.assertEqual(self.done.get(True, 1), 'ERR')
493     self.assertEqual(self.done.get(True, 1), 'ERR')
494     self.assertEqual(self.done.get(True, 1), 'ERR')
495     self.assertEqual(self.done.get(True, 1), 'ERR')
496     self.ls.add(['five', 'six'], acquired=1)
497     Thread(target=self._doLockSet, args=(['three', 'six'], 1)).start()
498     Thread(target=self._doLockSet, args=(['three', 'six'], 0)).start()
499     Thread(target=self._doLockSet, args=(['four', 'six'], 1)).start()
500     Thread(target=self._doLockSet, args=(['four', 'six'], 0)).start()
501     self.ls.remove('five')
502     self.ls.release()
503     self.assertEqual(self.done.get(True, 1), 'DONE')
504     self.assertEqual(self.done.get(True, 1), 'DONE')
505     self.assertEqual(self.done.get(True, 1), 'DONE')
506     self.assertEqual(self.done.get(True, 1), 'DONE')
507     self.ls.acquire(['three', 'four'])
508     Thread(target=self._doRemoveSet, args=(['four', 'six'], )).start()
509     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
510     self.ls.remove('four')
511     self.assertEqual(self.done.get(True, 1), ['six'])
512     Thread(target=self._doRemoveSet, args=(['two'])).start()
513     self.assertEqual(self.done.get(True, 1), ['two'])
514     self.ls.release()
515
516   def testConcurrentSharedSetLock(self):
517     # share the set-lock...
518     self.ls.acquire(None, shared=1)
519     # ...another thread can share it too
520     Thread(target=self._doLockSet, args=(None, 1)).start()
521     self.assertEqual(self.done.get(True, 1), 'DONE')
522     # ...or just share some elements
523     Thread(target=self._doLockSet, args=(['one', 'three'], 1)).start()
524     self.assertEqual(self.done.get(True, 1), 'DONE')
525     # ...but not add new ones or remove any
526     Thread(target=self._doAddSet, args=(['nine'])).start()
527     Thread(target=self._doRemoveSet, args=(['two'], )).start()
528     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
529     # this just releases the set-lock
530     self.ls.release([])
531     self.assertEqual(self.done.get(True, 1), 'DONE')
532     # release the lock on the actual elements so remove() can proceed too
533     self.ls.release()
534     self.assertEqual(self.done.get(True, 1), ['two'])
535
536   def testConcurrentExclusiveSetLock(self):
537     # acquire the set-lock...
538     self.ls.acquire(None, shared=0)
539     # ...no one can do anything else
540     Thread(target=self._doLockSet, args=(None, 1)).start()
541     Thread(target=self._doLockSet, args=(None, 0)).start()
542     Thread(target=self._doLockSet, args=(['three'], 0)).start()
543     Thread(target=self._doLockSet, args=(['two'], 1)).start()
544     Thread(target=self._doAddSet, args=(['nine'])).start()
545     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
546     self.ls.release()
547     self.assertEqual(self.done.get(True, 1), 'DONE')
548     self.assertEqual(self.done.get(True, 1), 'DONE')
549     self.assertEqual(self.done.get(True, 1), 'DONE')
550     self.assertEqual(self.done.get(True, 1), 'DONE')
551     self.assertEqual(self.done.get(True, 1), 'DONE')
552
553   def testEmptyLockSet(self):
554     # get the set-lock
555     self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
556     # now empty it...
557     self.ls.remove(['one', 'two', 'three'])
558     # and adds/locks by another thread still wait
559     Thread(target=self._doAddSet, args=(['nine'])).start()
560     Thread(target=self._doLockSet, args=(None, 1)).start()
561     Thread(target=self._doLockSet, args=(None, 0)).start()
562     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
563     self.ls.release()
564     self.assertEqual(self.done.get(True, 1), 'DONE')
565     self.assertEqual(self.done.get(True, 1), 'DONE')
566     self.assertEqual(self.done.get(True, 1), 'DONE')
567     # empty it again...
568     self.assertEqual(self.ls.remove(['nine']), ['nine'])
569     # now share it...
570     self.assertEqual(self.ls.acquire(None, shared=1), set())
571     # other sharers can go, adds still wait
572     Thread(target=self._doLockSet, args=(None, 1)).start()
573     self.assertEqual(self.done.get(True, 1), 'DONE')
574     Thread(target=self._doAddSet, args=(['nine'])).start()
575     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
576     self.ls.release()
577     self.assertEqual(self.done.get(True, 1), 'DONE')
578
579
580 class TestGanetiLockManager(unittest.TestCase):
581
582   def setUp(self):
583     self.nodes=['n1', 'n2']
584     self.instances=['i1', 'i2', 'i3']
585     self.GL = locking.GanetiLockManager(nodes=self.nodes,
586                                         instances=self.instances)
587     self.done = Queue.Queue(0)
588
589   def tearDown(self):
590     # Don't try this at home...
591     locking.GanetiLockManager._instance = None
592
593   def testLockingConstants(self):
594     # The locking library internally cheats by assuming its constants have some
595     # relationships with each other. Check those hold true.
596     # This relationship is also used in the Processor to recursively acquire
597     # the right locks. Again, please don't break it.
598     for i in range(len(locking.LEVELS)):
599       self.assertEqual(i, locking.LEVELS[i])
600
601   def testDoubleGLFails(self):
602     self.assertRaises(AssertionError, locking.GanetiLockManager)
603
604   def testLockNames(self):
605     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
606     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
607     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
608                      set(self.instances))
609
610   def testInitAndResources(self):
611     locking.GanetiLockManager._instance = None
612     self.GL = locking.GanetiLockManager()
613     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
614     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
615     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
616
617     locking.GanetiLockManager._instance = None
618     self.GL = locking.GanetiLockManager(nodes=self.nodes)
619     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
620     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
621     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
622
623     locking.GanetiLockManager._instance = None
624     self.GL = locking.GanetiLockManager(instances=self.instances)
625     self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
626     self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
627     self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
628                      set(self.instances))
629
630   def testAcquireRelease(self):
631     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
632     self.assertEquals(self.GL._list_owned(locking.LEVEL_CLUSTER), set(['BGL']))
633     self.GL.acquire(locking.LEVEL_INSTANCE, ['i1'])
634     self.GL.acquire(locking.LEVEL_NODE, ['n1', 'n2'], shared=1)
635     self.GL.release(locking.LEVEL_NODE, ['n2'])
636     self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
637     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
638     self.GL.release(locking.LEVEL_NODE)
639     self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set())
640     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
641     self.GL.release(locking.LEVEL_INSTANCE)
642     self.assertRaises(errors.LockError, self.GL.acquire,
643                       locking.LEVEL_INSTANCE, ['i5'])
644     self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
645     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i3']))
646
647   def testAcquireWholeSets(self):
648     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
649     self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
650                       set(self.instances))
651     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
652                       set(self.instances))
653     self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, None, shared=1),
654                       set(self.nodes))
655     self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
656                       set(self.nodes))
657     self.GL.release(locking.LEVEL_NODE)
658     self.GL.release(locking.LEVEL_INSTANCE)
659     self.GL.release(locking.LEVEL_CLUSTER)
660
661   def testAcquireWholeAndPartial(self):
662     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
663     self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
664                       set(self.instances))
665     self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
666                       set(self.instances))
667     self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, ['n2'], shared=1),
668                       set(['n2']))
669     self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
670                       set(['n2']))
671     self.GL.release(locking.LEVEL_NODE)
672     self.GL.release(locking.LEVEL_INSTANCE)
673     self.GL.release(locking.LEVEL_CLUSTER)
674
675   def testBGLDependency(self):
676     self.assertRaises(AssertionError, self.GL.acquire,
677                       locking.LEVEL_NODE, ['n1', 'n2'])
678     self.assertRaises(AssertionError, self.GL.acquire,
679                       locking.LEVEL_INSTANCE, ['i3'])
680     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
681     self.GL.acquire(locking.LEVEL_NODE, ['n1'])
682     self.assertRaises(AssertionError, self.GL.release,
683                       locking.LEVEL_CLUSTER, ['BGL'])
684     self.assertRaises(AssertionError, self.GL.release,
685                       locking.LEVEL_CLUSTER)
686     self.GL.release(locking.LEVEL_NODE)
687     self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
688     self.assertRaises(AssertionError, self.GL.release,
689                       locking.LEVEL_CLUSTER, ['BGL'])
690     self.assertRaises(AssertionError, self.GL.release,
691                       locking.LEVEL_CLUSTER)
692     self.GL.release(locking.LEVEL_INSTANCE)
693
694   def testWrongOrder(self):
695     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
696     self.GL.acquire(locking.LEVEL_NODE, ['n2'])
697     self.assertRaises(AssertionError, self.GL.acquire,
698                       locking.LEVEL_NODE, ['n1'])
699     self.assertRaises(AssertionError, self.GL.acquire,
700                       locking.LEVEL_INSTANCE, ['i2'])
701
702   # Helper function to run as a thread that shared the BGL and then acquires
703   # some locks at another level.
704   def _doLock(self, level, names, shared):
705     try:
706       self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
707       self.GL.acquire(level, names, shared=shared)
708       self.done.put('DONE')
709       self.GL.release(level)
710       self.GL.release(locking.LEVEL_CLUSTER)
711     except errors.LockError:
712       self.done.put('ERR')
713
714   def testConcurrency(self):
715     self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
716     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
717     self.assertEqual(self.done.get(True, 1), 'DONE')
718     self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
719     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
720     self.assertEqual(self.done.get(True, 1), 'DONE')
721     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i3', 1)).start()
722     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
723     self.GL.release(locking.LEVEL_INSTANCE)
724     self.assertEqual(self.done.get(True, 1), 'DONE')
725     self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)
726     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 1)).start()
727     self.assertEqual(self.done.get(True, 1), 'DONE')
728     Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 0)).start()
729     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
730     self.GL.release(locking.LEVEL_INSTANCE)
731     self.assertEqual(self.done.get(True, 1), 'DONE')
732
733
734 if __name__ == '__main__':
735   unittest.main()
736   #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
737   #unittest.TextTestRunner(verbosity=2).run(suite)