Add the delete() operation to SharedLock
[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.acquire()
108       self.done.put('DEL')
109       self.sl.release()
110     except errors.LockError:
111       self.done.put('ERR')
112
113   def testSharersCanCoexist(self):
114     self.sl.acquire(shared=1)
115     Thread(target=self._doItSharer).start()
116     self.assert_(self.done.get(True, 1))
117     self.sl.release()
118
119   def testExclusiveBlocksExclusive(self):
120     self.sl.acquire()
121     Thread(target=self._doItExclusive).start()
122     # give it a bit of time to check that it's not actually doing anything
123     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
124     self.sl.release()
125     self.assert_(self.done.get(True, 1))
126
127   def testExclusiveBlocksDelete(self):
128     self.sl.acquire()
129     Thread(target=self._doItDelete).start()
130     # give it a bit of time to check that it's not actually doing anything
131     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
132     self.sl.release()
133     self.assert_(self.done.get(True, 1))
134
135   def testExclusiveBlocksSharer(self):
136     self.sl.acquire()
137     Thread(target=self._doItSharer).start()
138     time.sleep(0.05)
139     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
140     self.sl.release()
141     self.assert_(self.done.get(True, 1))
142
143   def testSharerBlocksExclusive(self):
144     self.sl.acquire(shared=1)
145     Thread(target=self._doItExclusive).start()
146     time.sleep(0.05)
147     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
148     self.sl.release()
149     self.assert_(self.done.get(True, 1))
150
151   def testSharerBlocksDelete(self):
152     self.sl.acquire(shared=1)
153     Thread(target=self._doItDelete).start()
154     time.sleep(0.05)
155     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
156     self.sl.release()
157     self.assert_(self.done.get(True, 1))
158
159   def testWaitingExclusiveBlocksSharer(self):
160     self.sl.acquire(shared=1)
161     # the lock is acquired in shared mode...
162     Thread(target=self._doItExclusive).start()
163     # ...but now an exclusive is waiting...
164     time.sleep(0.05)
165     Thread(target=self._doItSharer).start()
166     # ...so the sharer should be blocked as well
167     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
168     self.sl.release()
169     # The exclusive passed before
170     self.assertEqual(self.done.get(True, 1), 'EXC')
171     self.assertEqual(self.done.get(True, 1), 'SHR')
172
173   def testWaitingSharerBlocksExclusive(self):
174     self.sl.acquire()
175     # the lock is acquired in exclusive mode...
176     Thread(target=self._doItSharer).start()
177     # ...but now a sharer is waiting...
178     time.sleep(0.05)
179     Thread(target=self._doItExclusive).start()
180     # ...the exclusive is waiting too...
181     self.assertRaises(Queue.Empty, self.done.get, True, 0.2)
182     self.sl.release()
183     # The sharer passed before
184     self.assertEqual(self.done.get(True, 1), 'SHR')
185     self.assertEqual(self.done.get(True, 1), 'EXC')
186
187   def testNoNonBlocking(self):
188     self.assertRaises(NotImplementedError, self.sl.acquire, blocking=0)
189     self.assertRaises(NotImplementedError, self.sl.delete, blocking=0)
190     self.sl.acquire()
191     self.sl.delete(blocking=0) # Fine, because the lock is already acquired
192
193   def testDelete(self):
194     self.sl.delete()
195     self.assertRaises(errors.LockError, self.sl.acquire)
196     self.assertRaises(errors.LockError, self.sl.delete)
197
198   def testDeletePendingSharersExclusiveDelete(self):
199     self.sl.acquire()
200     Thread(target=self._doItSharer).start()
201     Thread(target=self._doItSharer).start()
202     time.sleep(0.05)
203     Thread(target=self._doItExclusive).start()
204     Thread(target=self._doItDelete).start()
205     time.sleep(0.05)
206     self.sl.delete()
207     # The two threads who were pending return both ERR
208     self.assertEqual(self.done.get(True, 1), 'ERR')
209     self.assertEqual(self.done.get(True, 1), 'ERR')
210     self.assertEqual(self.done.get(True, 1), 'ERR')
211     self.assertEqual(self.done.get(True, 1), 'ERR')
212
213   def testDeletePendingDeleteExclusiveSharers(self):
214     self.sl.acquire()
215     Thread(target=self._doItDelete).start()
216     Thread(target=self._doItExclusive).start()
217     time.sleep(0.05)
218     Thread(target=self._doItSharer).start()
219     Thread(target=self._doItSharer).start()
220     time.sleep(0.05)
221     self.sl.delete()
222     # The two threads who were pending return both ERR
223     self.assertEqual(self.done.get(True, 1), 'ERR')
224     self.assertEqual(self.done.get(True, 1), 'ERR')
225     self.assertEqual(self.done.get(True, 1), 'ERR')
226     self.assertEqual(self.done.get(True, 1), 'ERR')
227
228
229 if __name__ == '__main__':
230   unittest.main()
231   #suite = unittest.TestLoader().loadTestsFromTestCase(TestSharedLock)
232   #unittest.TextTestRunner(verbosity=2).run(suite)