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