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