Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.locking_unittest.py @ 42a999d1

History | View | Annotate | Download (27.9 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 0.0510-1301, USA.
20

    
21

    
22
"""Script for unittesting the locking module"""
23

    
24

    
25
import os
26
import unittest
27
import time
28
import Queue
29

    
30
from ganeti import locking
31
from ganeti import errors
32
from threading import Thread
33

    
34

    
35
# This is used to test the ssynchronize decorator.
36
# Since it's passed as input to a decorator it must be declared as a global.
37
_decoratorlock = locking.SharedLock()
38

    
39

    
40
class TestSharedLock(unittest.TestCase):
41
  """SharedLock tests"""
42

    
43
  def setUp(self):
44
    self.sl = locking.SharedLock()
45
    # helper threads use the 'done' queue to tell the master they finished.
46
    self.done = Queue.Queue(0)
47

    
48
  def testSequenceAndOwnership(self):
49
    self.assert_(not self.sl._is_owned())
50
    self.sl.acquire(shared=1)
51
    self.assert_(self.sl._is_owned())
52
    self.assert_(self.sl._is_owned(shared=1))
53
    self.assert_(not self.sl._is_owned(shared=0))
54
    self.sl.release()
55
    self.assert_(not self.sl._is_owned())
56
    self.sl.acquire()
57
    self.assert_(self.sl._is_owned())
58
    self.assert_(not self.sl._is_owned(shared=1))
59
    self.assert_(self.sl._is_owned(shared=0))
60
    self.sl.release()
61
    self.assert_(not self.sl._is_owned())
62
    self.sl.acquire(shared=1)
63
    self.assert_(self.sl._is_owned())
64
    self.assert_(self.sl._is_owned(shared=1))
65
    self.assert_(not self.sl._is_owned(shared=0))
66
    self.sl.release()
67
    self.assert_(not self.sl._is_owned())
68

    
69
  def testBooleanValue(self):
70
    # semaphores are supposed to return a true value on a successful acquire
71
    self.assert_(self.sl.acquire(shared=1))
72
    self.sl.release()
73
    self.assert_(self.sl.acquire())
74
    self.sl.release()
75

    
76
  def testDoubleLockingStoE(self):
77
    self.sl.acquire(shared=1)
78
    self.assertRaises(AssertionError, self.sl.acquire)
79

    
80
  def testDoubleLockingEtoS(self):
81
    self.sl.acquire()
82
    self.assertRaises(AssertionError, self.sl.acquire, shared=1)
83

    
84
  def testDoubleLockingStoS(self):
85
    self.sl.acquire(shared=1)
86
    self.assertRaises(AssertionError, self.sl.acquire, shared=1)
87

    
88
  def testDoubleLockingEtoE(self):
89
    self.sl.acquire()
90
    self.assertRaises(AssertionError, self.sl.acquire)
91

    
92
  # helper functions: called in a separate thread they acquire the lock, send
93
  # their identifier on the done queue, then release it.
94
  def _doItSharer(self):
95
    try:
96
      self.sl.acquire(shared=1)
97
      self.done.put('SHR')
98
      self.sl.release()
99
    except errors.LockError:
100
      self.done.put('ERR')
101

    
102
  def _doItExclusive(self):
103
    try:
104
      self.sl.acquire()
105
      self.done.put('EXC')
106
      self.sl.release()
107
    except errors.LockError:
108
      self.done.put('ERR')
109

    
110
  def _doItDelete(self):
111
    try:
112
      self.sl.delete()
113
      self.done.put('DEL')
114
    except errors.LockError:
115
      self.done.put('ERR')
116

    
117
  def testSharersCanCoexist(self):
118
    self.sl.acquire(shared=1)
119
    Thread(target=self._doItSharer).start()
120
    self.assert_(self.done.get(True, 1))
121
    self.sl.release()
122

    
123
  def testExclusiveBlocksExclusive(self):
124
    self.sl.acquire()
125
    Thread(target=self._doItExclusive).start()
126
    # give it a bit of time to check that it's not actually doing anything
127
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
128
    self.sl.release()
129
    self.assert_(self.done.get(True, 1))
130

    
131
  def testExclusiveBlocksDelete(self):
132
    self.sl.acquire()
133
    Thread(target=self._doItDelete).start()
134
    # give it a bit of time to check that it's not actually doing anything
135
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
136
    self.sl.release()
137
    self.assert_(self.done.get(True, 1))
138

    
139
  def testExclusiveBlocksSharer(self):
140
    self.sl.acquire()
141
    Thread(target=self._doItSharer).start()
142
    time.sleep(0.05)
143
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
144
    self.sl.release()
145
    self.assert_(self.done.get(True, 1))
146

    
147
  def testSharerBlocksExclusive(self):
148
    self.sl.acquire(shared=1)
149
    Thread(target=self._doItExclusive).start()
150
    time.sleep(0.05)
151
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
152
    self.sl.release()
153
    self.assert_(self.done.get(True, 1))
154

    
155
  def testSharerBlocksDelete(self):
156
    self.sl.acquire(shared=1)
157
    Thread(target=self._doItDelete).start()
158
    time.sleep(0.05)
159
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
160
    self.sl.release()
161
    self.assert_(self.done.get(True, 1))
162

    
163
  def testWaitingExclusiveBlocksSharer(self):
164
    self.sl.acquire(shared=1)
165
    # the lock is acquired in shared mode...
166
    Thread(target=self._doItExclusive).start()
167
    # ...but now an exclusive is waiting...
168
    time.sleep(0.05)
169
    Thread(target=self._doItSharer).start()
170
    # ...so the sharer should be blocked as well
171
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
172
    self.sl.release()
173
    # The exclusive passed before
174
    self.assertEqual(self.done.get(True, 1), 'EXC')
175
    self.assertEqual(self.done.get(True, 1), 'SHR')
176

    
177
  def testWaitingSharerBlocksExclusive(self):
178
    self.sl.acquire()
179
    # the lock is acquired in exclusive mode...
180
    Thread(target=self._doItSharer).start()
181
    # ...but now a sharer is waiting...
182
    time.sleep(0.05)
183
    Thread(target=self._doItExclusive).start()
184
    # ...the exclusive is waiting too...
185
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
186
    self.sl.release()
187
    # The sharer passed before
188
    self.assertEqual(self.done.get(True, 1), 'SHR')
189
    self.assertEqual(self.done.get(True, 1), 'EXC')
190

    
191
  def testNoNonBlocking(self):
192
    self.assertRaises(NotImplementedError, self.sl.acquire, blocking=0)
193
    self.assertRaises(NotImplementedError, self.sl.delete, blocking=0)
194
    self.sl.acquire()
195
    self.sl.delete(blocking=0) # Fine, because the lock is already acquired
196

    
197
  def testDelete(self):
198
    self.sl.delete()
199
    self.assertRaises(errors.LockError, self.sl.acquire)
200
    self.assertRaises(errors.LockError, self.sl.acquire, shared=1)
201
    self.assertRaises(errors.LockError, self.sl.delete)
202

    
203
  def testNoDeleteIfSharer(self):
204
    self.sl.acquire(shared=1)
205
    self.assertRaises(AssertionError, self.sl.delete)
206

    
207
  def testDeletePendingSharersExclusiveDelete(self):
208
    self.sl.acquire()
209
    Thread(target=self._doItSharer).start()
210
    Thread(target=self._doItSharer).start()
211
    time.sleep(0.05)
212
    Thread(target=self._doItExclusive).start()
213
    Thread(target=self._doItDelete).start()
214
    time.sleep(0.05)
215
    self.sl.delete()
216
    # The two threads who were pending return both ERR
217
    self.assertEqual(self.done.get(True, 1), 'ERR')
218
    self.assertEqual(self.done.get(True, 1), 'ERR')
219
    self.assertEqual(self.done.get(True, 1), 'ERR')
220
    self.assertEqual(self.done.get(True, 1), 'ERR')
221

    
222
  def testDeletePendingDeleteExclusiveSharers(self):
223
    self.sl.acquire()
224
    Thread(target=self._doItDelete).start()
225
    Thread(target=self._doItExclusive).start()
226
    time.sleep(0.05)
227
    Thread(target=self._doItSharer).start()
228
    Thread(target=self._doItSharer).start()
229
    time.sleep(0.05)
230
    self.sl.delete()
231
    # The two threads who were pending return both ERR
232
    self.assertEqual(self.done.get(True, 1), 'ERR')
233
    self.assertEqual(self.done.get(True, 1), 'ERR')
234
    self.assertEqual(self.done.get(True, 1), 'ERR')
235
    self.assertEqual(self.done.get(True, 1), 'ERR')
236

    
237

    
238
class TestSSynchronizedDecorator(unittest.TestCase):
239
  """Shared Lock Synchronized decorator test"""
240

    
241
  def setUp(self):
242
    # helper threads use the 'done' queue to tell the master they finished.
243
    self.done = Queue.Queue(0)
244

    
245
  @locking.ssynchronized(_decoratorlock)
246
  def _doItExclusive(self):
247
    self.assert_(_decoratorlock._is_owned())
248
    self.done.put('EXC')
249

    
250
  @locking.ssynchronized(_decoratorlock, shared=1)
251
  def _doItSharer(self):
252
    self.assert_(_decoratorlock._is_owned(shared=1))
253
    self.done.put('SHR')
254

    
255
  def testDecoratedFunctions(self):
256
    self._doItExclusive()
257
    self.assert_(not _decoratorlock._is_owned())
258
    self._doItSharer()
259
    self.assert_(not _decoratorlock._is_owned())
260

    
261
  def testSharersCanCoexist(self):
262
    _decoratorlock.acquire(shared=1)
263
    Thread(target=self._doItSharer).start()
264
    self.assert_(self.done.get(True, 1))
265
    _decoratorlock.release()
266

    
267
  def testExclusiveBlocksExclusive(self):
268
    _decoratorlock.acquire()
269
    Thread(target=self._doItExclusive).start()
270
    # give it a bit of time to check that it's not actually doing anything
271
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
272
    _decoratorlock.release()
273
    self.assert_(self.done.get(True, 1))
274

    
275
  def testExclusiveBlocksSharer(self):
276
    _decoratorlock.acquire()
277
    Thread(target=self._doItSharer).start()
278
    time.sleep(0.05)
279
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
280
    _decoratorlock.release()
281
    self.assert_(self.done.get(True, 1))
282

    
283
  def testSharerBlocksExclusive(self):
284
    _decoratorlock.acquire(shared=1)
285
    Thread(target=self._doItExclusive).start()
286
    time.sleep(0.05)
287
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
288
    _decoratorlock.release()
289
    self.assert_(self.done.get(True, 1))
290

    
291

    
292
class TestLockSet(unittest.TestCase):
293
  """LockSet tests"""
294

    
295
  def setUp(self):
296
    self.resources = ['one', 'two', 'three']
297
    self.ls = locking.LockSet(members=self.resources)
298
    # helper threads use the 'done' queue to tell the master they finished.
299
    self.done = Queue.Queue(0)
300

    
301
  def testResources(self):
302
    self.assertEquals(self.ls._names(), set(self.resources))
303
    newls = locking.LockSet()
304
    self.assertEquals(newls._names(), set())
305

    
306
  def testAcquireRelease(self):
307
    self.assert_(self.ls.acquire('one'))
308
    self.assertEquals(self.ls._list_owned(), set(['one']))
309
    self.ls.release()
310
    self.assertEquals(self.ls._list_owned(), set())
311
    self.assertEquals(self.ls.acquire(['one']), set(['one']))
312
    self.assertEquals(self.ls._list_owned(), set(['one']))
313
    self.ls.release()
314
    self.assertEquals(self.ls._list_owned(), set())
315
    self.ls.acquire(['one', 'two', 'three'])
316
    self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
317
    self.ls.release('one')
318
    self.assertEquals(self.ls._list_owned(), set(['two', 'three']))
319
    self.ls.release(['three'])
320
    self.assertEquals(self.ls._list_owned(), set(['two']))
321
    self.ls.release()
322
    self.assertEquals(self.ls._list_owned(), set())
323
    self.assertEquals(self.ls.acquire(['one', 'three']), set(['one', 'three']))
324
    self.assertEquals(self.ls._list_owned(), set(['one', 'three']))
325
    self.ls.release()
326
    self.assertEquals(self.ls._list_owned(), set())
327

    
328
  def testNoDoubleAcquire(self):
329
    self.ls.acquire('one')
330
    self.assertRaises(AssertionError, self.ls.acquire, 'one')
331
    self.assertRaises(AssertionError, self.ls.acquire, ['two'])
332
    self.assertRaises(AssertionError, self.ls.acquire, ['two', 'three'])
333
    self.ls.release()
334
    self.ls.acquire(['one', 'three'])
335
    self.ls.release('one')
336
    self.assertRaises(AssertionError, self.ls.acquire, ['two'])
337
    self.ls.release('three')
338

    
339
  def testNoWrongRelease(self):
340
    self.assertRaises(AssertionError, self.ls.release)
341
    self.ls.acquire('one')
342
    self.assertRaises(AssertionError, self.ls.release, 'two')
343

    
344
  def testAddRemove(self):
345
    self.ls.add('four')
346
    self.assertEquals(self.ls._list_owned(), set())
347
    self.assert_('four' in self.ls._names())
348
    self.ls.add(['five', 'six', 'seven'], acquired=1)
349
    self.assert_('five' in self.ls._names())
350
    self.assert_('six' in self.ls._names())
351
    self.assert_('seven' in self.ls._names())
352
    self.assertEquals(self.ls._list_owned(), set(['five', 'six', 'seven']))
353
    self.assertEquals(self.ls.remove(['five', 'six']), ['five', 'six'])
354
    self.assert_('five' not in self.ls._names())
355
    self.assert_('six' not in self.ls._names())
356
    self.assertEquals(self.ls._list_owned(), set(['seven']))
357
    self.ls.add('eight', acquired=1, shared=1)
358
    self.assert_('eight' in self.ls._names())
359
    self.assertEquals(self.ls._list_owned(), set(['seven', 'eight']))
360
    self.ls.remove('seven')
361
    self.assert_('seven' not in self.ls._names())
362
    self.assertEquals(self.ls._list_owned(), set(['eight']))
363
    self.ls.release()
364
    self.ls.remove(['two'])
365
    self.assert_('two' not in self.ls._names())
366
    self.ls.acquire('three')
367
    self.assertEquals(self.ls.remove(['three']), ['three'])
368
    self.assert_('three' not in self.ls._names())
369
    self.assertEquals(self.ls.remove('three'), [])
370
    self.assertEquals(self.ls.remove(['one', 'three', 'six']), ['one'])
371
    self.assert_('one' not in self.ls._names())
372

    
373
  def testRemoveNonBlocking(self):
374
    self.assertRaises(NotImplementedError, self.ls.remove, 'one', blocking=0)
375
    self.ls.acquire('one')
376
    self.assertEquals(self.ls.remove('one', blocking=0), ['one'])
377
    self.ls.acquire(['two', 'three'])
378
    self.assertEquals(self.ls.remove(['two', 'three'], blocking=0),
379
                      ['two', 'three'])
380

    
381
  def testNoDoubleAdd(self):
382
    self.assertRaises(errors.LockError, self.ls.add, 'two')
383
    self.ls.add('four')
384
    self.assertRaises(errors.LockError, self.ls.add, 'four')
385

    
386
  def testNoWrongRemoves(self):
387
    self.ls.acquire(['one', 'three'], shared=1)
388
    # Cannot remove 'two' while holding something which is not a superset
389
    self.assertRaises(AssertionError, self.ls.remove, 'two')
390
    # Cannot remove 'three' as we are sharing it
391
    self.assertRaises(AssertionError, self.ls.remove, 'three')
392

    
393
  def testAcquireSetLock(self):
394
    # acquire the set-lock exclusively
395
    self.assertEquals(self.ls.acquire(None), set(['one', 'two', 'three']))
396
    # I can still add/remove elements...
397
    self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
398
    self.assert_(self.ls.add('six'))
399
    self.ls.release()
400
    # share the set-lock
401
    self.assertEquals(self.ls.acquire(None, shared=1), set(['one', 'six']))
402
    # adding new elements is not possible
403
    self.assertRaises(AssertionError, self.ls.add, 'five')
404
    self.ls.release()
405

    
406
  def _doLockSet(self, set, shared):
407
    try:
408
      self.ls.acquire(set, shared=shared)
409
      self.done.put('DONE')
410
      self.ls.release()
411
    except errors.LockError:
412
      self.done.put('ERR')
413

    
414
  def _doAddSet(self, set):
415
    try:
416
      self.ls.add(set, acquired=1)
417
      self.done.put('DONE')
418
      self.ls.release()
419
    except errors.LockError:
420
      self.done.put('ERR')
421

    
422
  def _doRemoveSet(self, set):
423
    self.done.put(self.ls.remove(set))
424

    
425
  def testConcurrentSharedAcquire(self):
426
    self.ls.acquire(['one', 'two'], shared=1)
427
    Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
428
    self.assertEqual(self.done.get(True, 1), 'DONE')
429
    Thread(target=self._doLockSet, args=(['one', 'two', 'three'], 1)).start()
430
    self.assertEqual(self.done.get(True, 1), 'DONE')
431
    Thread(target=self._doLockSet, args=('three', 1)).start()
432
    self.assertEqual(self.done.get(True, 1), 'DONE')
433
    Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
434
    Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
435
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
436
    self.ls.release()
437
    self.assertEqual(self.done.get(True, 1), 'DONE')
438
    self.assertEqual(self.done.get(True, 1), 'DONE')
439

    
440
  def testConcurrentExclusiveAcquire(self):
441
    self.ls.acquire(['one', 'two'])
442
    Thread(target=self._doLockSet, args=('three', 1)).start()
443
    self.assertEqual(self.done.get(True, 1), 'DONE')
444
    Thread(target=self._doLockSet, args=('three', 0)).start()
445
    self.assertEqual(self.done.get(True, 1), 'DONE')
446
    Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
447
    Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
448
    Thread(target=self._doLockSet, args=('one', 0)).start()
449
    Thread(target=self._doLockSet, args=('one', 1)).start()
450
    Thread(target=self._doLockSet, args=(['two', 'three'], 0)).start()
451
    Thread(target=self._doLockSet, args=(['two', 'three'], 1)).start()
452
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
453
    self.ls.release()
454
    self.assertEqual(self.done.get(True, 1), 'DONE')
455
    self.assertEqual(self.done.get(True, 1), 'DONE')
456
    self.assertEqual(self.done.get(True, 1), 'DONE')
457
    self.assertEqual(self.done.get(True, 1), 'DONE')
458
    self.assertEqual(self.done.get(True, 1), 'DONE')
459
    self.assertEqual(self.done.get(True, 1), 'DONE')
460

    
461
  def testConcurrentRemove(self):
462
    self.ls.add('four')
463
    self.ls.acquire(['one', 'two', 'four'])
464
    Thread(target=self._doLockSet, args=(['one', 'four'], 0)).start()
465
    Thread(target=self._doLockSet, args=(['one', 'four'], 1)).start()
466
    Thread(target=self._doLockSet, args=(['one', 'two'], 0)).start()
467
    Thread(target=self._doLockSet, args=(['one', 'two'], 1)).start()
468
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
469
    self.ls.remove('one')
470
    self.ls.release()
471
    self.assertEqual(self.done.get(True, 1), 'ERR')
472
    self.assertEqual(self.done.get(True, 1), 'ERR')
473
    self.assertEqual(self.done.get(True, 1), 'ERR')
474
    self.assertEqual(self.done.get(True, 1), 'ERR')
475
    self.ls.add(['five', 'six'], acquired=1)
476
    Thread(target=self._doLockSet, args=(['three', 'six'], 1)).start()
477
    Thread(target=self._doLockSet, args=(['three', 'six'], 0)).start()
478
    Thread(target=self._doLockSet, args=(['four', 'six'], 1)).start()
479
    Thread(target=self._doLockSet, args=(['four', 'six'], 0)).start()
480
    self.ls.remove('five')
481
    self.ls.release()
482
    self.assertEqual(self.done.get(True, 1), 'DONE')
483
    self.assertEqual(self.done.get(True, 1), 'DONE')
484
    self.assertEqual(self.done.get(True, 1), 'DONE')
485
    self.assertEqual(self.done.get(True, 1), 'DONE')
486
    self.ls.acquire(['three', 'four'])
487
    Thread(target=self._doRemoveSet, args=(['four', 'six'], )).start()
488
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
489
    self.ls.remove('four')
490
    self.assertEqual(self.done.get(True, 1), ['six'])
491
    Thread(target=self._doRemoveSet, args=(['two'])).start()
492
    self.assertEqual(self.done.get(True, 1), ['two'])
493
    self.ls.release()
494

    
495
  def testConcurrentSharedSetLock(self):
496
    # share the set-lock...
497
    self.ls.acquire(None, shared=1)
498
    # ...another thread can share it too
499
    Thread(target=self._doLockSet, args=(None, 1)).start()
500
    self.assertEqual(self.done.get(True, 1), 'DONE')
501
    # ...or just share some elements
502
    Thread(target=self._doLockSet, args=(['one', 'three'], 1)).start()
503
    self.assertEqual(self.done.get(True, 1), 'DONE')
504
    # ...but not add new ones or remove any
505
    Thread(target=self._doAddSet, args=(['nine'])).start()
506
    Thread(target=self._doRemoveSet, args=(['two'], )).start()
507
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
508
    # this just releases the set-lock
509
    self.ls.release([])
510
    self.assertEqual(self.done.get(True, 1), 'DONE')
511
    # release the lock on the actual elements so remove() can proceed too
512
    self.ls.release()
513
    self.assertEqual(self.done.get(True, 1), ['two'])
514

    
515
  def testConcurrentExclusiveSetLock(self):
516
    # acquire the set-lock...
517
    self.ls.acquire(None, shared=0)
518
    # ...no one can do anything else
519
    Thread(target=self._doLockSet, args=(None, 1)).start()
520
    Thread(target=self._doLockSet, args=(None, 0)).start()
521
    Thread(target=self._doLockSet, args=(['three'], 0)).start()
522
    Thread(target=self._doLockSet, args=(['two'], 1)).start()
523
    Thread(target=self._doAddSet, args=(['nine'])).start()
524
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
525
    self.ls.release()
526
    self.assertEqual(self.done.get(True, 1), 'DONE')
527
    self.assertEqual(self.done.get(True, 1), 'DONE')
528
    self.assertEqual(self.done.get(True, 1), 'DONE')
529
    self.assertEqual(self.done.get(True, 1), 'DONE')
530
    self.assertEqual(self.done.get(True, 1), 'DONE')
531

    
532
  def testEmptyLockSet(self):
533
    # get the set-lock
534
    self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
535
    # now empty it...
536
    self.ls.remove(['one', 'two', 'three'])
537
    # and adds/locks by another thread still wait
538
    Thread(target=self._doAddSet, args=(['nine'])).start()
539
    Thread(target=self._doLockSet, args=(None, 1)).start()
540
    Thread(target=self._doLockSet, args=(None, 0)).start()
541
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
542
    self.ls.release()
543
    self.assertEqual(self.done.get(True, 1), 'DONE')
544
    self.assertEqual(self.done.get(True, 1), 'DONE')
545
    self.assertEqual(self.done.get(True, 1), 'DONE')
546
    # empty it again...
547
    self.assertEqual(self.ls.remove(['nine']), ['nine'])
548
    # now share it...
549
    self.assertEqual(self.ls.acquire(None, shared=1), set())
550
    # other sharers can go, adds still wait
551
    Thread(target=self._doLockSet, args=(None, 1)).start()
552
    self.assertEqual(self.done.get(True, 1), 'DONE')
553
    Thread(target=self._doAddSet, args=(['nine'])).start()
554
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
555
    self.ls.release()
556
    self.assertEqual(self.done.get(True, 1), 'DONE')
557

    
558

    
559
class TestGanetiLockManager(unittest.TestCase):
560

    
561
  def setUp(self):
562
    self.nodes=['n1', 'n2']
563
    self.instances=['i1', 'i2', 'i3']
564
    self.GL = locking.GanetiLockManager(nodes=self.nodes,
565
                                        instances=self.instances)
566
    self.done = Queue.Queue(0)
567

    
568
  def tearDown(self):
569
    # Don't try this at home...
570
    locking.GanetiLockManager._instance = None
571

    
572
  def testLockingConstants(self):
573
    # The locking library internally cheats by assuming its constants have some
574
    # relationships with each other. Check those hold true.
575
    for i in range(len(locking.LEVELS)):
576
      self.assertEqual(i, locking.LEVELS[i])
577

    
578
  def testDoubleGLFails(self):
579
    self.assertRaises(AssertionError, locking.GanetiLockManager)
580

    
581
  def testLockNames(self):
582
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
583
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
584
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
585
                     set(self.instances))
586
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
587

    
588
  def testInitAndResources(self):
589
    locking.GanetiLockManager._instance = None
590
    self.GL = locking.GanetiLockManager()
591
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
592
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
593
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
594
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
595

    
596
    locking.GanetiLockManager._instance = None
597
    self.GL = locking.GanetiLockManager(nodes=self.nodes)
598
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
599
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
600
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
601
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
602

    
603
    locking.GanetiLockManager._instance = None
604
    self.GL = locking.GanetiLockManager(instances=self.instances)
605
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
606
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
607
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
608
                     set(self.instances))
609
    self.assertEqual(self.GL._names(locking.LEVEL_CONFIG), set(['config']))
610

    
611
  def testAcquireRelease(self):
612
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
613
    self.assertEquals(self.GL._list_owned(locking.LEVEL_CLUSTER), set(['BGL']))
614
    self.GL.acquire(locking.LEVEL_NODE, ['n1', 'n2'], shared=1)
615
    self.GL.release(locking.LEVEL_NODE)
616
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
617
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
618
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
619
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
620
    self.GL.release(locking.LEVEL_INSTANCE, ['i2'])
621
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
622
    self.GL.release(locking.LEVEL_NODE)
623
    self.GL.release(locking.LEVEL_INSTANCE)
624
    self.GL.release(locking.LEVEL_CONFIG)
625
    self.assertRaises(errors.LockError, self.GL.acquire,
626
                      locking.LEVEL_INSTANCE, ['i5'])
627
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
628
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i3']))
629

    
630
  def testBGLDependency(self):
631
    self.assertRaises(AssertionError, self.GL.acquire,
632
                      locking.LEVEL_NODE, ['n1', 'n2'])
633
    self.assertRaises(AssertionError, self.GL.acquire,
634
                      locking.LEVEL_INSTANCE, ['i3'])
635
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
636
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
637
    self.assertRaises(AssertionError, self.GL.release,
638
                      locking.LEVEL_CLUSTER, ['BGL'])
639
    self.assertRaises(AssertionError, self.GL.release,
640
                      locking.LEVEL_CLUSTER)
641
    self.GL.release(locking.LEVEL_NODE)
642
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
643
    self.assertRaises(AssertionError, self.GL.release,
644
                      locking.LEVEL_CLUSTER, ['BGL'])
645
    self.assertRaises(AssertionError, self.GL.release,
646
                      locking.LEVEL_CLUSTER)
647
    self.GL.release(locking.LEVEL_INSTANCE)
648
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
649
    self.assertRaises(AssertionError, self.GL.release,
650
                      locking.LEVEL_CLUSTER)
651

    
652
  def testWrongOrder(self):
653
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
654
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
655
    self.assertRaises(AssertionError, self.GL.acquire,
656
                      locking.LEVEL_NODE, ['n1'])
657
    self.assertRaises(AssertionError, self.GL.acquire,
658
                      locking.LEVEL_INSTANCE, ['i2'])
659
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
660
    self.assertRaises(AssertionError, self.GL.acquire,
661
                      locking.LEVEL_CONFIG, ['config'])
662
    self.GL.release(locking.LEVEL_INSTANCE)
663
    self.assertRaises(AssertionError, self.GL.acquire,
664
                      locking.LEVEL_NODE, ['n1'])
665
    self.assertRaises(AssertionError, self.GL.acquire,
666
                      locking.LEVEL_INSTANCE, ['i2'])
667
    self.assertRaises(AssertionError, self.GL.acquire,
668
                      locking.LEVEL_CONFIG, ['config'])
669

    
670
  # Helper function to run as a thread that shared the BGL and then acquires
671
  # some locks at another level.
672
  def _doLock(self, level, names, shared):
673
    try:
674
      self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
675
      self.GL.acquire(level, names, shared=shared)
676
      self.done.put('DONE')
677
      self.GL.release(level)
678
      self.GL.release(locking.LEVEL_CLUSTER)
679
    except errors.LockError:
680
      self.done.put('ERR')
681

    
682
  def testConcurrency(self):
683
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
684
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
685
    self.assertEqual(self.done.get(True, 1), 'DONE')
686
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
687
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
688
    self.GL.acquire(locking.LEVEL_CONFIG, ['config'])
689
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i1', 1)).start()
690
    self.assertEqual(self.done.get(True, 1), 'DONE')
691
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i3', 1)).start()
692
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
693
    self.GL.release(locking.LEVEL_CONFIG)
694
    self.GL.release(locking.LEVEL_INSTANCE)
695
    self.assertEqual(self.done.get(True, 1), 'DONE')
696
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)
697
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 1)).start()
698
    self.assertEqual(self.done.get(True, 1), 'DONE')
699
    Thread(target=self._doLock, args=(locking.LEVEL_INSTANCE, 'i2', 0)).start()
700
    self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
701
    self.GL.release(locking.LEVEL_INSTANCE)
702
    self.assertEqual(self.done.get(True, 1), 'DONE')
703

    
704

    
705
if __name__ == '__main__':
706
  unittest.main()
707
  #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
708
  #unittest.TextTestRunner(verbosity=2).run(suite)