##// END OF EJS Templates
tests: perform a shallow copy instead of a deep copy...
Gregory Szorc -
r41622:5880b4e7 default
parent child Browse files
Show More
@@ -1,297 +1,297 b''
1 1 from __future__ import absolute_import
2 2
3 3 import copy
4 4 import errno
5 5 import tempfile
6 6 import types
7 7 import unittest
8 8
9 9 import silenttestrunner
10 10
11 11 from mercurial import (
12 12 encoding,
13 13 error,
14 14 lock,
15 15 vfs as vfsmod,
16 16 )
17 17
18 18 testlockname = b'testlock'
19 19
20 20 # work around http://bugs.python.org/issue1515
21 21 if types.MethodType not in copy._deepcopy_dispatch:
22 22 def _deepcopy_method(x, memo):
23 23 return type(x)(x.__func__, copy.deepcopy(x.__self__, memo), x.im_class)
24 24 copy._deepcopy_dispatch[types.MethodType] = _deepcopy_method
25 25
26 26 class lockwrapper(lock.lock):
27 27 def __init__(self, pidoffset, *args, **kwargs):
28 28 # lock.lock.__init__() calls lock(), so the pidoffset assignment needs
29 29 # to be earlier
30 30 self._pidoffset = pidoffset
31 31 super(lockwrapper, self).__init__(*args, **kwargs)
32 32 def _getpid(self):
33 33 return super(lockwrapper, self)._getpid() + self._pidoffset
34 34
35 35 class teststate(object):
36 36 def __init__(self, testcase, dir, pidoffset=0):
37 37 self._testcase = testcase
38 38 self._acquirecalled = False
39 39 self._releasecalled = False
40 40 self._postreleasecalled = False
41 41 self.vfs = vfsmod.vfs(dir, audit=False)
42 42 self._pidoffset = pidoffset
43 43
44 44 def makelock(self, *args, **kwargs):
45 45 l = lockwrapper(self._pidoffset, self.vfs, testlockname,
46 46 releasefn=self.releasefn, acquirefn=self.acquirefn,
47 47 *args, **kwargs)
48 48 l.postrelease.append(self.postreleasefn)
49 49 return l
50 50
51 51 def acquirefn(self):
52 52 self._acquirecalled = True
53 53
54 54 def releasefn(self):
55 55 self._releasecalled = True
56 56
57 57 def postreleasefn(self):
58 58 self._postreleasecalled = True
59 59
60 60 def assertacquirecalled(self, called):
61 61 self._testcase.assertEqual(
62 62 self._acquirecalled, called,
63 63 'expected acquire to be %s but was actually %s' % (
64 64 self._tocalled(called),
65 65 self._tocalled(self._acquirecalled),
66 66 ))
67 67
68 68 def resetacquirefn(self):
69 69 self._acquirecalled = False
70 70
71 71 def assertreleasecalled(self, called):
72 72 self._testcase.assertEqual(
73 73 self._releasecalled, called,
74 74 'expected release to be %s but was actually %s' % (
75 75 self._tocalled(called),
76 76 self._tocalled(self._releasecalled),
77 77 ))
78 78
79 79 def assertpostreleasecalled(self, called):
80 80 self._testcase.assertEqual(
81 81 self._postreleasecalled, called,
82 82 'expected postrelease to be %s but was actually %s' % (
83 83 self._tocalled(called),
84 84 self._tocalled(self._postreleasecalled),
85 85 ))
86 86
87 87 def assertlockexists(self, exists):
88 88 actual = self.vfs.lexists(testlockname)
89 89 self._testcase.assertEqual(
90 90 actual, exists,
91 91 'expected lock to %s but actually did %s' % (
92 92 self._toexists(exists),
93 93 self._toexists(actual),
94 94 ))
95 95
96 96 def _tocalled(self, called):
97 97 if called:
98 98 return 'called'
99 99 else:
100 100 return 'not called'
101 101
102 102 def _toexists(self, exists):
103 103 if exists:
104 104 return 'exist'
105 105 else:
106 106 return 'not exist'
107 107
108 108 class testlock(unittest.TestCase):
109 109 def testlock(self):
110 110 state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd()))
111 111 lock = state.makelock()
112 112 state.assertacquirecalled(True)
113 113 lock.release()
114 114 state.assertreleasecalled(True)
115 115 state.assertpostreleasecalled(True)
116 116 state.assertlockexists(False)
117 117
118 118 def testrecursivelock(self):
119 119 state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd()))
120 120 lock = state.makelock()
121 121 state.assertacquirecalled(True)
122 122
123 123 state.resetacquirefn()
124 124 lock.lock()
125 125 # recursive lock should not call acquirefn again
126 126 state.assertacquirecalled(False)
127 127
128 128 lock.release() # brings lock refcount down from 2 to 1
129 129 state.assertreleasecalled(False)
130 130 state.assertpostreleasecalled(False)
131 131 state.assertlockexists(True)
132 132
133 133 lock.release() # releases the lock
134 134 state.assertreleasecalled(True)
135 135 state.assertpostreleasecalled(True)
136 136 state.assertlockexists(False)
137 137
138 138 def testlockfork(self):
139 139 state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd()))
140 140 lock = state.makelock()
141 141 state.assertacquirecalled(True)
142 142
143 143 # fake a fork
144 forklock = copy.deepcopy(lock)
144 forklock = copy.copy(lock)
145 145 forklock._pidoffset = 1
146 146 forklock.release()
147 147 state.assertreleasecalled(False)
148 148 state.assertpostreleasecalled(False)
149 149 state.assertlockexists(True)
150 150
151 151 # release the actual lock
152 152 lock.release()
153 153 state.assertreleasecalled(True)
154 154 state.assertpostreleasecalled(True)
155 155 state.assertlockexists(False)
156 156
157 157 def testinheritlock(self):
158 158 d = tempfile.mkdtemp(dir=encoding.getcwd())
159 159 parentstate = teststate(self, d)
160 160 parentlock = parentstate.makelock()
161 161 parentstate.assertacquirecalled(True)
162 162
163 163 # set up lock inheritance
164 164 with parentlock.inherit() as lockname:
165 165 parentstate.assertreleasecalled(True)
166 166 parentstate.assertpostreleasecalled(False)
167 167 parentstate.assertlockexists(True)
168 168
169 169 childstate = teststate(self, d, pidoffset=1)
170 170 childlock = childstate.makelock(parentlock=lockname)
171 171 childstate.assertacquirecalled(True)
172 172
173 173 childlock.release()
174 174 childstate.assertreleasecalled(True)
175 175 childstate.assertpostreleasecalled(False)
176 176 childstate.assertlockexists(True)
177 177
178 178 parentstate.resetacquirefn()
179 179
180 180 parentstate.assertacquirecalled(True)
181 181
182 182 parentlock.release()
183 183 parentstate.assertreleasecalled(True)
184 184 parentstate.assertpostreleasecalled(True)
185 185 parentstate.assertlockexists(False)
186 186
187 187 def testmultilock(self):
188 188 d = tempfile.mkdtemp(dir=encoding.getcwd())
189 189 state0 = teststate(self, d)
190 190 lock0 = state0.makelock()
191 191 state0.assertacquirecalled(True)
192 192
193 193 with lock0.inherit() as lock0name:
194 194 state0.assertreleasecalled(True)
195 195 state0.assertpostreleasecalled(False)
196 196 state0.assertlockexists(True)
197 197
198 198 state1 = teststate(self, d, pidoffset=1)
199 199 lock1 = state1.makelock(parentlock=lock0name)
200 200 state1.assertacquirecalled(True)
201 201
202 202 # from within lock1, acquire another lock
203 203 with lock1.inherit() as lock1name:
204 204 # since the file on disk is lock0's this should have the same
205 205 # name
206 206 self.assertEqual(lock0name, lock1name)
207 207
208 208 state2 = teststate(self, d, pidoffset=2)
209 209 lock2 = state2.makelock(parentlock=lock1name)
210 210 state2.assertacquirecalled(True)
211 211
212 212 lock2.release()
213 213 state2.assertreleasecalled(True)
214 214 state2.assertpostreleasecalled(False)
215 215 state2.assertlockexists(True)
216 216
217 217 state1.resetacquirefn()
218 218
219 219 state1.assertacquirecalled(True)
220 220
221 221 lock1.release()
222 222 state1.assertreleasecalled(True)
223 223 state1.assertpostreleasecalled(False)
224 224 state1.assertlockexists(True)
225 225
226 226 lock0.release()
227 227
228 228 def testinheritlockfork(self):
229 229 d = tempfile.mkdtemp(dir=encoding.getcwd())
230 230 parentstate = teststate(self, d)
231 231 parentlock = parentstate.makelock()
232 232 parentstate.assertacquirecalled(True)
233 233
234 234 # set up lock inheritance
235 235 with parentlock.inherit() as lockname:
236 236 childstate = teststate(self, d, pidoffset=1)
237 237 childlock = childstate.makelock(parentlock=lockname)
238 238 childstate.assertacquirecalled(True)
239 239
240 240 # fork the child lock
241 forkchildlock = copy.deepcopy(childlock)
241 forkchildlock = copy.copy(childlock)
242 242 forkchildlock._pidoffset += 1
243 243 forkchildlock.release()
244 244 childstate.assertreleasecalled(False)
245 245 childstate.assertpostreleasecalled(False)
246 246 childstate.assertlockexists(True)
247 247
248 248 # release the child lock
249 249 childlock.release()
250 250 childstate.assertreleasecalled(True)
251 251 childstate.assertpostreleasecalled(False)
252 252 childstate.assertlockexists(True)
253 253
254 254 parentlock.release()
255 255
256 256 def testinheritcheck(self):
257 257 d = tempfile.mkdtemp(dir=encoding.getcwd())
258 258 state = teststate(self, d)
259 259 def check():
260 260 raise error.LockInheritanceContractViolation('check failed')
261 261 lock = state.makelock(inheritchecker=check)
262 262 state.assertacquirecalled(True)
263 263
264 264 with self.assertRaises(error.LockInheritanceContractViolation):
265 265 with lock.inherit():
266 266 pass
267 267
268 268 lock.release()
269 269
270 270 def testfrequentlockunlock(self):
271 271 """This tests whether lock acquisition fails as expected, even if
272 272 (1) lock can't be acquired (makelock fails by EEXIST), and
273 273 (2) locker info can't be read in (readlock fails by ENOENT) while
274 274 retrying 5 times.
275 275 """
276 276
277 277 d = tempfile.mkdtemp(dir=encoding.getcwd())
278 278 state = teststate(self, d)
279 279
280 280 def emulatefrequentlock(*args):
281 281 raise OSError(errno.EEXIST, "File exists")
282 282 def emulatefrequentunlock(*args):
283 283 raise OSError(errno.ENOENT, "No such file or directory")
284 284
285 285 state.vfs.makelock = emulatefrequentlock
286 286 state.vfs.readlock = emulatefrequentunlock
287 287
288 288 try:
289 289 state.makelock(timeout=0)
290 290 self.fail("unexpected lock acquisition")
291 291 except error.LockHeld as why:
292 292 self.assertTrue(why.errno == errno.ETIMEDOUT)
293 293 self.assertTrue(why.locker == "")
294 294 state.assertlockexists(False)
295 295
296 296 if __name__ == '__main__':
297 297 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now