Add a few SharedLock delete() tests
[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 if __name__ == '__main__':
234   unittest.main()
235   #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
236   #unittest.TextTestRunner(verbosity=2).run(suite)