test-lock.py
316 lines
| 9.7 KiB
| text/x-python
|
PythonLexer
/ tests / test-lock.py
Siddharth Agarwal
|
r26289 | from __future__ import absolute_import | ||
Siddharth Agarwal
|
r26386 | import copy | ||
FUJIWARA Katsunori
|
r32089 | import errno | ||
Siddharth Agarwal
|
r26289 | import tempfile | ||
Siddharth Agarwal
|
r26386 | import types | ||
Siddharth Agarwal
|
r26289 | import unittest | ||
FUJIWARA Katsunori
|
r40240 | import silenttestrunner | ||
Siddharth Agarwal
|
r26289 | from mercurial import ( | ||
Matt Harbison
|
r39984 | encoding, | ||
Siddharth Agarwal
|
r26498 | error, | ||
Siddharth Agarwal
|
r26289 | lock, | ||
Pierre-Yves David
|
r31249 | vfs as vfsmod, | ||
Siddharth Agarwal
|
r26289 | ) | ||
Matt Harbison
|
r39984 | testlockname = b'testlock' | ||
Siddharth Agarwal
|
r26289 | |||
Siddharth Agarwal
|
r26386 | # work around http://bugs.python.org/issue1515 | ||
if types.MethodType not in copy._deepcopy_dispatch: | ||||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26386 | def _deepcopy_method(x, memo): | ||
Augie Fackler
|
r34727 | return type(x)(x.__func__, copy.deepcopy(x.__self__, memo), x.im_class) | ||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26386 | copy._deepcopy_dispatch[types.MethodType] = _deepcopy_method | ||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26384 | class lockwrapper(lock.lock): | ||
def __init__(self, pidoffset, *args, **kwargs): | ||||
# lock.lock.__init__() calls lock(), so the pidoffset assignment needs | ||||
# to be earlier | ||||
self._pidoffset = pidoffset | ||||
super(lockwrapper, self).__init__(*args, **kwargs) | ||||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26384 | def _getpid(self): | ||
timeless
|
r28027 | return super(lockwrapper, self)._getpid() + self._pidoffset | ||
Siddharth Agarwal
|
r26384 | |||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26289 | class teststate(object): | ||
Siddharth Agarwal
|
r26385 | def __init__(self, testcase, dir, pidoffset=0): | ||
Siddharth Agarwal
|
r26289 | self._testcase = testcase | ||
Siddharth Agarwal
|
r26321 | self._acquirecalled = False | ||
Siddharth Agarwal
|
r26289 | self._releasecalled = False | ||
self._postreleasecalled = False | ||||
Pierre-Yves David
|
r31249 | self.vfs = vfsmod.vfs(dir, audit=False) | ||
Siddharth Agarwal
|
r26385 | self._pidoffset = pidoffset | ||
Siddharth Agarwal
|
r26289 | |||
def makelock(self, *args, **kwargs): | ||||
Augie Fackler
|
r43346 | l = lockwrapper( | ||
self._pidoffset, | ||||
self.vfs, | ||||
testlockname, | ||||
releasefn=self.releasefn, | ||||
acquirefn=self.acquirefn, | ||||
*args, | ||||
**kwargs | ||||
) | ||||
Siddharth Agarwal
|
r26289 | l.postrelease.append(self.postreleasefn) | ||
return l | ||||
Siddharth Agarwal
|
r26321 | def acquirefn(self): | ||
self._acquirecalled = True | ||||
Siddharth Agarwal
|
r26289 | def releasefn(self): | ||
self._releasecalled = True | ||||
Kyle Lippincott
|
r44217 | def postreleasefn(self, success): | ||
Siddharth Agarwal
|
r26289 | self._postreleasecalled = True | ||
Siddharth Agarwal
|
r26321 | def assertacquirecalled(self, called): | ||
self._testcase.assertEqual( | ||||
Augie Fackler
|
r43346 | self._acquirecalled, | ||
called, | ||||
'expected acquire to be %s but was actually %s' | ||||
% (self._tocalled(called), self._tocalled(self._acquirecalled),), | ||||
) | ||||
Siddharth Agarwal
|
r26321 | |||
def resetacquirefn(self): | ||||
self._acquirecalled = False | ||||
Siddharth Agarwal
|
r26289 | def assertreleasecalled(self, called): | ||
self._testcase.assertEqual( | ||||
Augie Fackler
|
r43346 | self._releasecalled, | ||
called, | ||||
'expected release to be %s but was actually %s' | ||||
% (self._tocalled(called), self._tocalled(self._releasecalled),), | ||||
) | ||||
Siddharth Agarwal
|
r26289 | |||
def assertpostreleasecalled(self, called): | ||||
self._testcase.assertEqual( | ||||
Augie Fackler
|
r43346 | self._postreleasecalled, | ||
called, | ||||
'expected postrelease to be %s but was actually %s' | ||||
% ( | ||||
Siddharth Agarwal
|
r26289 | self._tocalled(called), | ||
self._tocalled(self._postreleasecalled), | ||||
Augie Fackler
|
r43346 | ), | ||
) | ||||
Siddharth Agarwal
|
r26289 | |||
def assertlockexists(self, exists): | ||||
actual = self.vfs.lexists(testlockname) | ||||
self._testcase.assertEqual( | ||||
Augie Fackler
|
r43346 | actual, | ||
exists, | ||||
'expected lock to %s but actually did %s' | ||||
% (self._toexists(exists), self._toexists(actual),), | ||||
) | ||||
Siddharth Agarwal
|
r26289 | |||
def _tocalled(self, called): | ||||
if called: | ||||
return 'called' | ||||
else: | ||||
return 'not called' | ||||
def _toexists(self, exists): | ||||
if exists: | ||||
Siddharth Agarwal
|
r26381 | return 'exist' | ||
Siddharth Agarwal
|
r26289 | else: | ||
Siddharth Agarwal
|
r26381 | return 'not exist' | ||
Siddharth Agarwal
|
r26289 | |||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26289 | class testlock(unittest.TestCase): | ||
def testlock(self): | ||||
Matt Harbison
|
r39984 | state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd())) | ||
Siddharth Agarwal
|
r26289 | lock = state.makelock() | ||
Siddharth Agarwal
|
r26321 | state.assertacquirecalled(True) | ||
Siddharth Agarwal
|
r26289 | lock.release() | ||
state.assertreleasecalled(True) | ||||
state.assertpostreleasecalled(True) | ||||
state.assertlockexists(False) | ||||
def testrecursivelock(self): | ||||
Matt Harbison
|
r39984 | state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd())) | ||
Siddharth Agarwal
|
r26289 | lock = state.makelock() | ||
Siddharth Agarwal
|
r26321 | state.assertacquirecalled(True) | ||
state.resetacquirefn() | ||||
Siddharth Agarwal
|
r26289 | lock.lock() | ||
Siddharth Agarwal
|
r26321 | # recursive lock should not call acquirefn again | ||
state.assertacquirecalled(False) | ||||
Augie Fackler
|
r43346 | lock.release() # brings lock refcount down from 2 to 1 | ||
Siddharth Agarwal
|
r26289 | state.assertreleasecalled(False) | ||
state.assertpostreleasecalled(False) | ||||
state.assertlockexists(True) | ||||
Augie Fackler
|
r43346 | lock.release() # releases the lock | ||
Siddharth Agarwal
|
r26289 | state.assertreleasecalled(True) | ||
state.assertpostreleasecalled(True) | ||||
state.assertlockexists(False) | ||||
def testlockfork(self): | ||||
Matt Harbison
|
r39984 | state = teststate(self, tempfile.mkdtemp(dir=encoding.getcwd())) | ||
Siddharth Agarwal
|
r26289 | lock = state.makelock() | ||
Siddharth Agarwal
|
r26321 | state.assertacquirecalled(True) | ||
Siddharth Agarwal
|
r26386 | |||
Siddharth Agarwal
|
r26289 | # fake a fork | ||
Gregory Szorc
|
r41622 | forklock = copy.copy(lock) | ||
Siddharth Agarwal
|
r26386 | forklock._pidoffset = 1 | ||
forklock.release() | ||||
Siddharth Agarwal
|
r26289 | state.assertreleasecalled(False) | ||
state.assertpostreleasecalled(False) | ||||
state.assertlockexists(True) | ||||
# release the actual lock | ||||
lock.release() | ||||
state.assertreleasecalled(True) | ||||
state.assertpostreleasecalled(True) | ||||
state.assertlockexists(False) | ||||
Siddharth Agarwal
|
r26387 | def testinheritlock(self): | ||
Matt Harbison
|
r39984 | d = tempfile.mkdtemp(dir=encoding.getcwd()) | ||
Siddharth Agarwal
|
r26387 | parentstate = teststate(self, d) | ||
parentlock = parentstate.makelock() | ||||
parentstate.assertacquirecalled(True) | ||||
# set up lock inheritance | ||||
Siddharth Agarwal
|
r26473 | with parentlock.inherit() as lockname: | ||
parentstate.assertreleasecalled(True) | ||||
parentstate.assertpostreleasecalled(False) | ||||
parentstate.assertlockexists(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | childstate = teststate(self, d, pidoffset=1) | ||
childlock = childstate.makelock(parentlock=lockname) | ||||
childstate.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | childlock.release() | ||
childstate.assertreleasecalled(True) | ||||
Siddharth Agarwal
|
r26474 | childstate.assertpostreleasecalled(False) | ||
Siddharth Agarwal
|
r26473 | childstate.assertlockexists(True) | ||
parentstate.resetacquirefn() | ||||
Siddharth Agarwal
|
r26387 | parentstate.assertacquirecalled(True) | ||
parentlock.release() | ||||
parentstate.assertreleasecalled(True) | ||||
parentstate.assertpostreleasecalled(True) | ||||
parentstate.assertlockexists(False) | ||||
def testmultilock(self): | ||||
Matt Harbison
|
r39984 | d = tempfile.mkdtemp(dir=encoding.getcwd()) | ||
Siddharth Agarwal
|
r26387 | state0 = teststate(self, d) | ||
lock0 = state0.makelock() | ||||
state0.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26473 | with lock0.inherit() as lock0name: | ||
state0.assertreleasecalled(True) | ||||
state0.assertpostreleasecalled(False) | ||||
state0.assertlockexists(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | state1 = teststate(self, d, pidoffset=1) | ||
lock1 = state1.makelock(parentlock=lock0name) | ||||
state1.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | # from within lock1, acquire another lock | ||
with lock1.inherit() as lock1name: | ||||
# since the file on disk is lock0's this should have the same | ||||
# name | ||||
self.assertEqual(lock0name, lock1name) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | state2 = teststate(self, d, pidoffset=2) | ||
lock2 = state2.makelock(parentlock=lock1name) | ||||
state2.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | lock2.release() | ||
state2.assertreleasecalled(True) | ||||
Siddharth Agarwal
|
r26474 | state2.assertpostreleasecalled(False) | ||
Siddharth Agarwal
|
r26473 | state2.assertlockexists(True) | ||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | state1.resetacquirefn() | ||
state1.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | lock1.release() | ||
state1.assertreleasecalled(True) | ||||
Siddharth Agarwal
|
r26474 | state1.assertpostreleasecalled(False) | ||
Siddharth Agarwal
|
r26473 | state1.assertlockexists(True) | ||
Siddharth Agarwal
|
r26387 | |||
lock0.release() | ||||
def testinheritlockfork(self): | ||||
Matt Harbison
|
r39984 | d = tempfile.mkdtemp(dir=encoding.getcwd()) | ||
Siddharth Agarwal
|
r26387 | parentstate = teststate(self, d) | ||
parentlock = parentstate.makelock() | ||||
parentstate.assertacquirecalled(True) | ||||
# set up lock inheritance | ||||
Siddharth Agarwal
|
r26473 | with parentlock.inherit() as lockname: | ||
childstate = teststate(self, d, pidoffset=1) | ||||
childlock = childstate.makelock(parentlock=lockname) | ||||
childstate.assertacquirecalled(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | # fork the child lock | ||
Gregory Szorc
|
r41622 | forkchildlock = copy.copy(childlock) | ||
Siddharth Agarwal
|
r26473 | forkchildlock._pidoffset += 1 | ||
forkchildlock.release() | ||||
childstate.assertreleasecalled(False) | ||||
childstate.assertpostreleasecalled(False) | ||||
childstate.assertlockexists(True) | ||||
Siddharth Agarwal
|
r26387 | |||
Siddharth Agarwal
|
r26473 | # release the child lock | ||
childlock.release() | ||||
childstate.assertreleasecalled(True) | ||||
Siddharth Agarwal
|
r26474 | childstate.assertpostreleasecalled(False) | ||
Siddharth Agarwal
|
r26473 | childstate.assertlockexists(True) | ||
Siddharth Agarwal
|
r26387 | |||
parentlock.release() | ||||
Siddharth Agarwal
|
r26498 | def testinheritcheck(self): | ||
Matt Harbison
|
r39984 | d = tempfile.mkdtemp(dir=encoding.getcwd()) | ||
Siddharth Agarwal
|
r26498 | state = teststate(self, d) | ||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26498 | def check(): | ||
raise error.LockInheritanceContractViolation('check failed') | ||||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26498 | lock = state.makelock(inheritchecker=check) | ||
state.assertacquirecalled(True) | ||||
Gregory Szorc
|
r32279 | with self.assertRaises(error.LockInheritanceContractViolation): | ||
Siddharth Agarwal
|
r26499 | with lock.inherit(): | ||
Siddharth Agarwal
|
r26498 | pass | ||
lock.release() | ||||
FUJIWARA Katsunori
|
r32089 | def testfrequentlockunlock(self): | ||
"""This tests whether lock acquisition fails as expected, even if | ||||
(1) lock can't be acquired (makelock fails by EEXIST), and | ||||
(2) locker info can't be read in (readlock fails by ENOENT) while | ||||
retrying 5 times. | ||||
""" | ||||
Matt Harbison
|
r39984 | d = tempfile.mkdtemp(dir=encoding.getcwd()) | ||
FUJIWARA Katsunori
|
r32089 | state = teststate(self, d) | ||
def emulatefrequentlock(*args): | ||||
raise OSError(errno.EEXIST, "File exists") | ||||
Augie Fackler
|
r43346 | |||
FUJIWARA Katsunori
|
r32089 | def emulatefrequentunlock(*args): | ||
raise OSError(errno.ENOENT, "No such file or directory") | ||||
state.vfs.makelock = emulatefrequentlock | ||||
state.vfs.readlock = emulatefrequentunlock | ||||
try: | ||||
state.makelock(timeout=0) | ||||
self.fail("unexpected lock acquisition") | ||||
except error.LockHeld as why: | ||||
self.assertTrue(why.errno == errno.ETIMEDOUT) | ||||
Gregory Szorc
|
r41623 | self.assertTrue(why.locker == b"") | ||
FUJIWARA Katsunori
|
r32089 | state.assertlockexists(False) | ||
Augie Fackler
|
r43346 | |||
Siddharth Agarwal
|
r26289 | if __name__ == '__main__': | ||
silenttestrunner.main(__name__) | ||||