Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.locking_unittest.py @ e6416152

History | View | Annotate | Download (31.9 kB)

1 162c1c1f Guido Trotter
#!/usr/bin/python
2 162c1c1f Guido Trotter
#
3 162c1c1f Guido Trotter
4 162c1c1f Guido Trotter
# Copyright (C) 2006, 2007 Google Inc.
5 162c1c1f Guido Trotter
#
6 162c1c1f Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 162c1c1f Guido Trotter
# it under the terms of the GNU General Public License as published by
8 162c1c1f Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 162c1c1f Guido Trotter
# (at your option) any later version.
10 162c1c1f Guido Trotter
#
11 162c1c1f Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 162c1c1f Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 162c1c1f Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 162c1c1f Guido Trotter
# General Public License for more details.
15 162c1c1f Guido Trotter
#
16 162c1c1f Guido Trotter
# You should have received a copy of the GNU General Public License
17 162c1c1f Guido Trotter
# along with this program; if not, write to the Free Software
18 162c1c1f Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 162c1c1f Guido Trotter
# 0.0510-1301, USA.
20 162c1c1f Guido Trotter
21 162c1c1f Guido Trotter
22 162c1c1f Guido Trotter
"""Script for unittesting the locking module"""
23 162c1c1f Guido Trotter
24 162c1c1f Guido Trotter
25 162c1c1f Guido Trotter
import os
26 162c1c1f Guido Trotter
import unittest
27 162c1c1f Guido Trotter
import time
28 162c1c1f Guido Trotter
import Queue
29 162c1c1f Guido Trotter
30 162c1c1f Guido Trotter
from ganeti import locking
31 a95fd5d7 Guido Trotter
from ganeti import errors
32 162c1c1f Guido Trotter
from threading import Thread
33 162c1c1f Guido Trotter
34 162c1c1f Guido Trotter
35 42a999d1 Guido Trotter
# This is used to test the ssynchronize decorator.
36 42a999d1 Guido Trotter
# Since it's passed as input to a decorator it must be declared as a global.
37 42a999d1 Guido Trotter
_decoratorlock = locking.SharedLock()
38 42a999d1 Guido Trotter
39 4607c978 Iustin Pop
#: List for looping tests
40 4607c978 Iustin Pop
ITERATIONS = range(8)
41 4607c978 Iustin Pop
42 4607c978 Iustin Pop
def _Repeat(fn):
43 4607c978 Iustin Pop
  """Decorator for executing a function many times"""
44 4607c978 Iustin Pop
  def wrapper(*args, **kwargs):
45 4607c978 Iustin Pop
    for i in ITERATIONS:
46 4607c978 Iustin Pop
      fn(*args, **kwargs)
47 4607c978 Iustin Pop
  return wrapper
48 4607c978 Iustin Pop
49 4607c978 Iustin Pop
class _ThreadedTestCase(unittest.TestCase):
50 4607c978 Iustin Pop
  """Test class that supports adding/waiting on threads"""
51 4607c978 Iustin Pop
  def setUp(self):
52 4607c978 Iustin Pop
    unittest.TestCase.setUp(self)
53 4607c978 Iustin Pop
    self.threads = []
54 4607c978 Iustin Pop
55 4607c978 Iustin Pop
  def _addThread(self, *args, **kwargs):
56 4607c978 Iustin Pop
    """Create and remember a new thread"""
57 4607c978 Iustin Pop
    t = Thread(*args, **kwargs)
58 4607c978 Iustin Pop
    self.threads.append(t)
59 4607c978 Iustin Pop
    t.start()
60 4607c978 Iustin Pop
    return t
61 4607c978 Iustin Pop
62 4607c978 Iustin Pop
  def _waitThreads(self):
63 4607c978 Iustin Pop
    """Wait for all our threads to finish"""
64 4607c978 Iustin Pop
    for t in self.threads:
65 4607c978 Iustin Pop
      t.join(60)
66 4607c978 Iustin Pop
      self.failIf(t.isAlive())
67 4607c978 Iustin Pop
    self.threads = []
68 42a999d1 Guido Trotter
69 4607c978 Iustin Pop
70 4607c978 Iustin Pop
class TestSharedLock(_ThreadedTestCase):
71 d6646186 Guido Trotter
  """SharedLock tests"""
72 162c1c1f Guido Trotter
73 162c1c1f Guido Trotter
  def setUp(self):
74 4607c978 Iustin Pop
    _ThreadedTestCase.setUp(self)
75 162c1c1f Guido Trotter
    self.sl = locking.SharedLock()
76 162c1c1f Guido Trotter
    # helper threads use the 'done' queue to tell the master they finished.
77 162c1c1f Guido Trotter
    self.done = Queue.Queue(0)
78 162c1c1f Guido Trotter
79 162c1c1f Guido Trotter
  def testSequenceAndOwnership(self):
80 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned())
81 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
82 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned())
83 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned(shared=1))
84 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned(shared=0))
85 162c1c1f Guido Trotter
    self.sl.release()
86 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned())
87 162c1c1f Guido Trotter
    self.sl.acquire()
88 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned())
89 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned(shared=1))
90 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned(shared=0))
91 162c1c1f Guido Trotter
    self.sl.release()
92 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned())
93 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
94 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned())
95 162c1c1f Guido Trotter
    self.assert_(self.sl._is_owned(shared=1))
96 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned(shared=0))
97 162c1c1f Guido Trotter
    self.sl.release()
98 162c1c1f Guido Trotter
    self.assert_(not self.sl._is_owned())
99 162c1c1f Guido Trotter
100 162c1c1f Guido Trotter
  def testBooleanValue(self):
101 162c1c1f Guido Trotter
    # semaphores are supposed to return a true value on a successful acquire
102 162c1c1f Guido Trotter
    self.assert_(self.sl.acquire(shared=1))
103 162c1c1f Guido Trotter
    self.sl.release()
104 162c1c1f Guido Trotter
    self.assert_(self.sl.acquire())
105 162c1c1f Guido Trotter
    self.sl.release()
106 162c1c1f Guido Trotter
107 162c1c1f Guido Trotter
  def testDoubleLockingStoE(self):
108 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
109 162c1c1f Guido Trotter
    self.assertRaises(AssertionError, self.sl.acquire)
110 162c1c1f Guido Trotter
111 162c1c1f Guido Trotter
  def testDoubleLockingEtoS(self):
112 162c1c1f Guido Trotter
    self.sl.acquire()
113 162c1c1f Guido Trotter
    self.assertRaises(AssertionError, self.sl.acquire, shared=1)
114 162c1c1f Guido Trotter
115 162c1c1f Guido Trotter
  def testDoubleLockingStoS(self):
116 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
117 162c1c1f Guido Trotter
    self.assertRaises(AssertionError, self.sl.acquire, shared=1)
118 162c1c1f Guido Trotter
119 162c1c1f Guido Trotter
  def testDoubleLockingEtoE(self):
120 162c1c1f Guido Trotter
    self.sl.acquire()
121 162c1c1f Guido Trotter
    self.assertRaises(AssertionError, self.sl.acquire)
122 162c1c1f Guido Trotter
123 162c1c1f Guido Trotter
  # helper functions: called in a separate thread they acquire the lock, send
124 162c1c1f Guido Trotter
  # their identifier on the done queue, then release it.
125 162c1c1f Guido Trotter
  def _doItSharer(self):
126 a95fd5d7 Guido Trotter
    try:
127 a95fd5d7 Guido Trotter
      self.sl.acquire(shared=1)
128 a95fd5d7 Guido Trotter
      self.done.put('SHR')
129 a95fd5d7 Guido Trotter
      self.sl.release()
130 a95fd5d7 Guido Trotter
    except errors.LockError:
131 a95fd5d7 Guido Trotter
      self.done.put('ERR')
132 162c1c1f Guido Trotter
133 162c1c1f Guido Trotter
  def _doItExclusive(self):
134 a95fd5d7 Guido Trotter
    try:
135 a95fd5d7 Guido Trotter
      self.sl.acquire()
136 a95fd5d7 Guido Trotter
      self.done.put('EXC')
137 a95fd5d7 Guido Trotter
      self.sl.release()
138 a95fd5d7 Guido Trotter
    except errors.LockError:
139 a95fd5d7 Guido Trotter
      self.done.put('ERR')
140 a95fd5d7 Guido Trotter
141 a95fd5d7 Guido Trotter
  def _doItDelete(self):
142 a95fd5d7 Guido Trotter
    try:
143 4354ab03 Guido Trotter
      self.sl.delete()
144 a95fd5d7 Guido Trotter
      self.done.put('DEL')
145 a95fd5d7 Guido Trotter
    except errors.LockError:
146 a95fd5d7 Guido Trotter
      self.done.put('ERR')
147 162c1c1f Guido Trotter
148 162c1c1f Guido Trotter
  def testSharersCanCoexist(self):
149 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
150 162c1c1f Guido Trotter
    Thread(target=self._doItSharer).start()
151 162c1c1f Guido Trotter
    self.assert_(self.done.get(True, 1))
152 162c1c1f Guido Trotter
    self.sl.release()
153 162c1c1f Guido Trotter
154 4607c978 Iustin Pop
  @_Repeat
155 162c1c1f Guido Trotter
  def testExclusiveBlocksExclusive(self):
156 162c1c1f Guido Trotter
    self.sl.acquire()
157 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
158 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
159 162c1c1f Guido Trotter
    self.sl.release()
160 4607c978 Iustin Pop
    self._waitThreads()
161 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'EXC')
162 162c1c1f Guido Trotter
163 4607c978 Iustin Pop
  @_Repeat
164 a95fd5d7 Guido Trotter
  def testExclusiveBlocksDelete(self):
165 a95fd5d7 Guido Trotter
    self.sl.acquire()
166 4607c978 Iustin Pop
    self._addThread(target=self._doItDelete)
167 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
168 a95fd5d7 Guido Trotter
    self.sl.release()
169 4607c978 Iustin Pop
    self._waitThreads()
170 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'DEL')
171 4607c978 Iustin Pop
    self.sl = locking.SharedLock()
172 a95fd5d7 Guido Trotter
173 4607c978 Iustin Pop
  @_Repeat
174 162c1c1f Guido Trotter
  def testExclusiveBlocksSharer(self):
175 162c1c1f Guido Trotter
    self.sl.acquire()
176 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
177 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
178 162c1c1f Guido Trotter
    self.sl.release()
179 4607c978 Iustin Pop
    self._waitThreads()
180 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'SHR')
181 162c1c1f Guido Trotter
182 4607c978 Iustin Pop
  @_Repeat
183 162c1c1f Guido Trotter
  def testSharerBlocksExclusive(self):
184 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
185 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
186 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
187 162c1c1f Guido Trotter
    self.sl.release()
188 4607c978 Iustin Pop
    self._waitThreads()
189 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'EXC')
190 162c1c1f Guido Trotter
191 4607c978 Iustin Pop
  @_Repeat
192 a95fd5d7 Guido Trotter
  def testSharerBlocksDelete(self):
193 a95fd5d7 Guido Trotter
    self.sl.acquire(shared=1)
194 4607c978 Iustin Pop
    self._addThread(target=self._doItDelete)
195 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
196 a95fd5d7 Guido Trotter
    self.sl.release()
197 4607c978 Iustin Pop
    self._waitThreads()
198 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'DEL')
199 4607c978 Iustin Pop
    self.sl = locking.SharedLock()
200 a95fd5d7 Guido Trotter
201 4607c978 Iustin Pop
  @_Repeat
202 162c1c1f Guido Trotter
  def testWaitingExclusiveBlocksSharer(self):
203 e6416152 Iustin Pop
    """SKIPPED testWaitingExclusiveBlockSharer"""
204 e6416152 Iustin Pop
    return
205 e6416152 Iustin Pop
206 162c1c1f Guido Trotter
    self.sl.acquire(shared=1)
207 162c1c1f Guido Trotter
    # the lock is acquired in shared mode...
208 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
209 162c1c1f Guido Trotter
    # ...but now an exclusive is waiting...
210 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
211 162c1c1f Guido Trotter
    # ...so the sharer should be blocked as well
212 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
213 162c1c1f Guido Trotter
    self.sl.release()
214 4607c978 Iustin Pop
    self._waitThreads()
215 162c1c1f Guido Trotter
    # The exclusive passed before
216 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'EXC')
217 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'SHR')
218 162c1c1f Guido Trotter
219 4607c978 Iustin Pop
  @_Repeat
220 162c1c1f Guido Trotter
  def testWaitingSharerBlocksExclusive(self):
221 162c1c1f Guido Trotter
    self.sl.acquire()
222 162c1c1f Guido Trotter
    # the lock is acquired in exclusive mode...
223 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
224 162c1c1f Guido Trotter
    # ...but now a sharer is waiting...
225 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
226 162c1c1f Guido Trotter
    # ...the exclusive is waiting too...
227 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
228 162c1c1f Guido Trotter
    self.sl.release()
229 4607c978 Iustin Pop
    self._waitThreads()
230 162c1c1f Guido Trotter
    # The sharer passed before
231 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'SHR')
232 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'EXC')
233 162c1c1f Guido Trotter
234 a95fd5d7 Guido Trotter
  def testNoNonBlocking(self):
235 a95fd5d7 Guido Trotter
    self.assertRaises(NotImplementedError, self.sl.acquire, blocking=0)
236 a95fd5d7 Guido Trotter
    self.assertRaises(NotImplementedError, self.sl.delete, blocking=0)
237 a95fd5d7 Guido Trotter
    self.sl.acquire()
238 a95fd5d7 Guido Trotter
    self.sl.delete(blocking=0) # Fine, because the lock is already acquired
239 a95fd5d7 Guido Trotter
240 a95fd5d7 Guido Trotter
  def testDelete(self):
241 a95fd5d7 Guido Trotter
    self.sl.delete()
242 a95fd5d7 Guido Trotter
    self.assertRaises(errors.LockError, self.sl.acquire)
243 84152b96 Guido Trotter
    self.assertRaises(errors.LockError, self.sl.acquire, shared=1)
244 a95fd5d7 Guido Trotter
    self.assertRaises(errors.LockError, self.sl.delete)
245 a95fd5d7 Guido Trotter
246 84152b96 Guido Trotter
  def testNoDeleteIfSharer(self):
247 84152b96 Guido Trotter
    self.sl.acquire(shared=1)
248 84152b96 Guido Trotter
    self.assertRaises(AssertionError, self.sl.delete)
249 84152b96 Guido Trotter
250 4607c978 Iustin Pop
  @_Repeat
251 a95fd5d7 Guido Trotter
  def testDeletePendingSharersExclusiveDelete(self):
252 a95fd5d7 Guido Trotter
    self.sl.acquire()
253 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
254 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
255 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
256 4607c978 Iustin Pop
    self._addThread(target=self._doItDelete)
257 a95fd5d7 Guido Trotter
    self.sl.delete()
258 4607c978 Iustin Pop
    self._waitThreads()
259 4607c978 Iustin Pop
    # The threads who were pending return ERR
260 4607c978 Iustin Pop
    for _ in range(4):
261 4607c978 Iustin Pop
      self.assertEqual(self.done.get_nowait(), 'ERR')
262 4607c978 Iustin Pop
    self.sl = locking.SharedLock()
263 a95fd5d7 Guido Trotter
264 4607c978 Iustin Pop
  @_Repeat
265 a95fd5d7 Guido Trotter
  def testDeletePendingDeleteExclusiveSharers(self):
266 a95fd5d7 Guido Trotter
    self.sl.acquire()
267 4607c978 Iustin Pop
    self._addThread(target=self._doItDelete)
268 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
269 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
270 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
271 a95fd5d7 Guido Trotter
    self.sl.delete()
272 4607c978 Iustin Pop
    self._waitThreads()
273 a95fd5d7 Guido Trotter
    # The two threads who were pending return both ERR
274 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'ERR')
275 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'ERR')
276 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'ERR')
277 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'ERR')
278 4607c978 Iustin Pop
    self.sl = locking.SharedLock()
279 a95fd5d7 Guido Trotter
280 162c1c1f Guido Trotter
281 4607c978 Iustin Pop
class TestSSynchronizedDecorator(_ThreadedTestCase):
282 42a999d1 Guido Trotter
  """Shared Lock Synchronized decorator test"""
283 42a999d1 Guido Trotter
284 42a999d1 Guido Trotter
  def setUp(self):
285 4607c978 Iustin Pop
    _ThreadedTestCase.setUp(self)
286 42a999d1 Guido Trotter
    # helper threads use the 'done' queue to tell the master they finished.
287 42a999d1 Guido Trotter
    self.done = Queue.Queue(0)
288 42a999d1 Guido Trotter
289 42a999d1 Guido Trotter
  @locking.ssynchronized(_decoratorlock)
290 42a999d1 Guido Trotter
  def _doItExclusive(self):
291 42a999d1 Guido Trotter
    self.assert_(_decoratorlock._is_owned())
292 42a999d1 Guido Trotter
    self.done.put('EXC')
293 42a999d1 Guido Trotter
294 42a999d1 Guido Trotter
  @locking.ssynchronized(_decoratorlock, shared=1)
295 42a999d1 Guido Trotter
  def _doItSharer(self):
296 42a999d1 Guido Trotter
    self.assert_(_decoratorlock._is_owned(shared=1))
297 42a999d1 Guido Trotter
    self.done.put('SHR')
298 42a999d1 Guido Trotter
299 42a999d1 Guido Trotter
  def testDecoratedFunctions(self):
300 42a999d1 Guido Trotter
    self._doItExclusive()
301 42a999d1 Guido Trotter
    self.assert_(not _decoratorlock._is_owned())
302 42a999d1 Guido Trotter
    self._doItSharer()
303 42a999d1 Guido Trotter
    self.assert_(not _decoratorlock._is_owned())
304 42a999d1 Guido Trotter
305 42a999d1 Guido Trotter
  def testSharersCanCoexist(self):
306 42a999d1 Guido Trotter
    _decoratorlock.acquire(shared=1)
307 42a999d1 Guido Trotter
    Thread(target=self._doItSharer).start()
308 42a999d1 Guido Trotter
    self.assert_(self.done.get(True, 1))
309 42a999d1 Guido Trotter
    _decoratorlock.release()
310 42a999d1 Guido Trotter
311 4607c978 Iustin Pop
  @_Repeat
312 42a999d1 Guido Trotter
  def testExclusiveBlocksExclusive(self):
313 42a999d1 Guido Trotter
    _decoratorlock.acquire()
314 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
315 42a999d1 Guido Trotter
    # give it a bit of time to check that it's not actually doing anything
316 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
317 42a999d1 Guido Trotter
    _decoratorlock.release()
318 4607c978 Iustin Pop
    self._waitThreads()
319 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'EXC')
320 42a999d1 Guido Trotter
321 4607c978 Iustin Pop
  @_Repeat
322 42a999d1 Guido Trotter
  def testExclusiveBlocksSharer(self):
323 42a999d1 Guido Trotter
    _decoratorlock.acquire()
324 4607c978 Iustin Pop
    self._addThread(target=self._doItSharer)
325 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
326 42a999d1 Guido Trotter
    _decoratorlock.release()
327 4607c978 Iustin Pop
    self._waitThreads()
328 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'SHR')
329 42a999d1 Guido Trotter
330 4607c978 Iustin Pop
  @_Repeat
331 42a999d1 Guido Trotter
  def testSharerBlocksExclusive(self):
332 42a999d1 Guido Trotter
    _decoratorlock.acquire(shared=1)
333 4607c978 Iustin Pop
    self._addThread(target=self._doItExclusive)
334 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
335 42a999d1 Guido Trotter
    _decoratorlock.release()
336 4607c978 Iustin Pop
    self._waitThreads()
337 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), 'EXC')
338 42a999d1 Guido Trotter
339 42a999d1 Guido Trotter
340 4607c978 Iustin Pop
class TestLockSet(_ThreadedTestCase):
341 aaae9bc0 Guido Trotter
  """LockSet tests"""
342 aaae9bc0 Guido Trotter
343 aaae9bc0 Guido Trotter
  def setUp(self):
344 4607c978 Iustin Pop
    _ThreadedTestCase.setUp(self)
345 4607c978 Iustin Pop
    self._setUpLS()
346 aaae9bc0 Guido Trotter
    # helper threads use the 'done' queue to tell the master they finished.
347 aaae9bc0 Guido Trotter
    self.done = Queue.Queue(0)
348 aaae9bc0 Guido Trotter
349 4607c978 Iustin Pop
  def _setUpLS(self):
350 4607c978 Iustin Pop
    """Helper to (re)initialize the lock set"""
351 4607c978 Iustin Pop
    self.resources = ['one', 'two', 'three']
352 4607c978 Iustin Pop
    self.ls = locking.LockSet(members=self.resources)
353 4607c978 Iustin Pop
354 4607c978 Iustin Pop
355 aaae9bc0 Guido Trotter
  def testResources(self):
356 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._names(), set(self.resources))
357 aaae9bc0 Guido Trotter
    newls = locking.LockSet()
358 aaae9bc0 Guido Trotter
    self.assertEquals(newls._names(), set())
359 aaae9bc0 Guido Trotter
360 aaae9bc0 Guido Trotter
  def testAcquireRelease(self):
361 0cc00929 Guido Trotter
    self.assert_(self.ls.acquire('one'))
362 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['one']))
363 aaae9bc0 Guido Trotter
    self.ls.release()
364 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
365 0cc00929 Guido Trotter
    self.assertEquals(self.ls.acquire(['one']), set(['one']))
366 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['one']))
367 aaae9bc0 Guido Trotter
    self.ls.release()
368 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
369 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'two', 'three'])
370 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
371 aaae9bc0 Guido Trotter
    self.ls.release('one')
372 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['two', 'three']))
373 aaae9bc0 Guido Trotter
    self.ls.release(['three'])
374 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['two']))
375 aaae9bc0 Guido Trotter
    self.ls.release()
376 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
377 0cc00929 Guido Trotter
    self.assertEquals(self.ls.acquire(['one', 'three']), set(['one', 'three']))
378 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['one', 'three']))
379 aaae9bc0 Guido Trotter
    self.ls.release()
380 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
381 aaae9bc0 Guido Trotter
382 aaae9bc0 Guido Trotter
  def testNoDoubleAcquire(self):
383 aaae9bc0 Guido Trotter
    self.ls.acquire('one')
384 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.acquire, 'one')
385 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.acquire, ['two'])
386 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.acquire, ['two', 'three'])
387 aaae9bc0 Guido Trotter
    self.ls.release()
388 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'three'])
389 aaae9bc0 Guido Trotter
    self.ls.release('one')
390 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.acquire, ['two'])
391 aaae9bc0 Guido Trotter
    self.ls.release('three')
392 aaae9bc0 Guido Trotter
393 aaae9bc0 Guido Trotter
  def testNoWrongRelease(self):
394 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.release)
395 aaae9bc0 Guido Trotter
    self.ls.acquire('one')
396 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.release, 'two')
397 aaae9bc0 Guido Trotter
398 aaae9bc0 Guido Trotter
  def testAddRemove(self):
399 aaae9bc0 Guido Trotter
    self.ls.add('four')
400 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
401 aaae9bc0 Guido Trotter
    self.assert_('four' in self.ls._names())
402 aaae9bc0 Guido Trotter
    self.ls.add(['five', 'six', 'seven'], acquired=1)
403 aaae9bc0 Guido Trotter
    self.assert_('five' in self.ls._names())
404 aaae9bc0 Guido Trotter
    self.assert_('six' in self.ls._names())
405 aaae9bc0 Guido Trotter
    self.assert_('seven' in self.ls._names())
406 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['five', 'six', 'seven']))
407 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove(['five', 'six']), ['five', 'six'])
408 aaae9bc0 Guido Trotter
    self.assert_('five' not in self.ls._names())
409 aaae9bc0 Guido Trotter
    self.assert_('six' not in self.ls._names())
410 aaae9bc0 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['seven']))
411 d2aff862 Guido Trotter
    self.assertRaises(AssertionError, self.ls.add, 'eight', acquired=1)
412 aaae9bc0 Guido Trotter
    self.ls.remove('seven')
413 aaae9bc0 Guido Trotter
    self.assert_('seven' not in self.ls._names())
414 d2aff862 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set([]))
415 d2aff862 Guido Trotter
    self.ls.acquire(None, shared=1)
416 d2aff862 Guido Trotter
    self.assertRaises(AssertionError, self.ls.add, 'eight')
417 d2aff862 Guido Trotter
    self.ls.release()
418 d2aff862 Guido Trotter
    self.ls.acquire(None)
419 d2aff862 Guido Trotter
    self.ls.add('eight', acquired=1)
420 d2aff862 Guido Trotter
    self.assert_('eight' in self.ls._names())
421 d2aff862 Guido Trotter
    self.assert_('eight' in self.ls._list_owned())
422 d2aff862 Guido Trotter
    self.ls.add('nine')
423 d2aff862 Guido Trotter
    self.assert_('nine' in self.ls._names())
424 d2aff862 Guido Trotter
    self.assert_('nine' not in self.ls._list_owned())
425 aaae9bc0 Guido Trotter
    self.ls.release()
426 aaae9bc0 Guido Trotter
    self.ls.remove(['two'])
427 aaae9bc0 Guido Trotter
    self.assert_('two' not in self.ls._names())
428 aaae9bc0 Guido Trotter
    self.ls.acquire('three')
429 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove(['three']), ['three'])
430 aaae9bc0 Guido Trotter
    self.assert_('three' not in self.ls._names())
431 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove('three'), [])
432 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove(['one', 'three', 'six']), ['one'])
433 aaae9bc0 Guido Trotter
    self.assert_('one' not in self.ls._names())
434 aaae9bc0 Guido Trotter
435 aaae9bc0 Guido Trotter
  def testRemoveNonBlocking(self):
436 aaae9bc0 Guido Trotter
    self.assertRaises(NotImplementedError, self.ls.remove, 'one', blocking=0)
437 aaae9bc0 Guido Trotter
    self.ls.acquire('one')
438 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove('one', blocking=0), ['one'])
439 aaae9bc0 Guido Trotter
    self.ls.acquire(['two', 'three'])
440 3f404fc5 Guido Trotter
    self.assertEquals(self.ls.remove(['two', 'three'], blocking=0),
441 3f404fc5 Guido Trotter
                      ['two', 'three'])
442 aaae9bc0 Guido Trotter
443 aaae9bc0 Guido Trotter
  def testNoDoubleAdd(self):
444 aaae9bc0 Guido Trotter
    self.assertRaises(errors.LockError, self.ls.add, 'two')
445 aaae9bc0 Guido Trotter
    self.ls.add('four')
446 aaae9bc0 Guido Trotter
    self.assertRaises(errors.LockError, self.ls.add, 'four')
447 aaae9bc0 Guido Trotter
448 aaae9bc0 Guido Trotter
  def testNoWrongRemoves(self):
449 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'three'], shared=1)
450 aaae9bc0 Guido Trotter
    # Cannot remove 'two' while holding something which is not a superset
451 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.remove, 'two')
452 aaae9bc0 Guido Trotter
    # Cannot remove 'three' as we are sharing it
453 aaae9bc0 Guido Trotter
    self.assertRaises(AssertionError, self.ls.remove, 'three')
454 aaae9bc0 Guido Trotter
455 3b7ed473 Guido Trotter
  def testAcquireSetLock(self):
456 3b7ed473 Guido Trotter
    # acquire the set-lock exclusively
457 3b7ed473 Guido Trotter
    self.assertEquals(self.ls.acquire(None), set(['one', 'two', 'three']))
458 d4803c24 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['one', 'two', 'three']))
459 d4803c24 Guido Trotter
    self.assertEquals(self.ls._is_owned(), True)
460 d4803c24 Guido Trotter
    self.assertEquals(self.ls._names(), set(['one', 'two', 'three']))
461 3b7ed473 Guido Trotter
    # I can still add/remove elements...
462 3b7ed473 Guido Trotter
    self.assertEquals(self.ls.remove(['two', 'three']), ['two', 'three'])
463 3b7ed473 Guido Trotter
    self.assert_(self.ls.add('six'))
464 3b7ed473 Guido Trotter
    self.ls.release()
465 3b7ed473 Guido Trotter
    # share the set-lock
466 3b7ed473 Guido Trotter
    self.assertEquals(self.ls.acquire(None, shared=1), set(['one', 'six']))
467 3b7ed473 Guido Trotter
    # adding new elements is not possible
468 3b7ed473 Guido Trotter
    self.assertRaises(AssertionError, self.ls.add, 'five')
469 3b7ed473 Guido Trotter
    self.ls.release()
470 3b7ed473 Guido Trotter
471 d4f6a91c Guido Trotter
  def testAcquireWithRepetitions(self):
472 d4f6a91c Guido Trotter
    self.assertEquals(self.ls.acquire(['two', 'two', 'three'], shared=1),
473 d4f6a91c Guido Trotter
                      set(['two', 'two', 'three']))
474 d4f6a91c Guido Trotter
    self.ls.release(['two', 'two'])
475 d4f6a91c Guido Trotter
    self.assertEquals(self.ls._list_owned(), set(['three']))
476 d4f6a91c Guido Trotter
477 2e1d6d96 Guido Trotter
  def testEmptyAcquire(self):
478 2e1d6d96 Guido Trotter
    # Acquire an empty list of locks...
479 2e1d6d96 Guido Trotter
    self.assertEquals(self.ls.acquire([]), set())
480 2e1d6d96 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
481 2e1d6d96 Guido Trotter
    # New locks can still be addded
482 2e1d6d96 Guido Trotter
    self.assert_(self.ls.add('six'))
483 2e1d6d96 Guido Trotter
    # "re-acquiring" is not an issue, since we had really acquired nothing
484 2e1d6d96 Guido Trotter
    self.assertEquals(self.ls.acquire([], shared=1), set())
485 2e1d6d96 Guido Trotter
    self.assertEquals(self.ls._list_owned(), set())
486 2e1d6d96 Guido Trotter
    # We haven't really acquired anything, so we cannot release
487 2e1d6d96 Guido Trotter
    self.assertRaises(AssertionError, self.ls.release)
488 2e1d6d96 Guido Trotter
489 aaae9bc0 Guido Trotter
  def _doLockSet(self, set, shared):
490 aaae9bc0 Guido Trotter
    try:
491 aaae9bc0 Guido Trotter
      self.ls.acquire(set, shared=shared)
492 aaae9bc0 Guido Trotter
      self.done.put('DONE')
493 aaae9bc0 Guido Trotter
      self.ls.release()
494 aaae9bc0 Guido Trotter
    except errors.LockError:
495 aaae9bc0 Guido Trotter
      self.done.put('ERR')
496 aaae9bc0 Guido Trotter
497 3b7ed473 Guido Trotter
  def _doAddSet(self, set):
498 3b7ed473 Guido Trotter
    try:
499 3b7ed473 Guido Trotter
      self.ls.add(set, acquired=1)
500 3b7ed473 Guido Trotter
      self.done.put('DONE')
501 3b7ed473 Guido Trotter
      self.ls.release()
502 3b7ed473 Guido Trotter
    except errors.LockError:
503 3b7ed473 Guido Trotter
      self.done.put('ERR')
504 3b7ed473 Guido Trotter
505 aaae9bc0 Guido Trotter
  def _doRemoveSet(self, set):
506 aaae9bc0 Guido Trotter
    self.done.put(self.ls.remove(set))
507 aaae9bc0 Guido Trotter
508 4607c978 Iustin Pop
  @_Repeat
509 aaae9bc0 Guido Trotter
  def testConcurrentSharedAcquire(self):
510 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'two'], shared=1)
511 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
512 4607c978 Iustin Pop
    self._waitThreads()
513 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
514 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two', 'three'], 1))
515 4607c978 Iustin Pop
    self._waitThreads()
516 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
517 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=('three', 1))
518 4607c978 Iustin Pop
    self._waitThreads()
519 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
520 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
521 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['two', 'three'], 0))
522 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
523 aaae9bc0 Guido Trotter
    self.ls.release()
524 4607c978 Iustin Pop
    self._waitThreads()
525 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
526 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
527 aaae9bc0 Guido Trotter
528 4607c978 Iustin Pop
  @_Repeat
529 aaae9bc0 Guido Trotter
  def testConcurrentExclusiveAcquire(self):
530 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'two'])
531 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=('three', 1))
532 4607c978 Iustin Pop
    self._waitThreads()
533 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
534 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=('three', 0))
535 4607c978 Iustin Pop
    self._waitThreads()
536 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
537 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
538 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
539 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=('one', 0))
540 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=('one', 1))
541 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['two', 'three'], 0))
542 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['two', 'three'], 1))
543 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
544 aaae9bc0 Guido Trotter
    self.ls.release()
545 4607c978 Iustin Pop
    self._waitThreads()
546 4607c978 Iustin Pop
    for _ in range(6):
547 4607c978 Iustin Pop
      self.failUnlessEqual(self.done.get_nowait(), 'DONE')
548 aaae9bc0 Guido Trotter
549 4607c978 Iustin Pop
  @_Repeat
550 aaae9bc0 Guido Trotter
  def testConcurrentRemove(self):
551 aaae9bc0 Guido Trotter
    self.ls.add('four')
552 aaae9bc0 Guido Trotter
    self.ls.acquire(['one', 'two', 'four'])
553 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'four'], 0))
554 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'four'], 1))
555 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 0))
556 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'two'], 1))
557 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
558 aaae9bc0 Guido Trotter
    self.ls.remove('one')
559 aaae9bc0 Guido Trotter
    self.ls.release()
560 4607c978 Iustin Pop
    self._waitThreads()
561 4607c978 Iustin Pop
    for i in range(4):
562 4607c978 Iustin Pop
      self.failUnlessEqual(self.done.get_nowait(), 'ERR')
563 aaae9bc0 Guido Trotter
    self.ls.add(['five', 'six'], acquired=1)
564 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['three', 'six'], 1))
565 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['three', 'six'], 0))
566 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['four', 'six'], 1))
567 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['four', 'six'], 0))
568 aaae9bc0 Guido Trotter
    self.ls.remove('five')
569 aaae9bc0 Guido Trotter
    self.ls.release()
570 4607c978 Iustin Pop
    self._waitThreads()
571 4607c978 Iustin Pop
    for i in range(4):
572 4607c978 Iustin Pop
      self.failUnlessEqual(self.done.get_nowait(), 'DONE')
573 aaae9bc0 Guido Trotter
    self.ls.acquire(['three', 'four'])
574 4607c978 Iustin Pop
    self._addThread(target=self._doRemoveSet, args=(['four', 'six'], ))
575 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
576 aaae9bc0 Guido Trotter
    self.ls.remove('four')
577 4607c978 Iustin Pop
    self._waitThreads()
578 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), ['six'])
579 4607c978 Iustin Pop
    self._addThread(target=self._doRemoveSet, args=(['two']))
580 4607c978 Iustin Pop
    self._waitThreads()
581 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), ['two'])
582 aaae9bc0 Guido Trotter
    self.ls.release()
583 4607c978 Iustin Pop
    # reset lockset
584 4607c978 Iustin Pop
    self._setUpLS()
585 aaae9bc0 Guido Trotter
586 4607c978 Iustin Pop
  @_Repeat
587 3b7ed473 Guido Trotter
  def testConcurrentSharedSetLock(self):
588 3b7ed473 Guido Trotter
    # share the set-lock...
589 3b7ed473 Guido Trotter
    self.ls.acquire(None, shared=1)
590 3b7ed473 Guido Trotter
    # ...another thread can share it too
591 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
592 4607c978 Iustin Pop
    self._waitThreads()
593 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
594 3b7ed473 Guido Trotter
    # ...or just share some elements
595 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['one', 'three'], 1))
596 4607c978 Iustin Pop
    self._waitThreads()
597 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
598 3b7ed473 Guido Trotter
    # ...but not add new ones or remove any
599 4607c978 Iustin Pop
    t = self._addThread(target=self._doAddSet, args=(['nine']))
600 4607c978 Iustin Pop
    self._addThread(target=self._doRemoveSet, args=(['two'], ))
601 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
602 3b7ed473 Guido Trotter
    # this just releases the set-lock
603 3b7ed473 Guido Trotter
    self.ls.release([])
604 4607c978 Iustin Pop
    t.join(60)
605 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
606 3b7ed473 Guido Trotter
    # release the lock on the actual elements so remove() can proceed too
607 3b7ed473 Guido Trotter
    self.ls.release()
608 4607c978 Iustin Pop
    self._waitThreads()
609 4607c978 Iustin Pop
    self.failUnlessEqual(self.done.get_nowait(), ['two'])
610 4607c978 Iustin Pop
    # reset lockset
611 4607c978 Iustin Pop
    self._setUpLS()
612 3b7ed473 Guido Trotter
613 4607c978 Iustin Pop
  @_Repeat
614 3b7ed473 Guido Trotter
  def testConcurrentExclusiveSetLock(self):
615 3b7ed473 Guido Trotter
    # acquire the set-lock...
616 3b7ed473 Guido Trotter
    self.ls.acquire(None, shared=0)
617 3b7ed473 Guido Trotter
    # ...no one can do anything else
618 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
619 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 0))
620 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['three'], 0))
621 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(['two'], 1))
622 4607c978 Iustin Pop
    self._addThread(target=self._doAddSet, args=(['nine']))
623 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
624 3b7ed473 Guido Trotter
    self.ls.release()
625 4607c978 Iustin Pop
    self._waitThreads()
626 4607c978 Iustin Pop
    for _ in range(5):
627 4607c978 Iustin Pop
      self.assertEqual(self.done.get(True, 1), 'DONE')
628 4607c978 Iustin Pop
    # cleanup
629 4607c978 Iustin Pop
    self._setUpLS()
630 3b7ed473 Guido Trotter
631 4607c978 Iustin Pop
  @_Repeat
632 d2aff862 Guido Trotter
  def testConcurrentSetLockAdd(self):
633 d2aff862 Guido Trotter
    self.ls.acquire('one')
634 d2aff862 Guido Trotter
    # Another thread wants the whole SetLock
635 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 0))
636 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
637 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
638 d2aff862 Guido Trotter
    self.assertRaises(AssertionError, self.ls.add, 'four')
639 d2aff862 Guido Trotter
    self.ls.release()
640 4607c978 Iustin Pop
    self._waitThreads()
641 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
642 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
643 d2aff862 Guido Trotter
    self.ls.acquire(None)
644 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 0))
645 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
646 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
647 d2aff862 Guido Trotter
    self.ls.add('four')
648 d2aff862 Guido Trotter
    self.ls.add('five', acquired=1)
649 d2aff862 Guido Trotter
    self.ls.add('six', acquired=1, shared=1)
650 d2aff862 Guido Trotter
    self.assertEquals(self.ls._list_owned(),
651 d2aff862 Guido Trotter
      set(['one', 'two', 'three', 'five', 'six']))
652 d2aff862 Guido Trotter
    self.assertEquals(self.ls._is_owned(), True)
653 d2aff862 Guido Trotter
    self.assertEquals(self.ls._names(),
654 d2aff862 Guido Trotter
      set(['one', 'two', 'three', 'four', 'five', 'six']))
655 d2aff862 Guido Trotter
    self.ls.release()
656 4607c978 Iustin Pop
    self._waitThreads()
657 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
658 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
659 4607c978 Iustin Pop
    self._setUpLS()
660 d2aff862 Guido Trotter
661 4607c978 Iustin Pop
  @_Repeat
662 b2dabfd6 Guido Trotter
  def testEmptyLockSet(self):
663 b2dabfd6 Guido Trotter
    # get the set-lock
664 b2dabfd6 Guido Trotter
    self.assertEqual(self.ls.acquire(None), set(['one', 'two', 'three']))
665 b2dabfd6 Guido Trotter
    # now empty it...
666 b2dabfd6 Guido Trotter
    self.ls.remove(['one', 'two', 'three'])
667 b2dabfd6 Guido Trotter
    # and adds/locks by another thread still wait
668 4607c978 Iustin Pop
    self._addThread(target=self._doAddSet, args=(['nine']))
669 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
670 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 0))
671 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
672 b2dabfd6 Guido Trotter
    self.ls.release()
673 4607c978 Iustin Pop
    self._waitThreads()
674 4607c978 Iustin Pop
    for _ in range(3):
675 4607c978 Iustin Pop
      self.assertEqual(self.done.get_nowait(), 'DONE')
676 b2dabfd6 Guido Trotter
    # empty it again...
677 b2dabfd6 Guido Trotter
    self.assertEqual(self.ls.remove(['nine']), ['nine'])
678 b2dabfd6 Guido Trotter
    # now share it...
679 b2dabfd6 Guido Trotter
    self.assertEqual(self.ls.acquire(None, shared=1), set())
680 b2dabfd6 Guido Trotter
    # other sharers can go, adds still wait
681 4607c978 Iustin Pop
    self._addThread(target=self._doLockSet, args=(None, 1))
682 4607c978 Iustin Pop
    self._waitThreads()
683 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
684 4607c978 Iustin Pop
    self._addThread(target=self._doAddSet, args=(['nine']))
685 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
686 b2dabfd6 Guido Trotter
    self.ls.release()
687 4607c978 Iustin Pop
    self._waitThreads()
688 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
689 4607c978 Iustin Pop
    self._setUpLS()
690 b2dabfd6 Guido Trotter
691 aaae9bc0 Guido Trotter
692 4607c978 Iustin Pop
class TestGanetiLockManager(_ThreadedTestCase):
693 7ee7c0c7 Guido Trotter
694 7ee7c0c7 Guido Trotter
  def setUp(self):
695 4607c978 Iustin Pop
    _ThreadedTestCase.setUp(self)
696 7ee7c0c7 Guido Trotter
    self.nodes=['n1', 'n2']
697 7ee7c0c7 Guido Trotter
    self.instances=['i1', 'i2', 'i3']
698 7ee7c0c7 Guido Trotter
    self.GL = locking.GanetiLockManager(nodes=self.nodes,
699 7ee7c0c7 Guido Trotter
                                        instances=self.instances)
700 7ee7c0c7 Guido Trotter
    self.done = Queue.Queue(0)
701 7ee7c0c7 Guido Trotter
702 7ee7c0c7 Guido Trotter
  def tearDown(self):
703 7ee7c0c7 Guido Trotter
    # Don't try this at home...
704 7ee7c0c7 Guido Trotter
    locking.GanetiLockManager._instance = None
705 7ee7c0c7 Guido Trotter
706 7ee7c0c7 Guido Trotter
  def testLockingConstants(self):
707 7ee7c0c7 Guido Trotter
    # The locking library internally cheats by assuming its constants have some
708 7ee7c0c7 Guido Trotter
    # relationships with each other. Check those hold true.
709 b10b9d74 Guido Trotter
    # This relationship is also used in the Processor to recursively acquire
710 b10b9d74 Guido Trotter
    # the right locks. Again, please don't break it.
711 7ee7c0c7 Guido Trotter
    for i in range(len(locking.LEVELS)):
712 7ee7c0c7 Guido Trotter
      self.assertEqual(i, locking.LEVELS[i])
713 7ee7c0c7 Guido Trotter
714 7ee7c0c7 Guido Trotter
  def testDoubleGLFails(self):
715 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, locking.GanetiLockManager)
716 7ee7c0c7 Guido Trotter
717 7ee7c0c7 Guido Trotter
  def testLockNames(self):
718 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
719 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
720 cdb08f44 Michael Hanselmann
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
721 cdb08f44 Michael Hanselmann
                     set(self.instances))
722 7ee7c0c7 Guido Trotter
723 7ee7c0c7 Guido Trotter
  def testInitAndResources(self):
724 7ee7c0c7 Guido Trotter
    locking.GanetiLockManager._instance = None
725 7ee7c0c7 Guido Trotter
    self.GL = locking.GanetiLockManager()
726 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
727 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
728 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
729 7ee7c0c7 Guido Trotter
730 7ee7c0c7 Guido Trotter
    locking.GanetiLockManager._instance = None
731 7ee7c0c7 Guido Trotter
    self.GL = locking.GanetiLockManager(nodes=self.nodes)
732 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
733 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set(self.nodes))
734 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE), set())
735 7ee7c0c7 Guido Trotter
736 7ee7c0c7 Guido Trotter
    locking.GanetiLockManager._instance = None
737 7ee7c0c7 Guido Trotter
    self.GL = locking.GanetiLockManager(instances=self.instances)
738 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_CLUSTER), set(['BGL']))
739 7ee7c0c7 Guido Trotter
    self.assertEqual(self.GL._names(locking.LEVEL_NODE), set())
740 cdb08f44 Michael Hanselmann
    self.assertEqual(self.GL._names(locking.LEVEL_INSTANCE),
741 cdb08f44 Michael Hanselmann
                     set(self.instances))
742 7ee7c0c7 Guido Trotter
743 7ee7c0c7 Guido Trotter
  def testAcquireRelease(self):
744 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
745 7ee7c0c7 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_CLUSTER), set(['BGL']))
746 04e1bfaf Guido Trotter
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i1'])
747 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_NODE, ['n1', 'n2'], shared=1)
748 04e1bfaf Guido Trotter
    self.GL.release(locking.LEVEL_NODE, ['n2'])
749 7ee7c0c7 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set(['n1']))
750 7ee7c0c7 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
751 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_NODE)
752 04e1bfaf Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE), set())
753 04e1bfaf Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i1']))
754 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
755 7ee7c0c7 Guido Trotter
    self.assertRaises(errors.LockError, self.GL.acquire,
756 7ee7c0c7 Guido Trotter
                      locking.LEVEL_INSTANCE, ['i5'])
757 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'], shared=1)
758 7ee7c0c7 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE), set(['i3']))
759 7ee7c0c7 Guido Trotter
760 90c942d1 Guido Trotter
  def testAcquireWholeSets(self):
761 90c942d1 Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
762 90c942d1 Guido Trotter
    self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
763 90c942d1 Guido Trotter
                      set(self.instances))
764 90c942d1 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
765 90c942d1 Guido Trotter
                      set(self.instances))
766 90c942d1 Guido Trotter
    self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, None, shared=1),
767 90c942d1 Guido Trotter
                      set(self.nodes))
768 90c942d1 Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
769 90c942d1 Guido Trotter
                      set(self.nodes))
770 90c942d1 Guido Trotter
    self.GL.release(locking.LEVEL_NODE)
771 d4f6a91c Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
772 d4f6a91c Guido Trotter
    self.GL.release(locking.LEVEL_CLUSTER)
773 d4f6a91c Guido Trotter
774 d4f6a91c Guido Trotter
  def testAcquireWholeAndPartial(self):
775 d4f6a91c Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
776 d4f6a91c Guido Trotter
    self.assertEquals(self.GL.acquire(locking.LEVEL_INSTANCE, None),
777 d4f6a91c Guido Trotter
                      set(self.instances))
778 d4f6a91c Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_INSTANCE),
779 d4f6a91c Guido Trotter
                      set(self.instances))
780 d4f6a91c Guido Trotter
    self.assertEquals(self.GL.acquire(locking.LEVEL_NODE, ['n2'], shared=1),
781 d4f6a91c Guido Trotter
                      set(['n2']))
782 d4f6a91c Guido Trotter
    self.assertEquals(self.GL._list_owned(locking.LEVEL_NODE),
783 d4f6a91c Guido Trotter
                      set(['n2']))
784 d4f6a91c Guido Trotter
    self.GL.release(locking.LEVEL_NODE)
785 90c942d1 Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
786 90c942d1 Guido Trotter
    self.GL.release(locking.LEVEL_CLUSTER)
787 90c942d1 Guido Trotter
788 7ee7c0c7 Guido Trotter
  def testBGLDependency(self):
789 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.acquire,
790 7ee7c0c7 Guido Trotter
                      locking.LEVEL_NODE, ['n1', 'n2'])
791 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.acquire,
792 7ee7c0c7 Guido Trotter
                      locking.LEVEL_INSTANCE, ['i3'])
793 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
794 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_NODE, ['n1'])
795 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.release,
796 7ee7c0c7 Guido Trotter
                      locking.LEVEL_CLUSTER, ['BGL'])
797 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.release,
798 7ee7c0c7 Guido Trotter
                      locking.LEVEL_CLUSTER)
799 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_NODE)
800 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i1', 'i2'])
801 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.release,
802 7ee7c0c7 Guido Trotter
                      locking.LEVEL_CLUSTER, ['BGL'])
803 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.release,
804 7ee7c0c7 Guido Trotter
                      locking.LEVEL_CLUSTER)
805 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
806 7ee7c0c7 Guido Trotter
807 7ee7c0c7 Guido Trotter
  def testWrongOrder(self):
808 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
809 04e1bfaf Guido Trotter
    self.GL.acquire(locking.LEVEL_NODE, ['n2'])
810 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.acquire,
811 7ee7c0c7 Guido Trotter
                      locking.LEVEL_NODE, ['n1'])
812 7ee7c0c7 Guido Trotter
    self.assertRaises(AssertionError, self.GL.acquire,
813 7ee7c0c7 Guido Trotter
                      locking.LEVEL_INSTANCE, ['i2'])
814 7ee7c0c7 Guido Trotter
815 7ee7c0c7 Guido Trotter
  # Helper function to run as a thread that shared the BGL and then acquires
816 7ee7c0c7 Guido Trotter
  # some locks at another level.
817 7ee7c0c7 Guido Trotter
  def _doLock(self, level, names, shared):
818 7ee7c0c7 Guido Trotter
    try:
819 7ee7c0c7 Guido Trotter
      self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
820 7ee7c0c7 Guido Trotter
      self.GL.acquire(level, names, shared=shared)
821 7ee7c0c7 Guido Trotter
      self.done.put('DONE')
822 7ee7c0c7 Guido Trotter
      self.GL.release(level)
823 7ee7c0c7 Guido Trotter
      self.GL.release(locking.LEVEL_CLUSTER)
824 7ee7c0c7 Guido Trotter
    except errors.LockError:
825 7ee7c0c7 Guido Trotter
      self.done.put('ERR')
826 7ee7c0c7 Guido Trotter
827 4607c978 Iustin Pop
  @_Repeat
828 7ee7c0c7 Guido Trotter
  def testConcurrency(self):
829 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_CLUSTER, ['BGL'], shared=1)
830 4607c978 Iustin Pop
    self._addThread(target=self._doLock,
831 4607c978 Iustin Pop
                    args=(locking.LEVEL_INSTANCE, 'i1', 1))
832 4607c978 Iustin Pop
    self._waitThreads()
833 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
834 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i3'])
835 4607c978 Iustin Pop
    self._addThread(target=self._doLock,
836 4607c978 Iustin Pop
                    args=(locking.LEVEL_INSTANCE, 'i1', 1))
837 4607c978 Iustin Pop
    self._waitThreads()
838 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
839 4607c978 Iustin Pop
    self._addThread(target=self._doLock,
840 4607c978 Iustin Pop
                    args=(locking.LEVEL_INSTANCE, 'i3', 1))
841 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
842 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
843 4607c978 Iustin Pop
    self._waitThreads()
844 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
845 7ee7c0c7 Guido Trotter
    self.GL.acquire(locking.LEVEL_INSTANCE, ['i2'], shared=1)
846 4607c978 Iustin Pop
    self._addThread(target=self._doLock,
847 4607c978 Iustin Pop
                    args=(locking.LEVEL_INSTANCE, 'i2', 1))
848 4607c978 Iustin Pop
    self._waitThreads()
849 4607c978 Iustin Pop
    self.assertEqual(self.done.get_nowait(), 'DONE')
850 4607c978 Iustin Pop
    self._addThread(target=self._doLock,
851 4607c978 Iustin Pop
                    args=(locking.LEVEL_INSTANCE, 'i2', 0))
852 4607c978 Iustin Pop
    self.assertRaises(Queue.Empty, self.done.get_nowait)
853 7ee7c0c7 Guido Trotter
    self.GL.release(locking.LEVEL_INSTANCE)
854 4607c978 Iustin Pop
    self._waitThreads()
855 7ee7c0c7 Guido Trotter
    self.assertEqual(self.done.get(True, 1), 'DONE')
856 4607c978 Iustin Pop
    self.GL.release(locking.LEVEL_CLUSTER, ['BGL'])
857 7ee7c0c7 Guido Trotter
858 7ee7c0c7 Guido Trotter
859 162c1c1f Guido Trotter
if __name__ == '__main__':
860 162c1c1f Guido Trotter
  unittest.main()
861 162c1c1f Guido Trotter
  #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
862 162c1c1f Guido Trotter
  #unittest.TextTestRunner(verbosity=2).run(suite)