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