109
104
"""Fail to create lock on readonly transport"""
110
105
t = self.get_readonly_transport()
111
106
lf = LockDir(t, 'test_lock')
112
self.assertRaises(LockFailed, lf.create)
107
self.assertRaises(UnlockableTransport, lf.create)
114
109
def test_12_lock_readonly_transport(self):
115
110
"""Fail to lock on readonly transport"""
116
111
lf = LockDir(self.get_transport(), 'test_lock')
118
113
lf = LockDir(self.get_readonly_transport(), 'test_lock')
119
self.assertRaises(LockFailed, lf.attempt_lock)
114
self.assertRaises(UnlockableTransport, lf.attempt_lock)
121
116
def test_20_lock_contested(self):
122
117
"""Contention to get a lock"""
185
180
after = time.time()
186
181
# it should only take about 0.4 seconds, but we allow more time in
187
182
# case the machine is heavily loaded
188
self.assertTrue(after - before <= 8.0,
183
self.assertTrue(after - before <= 8.0,
189
184
"took %f seconds to detect lock contention" % (after - before))
192
187
lock_base = lf2.transport.abspath(lf2.path)
193
188
self.assertEqual(1, len(self._logged_reports))
194
lock_url = lf2.transport.abspath(lf2.path)
195
189
self.assertEqual('%s %s\n'
197
'Will continue to try until %s, unless '
199
'If you\'re sure that it\'s not being '
200
'modified, use bzr break-lock %s',
191
'Will continue to try until %s\n',
201
192
self._logged_reports[0][0])
202
193
args = self._logged_reports[0][1]
203
194
self.assertEqual('Unable to obtain', args[0])
226
217
def test_32_lock_wait_succeed(self):
227
218
"""Succeed when trying to acquire a lock that gets released
229
One thread holds on a lock and then releases it; another
220
One thread holds on a lock and then releases it; another
230
221
tries to lock it.
232
# This test sometimes fails like this:
233
# Traceback (most recent call last):
235
# File "/home/pqm/bzr-pqm-workdir/home/+trunk/bzrlib/tests/
236
# test_lockdir.py", line 247, in test_32_lock_wait_succeed
237
# self.assertEqual(1, len(self._logged_reports))
238
# AssertionError: not equal:
241
raise tests.TestSkipped("Test fails intermittently")
242
223
t = self.get_transport()
243
224
lf1 = LockDir(t, 'test_lock')
276
257
self.assertEndsWith(args[3], ' ago')
277
258
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
260
def test_33_wait(self):
261
"""Succeed when waiting on a lock that gets released
263
The difference from test_32_lock_wait_succeed is that the second
264
caller does not actually acquire the lock, but just waits for it
265
to be released. This is done over a readonly transport.
267
t = self.get_transport()
268
lf1 = LockDir(t, 'test_lock')
272
def wait_and_unlock():
275
unlocker = Thread(target=wait_and_unlock)
278
lf2 = LockDir(self.get_readonly_transport(), 'test_lock')
280
# wait but don't lock
281
lf2.wait(timeout=0.4, poll=0.1)
283
self.assertTrue(after - before <= 1.0)
279
287
def test_34_lock_write_waits(self):
280
"""LockDir.lock_write() will wait for the lock."""
288
"""LockDir.lock_write() will wait for the lock."""
281
289
# the test suite sets the default to 0 to make deadlocks fail fast.
282
290
# change it for this test, as we want to try a manual deadlock.
283
raise tests.TestSkipped('Timing-sensitive test')
284
291
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 300
285
292
t = self.get_transport()
286
293
lf1 = LockDir(t, 'test_lock')
321
328
def test_35_wait_lock_changing(self):
322
329
"""LockDir.wait_lock() will report if the lock changes underneath.
324
331
This is the stages we want to happen:
326
333
0) Synchronization locks are created and locked.
327
334
1) Lock1 obtains the lockdir, and releases the 'check' lock.
328
335
2) Lock2 grabs the 'check' lock, and checks the lockdir.
329
It sees the lockdir is already acquired, reports the fact,
336
It sees the lockdir is already acquired, reports the fact,
330
337
and unsets the 'checked' lock.
331
338
3) Thread1 blocks on acquiring the 'checked' lock, and then tells
332
339
Lock1 to release and acquire the lockdir. This resets the 'check'
334
341
4) Lock2 acquires the 'check' lock, and checks again. It notices
335
that the holder of the lock has changed, and so reports a new
342
that the holder of the lock has changed, and so reports a new
337
344
5) Thread1 blocks on the 'checked' lock, this time, it completely
338
345
unlocks the lockdir, allowing Lock2 to acquire the lock.
341
raise tests.KnownFailure(
342
"timing dependency in lock tests (#213182)")
344
348
wait_to_check_lock = Lock()
345
349
wait_until_checked_lock = Lock()
414
418
# There should be 2 reports, because the lock changed
415
419
lock_base = lf2.transport.abspath(lf2.path)
416
420
self.assertEqual(2, len(self._logged_reports))
417
lock_url = lf2.transport.abspath(lf2.path)
418
422
self.assertEqual('%s %s\n'
420
'Will continue to try until %s, unless '
422
'If you\'re sure that it\'s not being '
423
'modified, use bzr break-lock %s',
424
'Will continue to try until %s\n',
424
425
self._logged_reports[0][0])
425
426
args = self._logged_reports[0][1]
426
427
self.assertEqual('Unable to obtain', args[0])
616
614
lock_path = ld1.transport.local_abspath('test_lock')
617
615
os.mkdir(lock_path)
618
616
osutils.make_readonly(lock_path)
619
self.assertRaises(errors.LockFailed, ld1.attempt_lock)
621
def test_lock_by_token(self):
622
ld1 = self.get_lock()
623
token = ld1.lock_write()
624
self.assertNotEqual(None, token)
625
ld2 = self.get_lock()
626
t2 = ld2.lock_write(token)
627
self.assertEqual(token, t2)
629
def test_lock_with_buggy_rename(self):
630
# test that lock acquisition handles servers which pretend they
631
# renamed correctly but that actually fail
632
t = transport.get_transport('brokenrename+' + self.get_url())
633
ld1 = LockDir(t, 'test_lock')
636
ld2 = LockDir(t, 'test_lock')
637
# we should fail to lock
638
e = self.assertRaises(errors.LockContention, ld2.attempt_lock)
639
# now the original caller should succeed in unlocking
641
# and there should be nothing left over
642
self.assertEquals([], t.list_dir('test_lock'))
644
def test_failed_lock_leaves_no_trash(self):
645
# if we fail to acquire the lock, we don't leave pending directories
646
# behind -- https://bugs.launchpad.net/bzr/+bug/109169
647
ld1 = self.get_lock()
648
ld2 = self.get_lock()
649
# should be nothing before we start
651
t = self.get_transport().clone('test_lock')
653
self.assertEquals(a, t.list_dir('.'))
655
# when held, that's all we see
658
# second guy should fail
659
self.assertRaises(errors.LockContention, ld2.attempt_lock)
663
def record_hook(self, result):
664
self._calls.append(result)
666
def reset_hooks(self):
667
self._old_hooks = lock.Lock.hooks
668
self.addCleanup(self.restore_hooks)
669
lock.Lock.hooks = lock.LockHooks()
671
def restore_hooks(self):
672
lock.Lock.hooks = self._old_hooks
674
def test_LockDir_acquired_success(self):
675
# the LockDir.lock_acquired hook fires when a lock is acquired.
678
LockDir.hooks.install_named_hook('lock_acquired',
679
self.record_hook, 'record_hook')
682
self.assertEqual([], self._calls)
683
result = ld.attempt_lock()
684
lock_path = ld.transport.abspath(ld.path)
685
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
687
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
689
def test_LockDir_acquired_fail(self):
690
# the LockDir.lock_acquired hook does not fire on failure.
695
ld2 = self.get_lock()
697
# install a lock hook now, when the disk lock is locked
698
LockDir.hooks.install_named_hook('lock_acquired',
699
self.record_hook, 'record_hook')
700
self.assertRaises(errors.LockContention, ld.attempt_lock)
701
self.assertEqual([], self._calls)
703
self.assertEqual([], self._calls)
705
def test_LockDir_released_success(self):
706
# the LockDir.lock_released hook fires when a lock is acquired.
709
LockDir.hooks.install_named_hook('lock_released',
710
self.record_hook, 'record_hook')
713
self.assertEqual([], self._calls)
714
result = ld.attempt_lock()
715
self.assertEqual([], self._calls)
717
lock_path = ld.transport.abspath(ld.path)
718
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
720
def test_LockDir_released_fail(self):
721
# the LockDir.lock_released hook does not fire on failure.
726
ld2 = self.get_lock()
728
ld2.force_break(ld2.peek())
729
LockDir.hooks.install_named_hook('lock_released',
730
self.record_hook, 'record_hook')
731
self.assertRaises(LockBroken, ld.unlock)
732
self.assertEqual([], self._calls)
617
self.assertRaises(errors.PermissionDenied, ld1.attempt_lock)