320
323
def test_35_wait_lock_changing(self):
321
324
"""LockDir.wait_lock() will report if the lock changes underneath.
323
326
This is the stages we want to happen:
325
328
0) Synchronization locks are created and locked.
326
329
1) Lock1 obtains the lockdir, and releases the 'check' lock.
327
330
2) Lock2 grabs the 'check' lock, and checks the lockdir.
328
It sees the lockdir is already acquired, reports the fact,
331
It sees the lockdir is already acquired, reports the fact,
329
332
and unsets the 'checked' lock.
330
333
3) Thread1 blocks on acquiring the 'checked' lock, and then tells
331
334
Lock1 to release and acquire the lockdir. This resets the 'check'
333
336
4) Lock2 acquires the 'check' lock, and checks again. It notices
334
that the holder of the lock has changed, and so reports a new
337
that the holder of the lock has changed, and so reports a new
336
339
5) Thread1 blocks on the 'checked' lock, this time, it completely
337
340
unlocks the lockdir, allowing Lock2 to acquire the lock.
654
663
# when held, that's all we see
655
664
ld1.attempt_lock()
665
self.addCleanup(ld1.unlock)
656
666
check_dir(['held'])
657
667
# second guy should fail
658
668
self.assertRaises(errors.LockContention, ld2.attempt_lock)
660
670
check_dir(['held'])
672
def test_no_lockdir_info(self):
673
"""We can cope with empty info files."""
674
# This seems like a fairly common failure case - see
675
# <https://bugs.edge.launchpad.net/bzr/+bug/185103> and all its dupes.
676
# Processes are often interrupted after opening the file
677
# before the actual contents are committed.
678
t = self.get_transport()
680
t.mkdir('test_lock/held')
681
t.put_bytes('test_lock/held/info', '')
682
lf = LockDir(t, 'test_lock')
684
formatted_info = lf._format_lock_info(info)
686
['lock %s' % t.abspath('test_lock'),
687
'held by <unknown> on host <unknown> [process #<unknown>]',
692
class TestLockDirHooks(TestCaseWithTransport):
695
super(TestLockDirHooks, self).setUp()
699
return LockDir(self.get_transport(), 'test_lock')
701
def record_hook(self, result):
702
self._calls.append(result)
704
def test_LockDir_acquired_success(self):
705
# the LockDir.lock_acquired hook fires when a lock is acquired.
706
LockDir.hooks.install_named_hook('lock_acquired',
707
self.record_hook, 'record_hook')
710
self.assertEqual([], self._calls)
711
result = ld.attempt_lock()
712
lock_path = ld.transport.abspath(ld.path)
713
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
715
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
717
def test_LockDir_acquired_fail(self):
718
# the LockDir.lock_acquired hook does not fire on failure.
721
ld2 = self.get_lock()
723
# install a lock hook now, when the disk lock is locked
724
LockDir.hooks.install_named_hook('lock_acquired',
725
self.record_hook, 'record_hook')
726
self.assertRaises(errors.LockContention, ld.attempt_lock)
727
self.assertEqual([], self._calls)
729
self.assertEqual([], self._calls)
731
def test_LockDir_released_success(self):
732
# the LockDir.lock_released hook fires when a lock is acquired.
733
LockDir.hooks.install_named_hook('lock_released',
734
self.record_hook, 'record_hook')
737
self.assertEqual([], self._calls)
738
result = ld.attempt_lock()
739
self.assertEqual([], self._calls)
741
lock_path = ld.transport.abspath(ld.path)
742
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
744
def test_LockDir_released_fail(self):
745
# the LockDir.lock_released hook does not fire on failure.
748
ld2 = self.get_lock()
750
ld2.force_break(ld2.peek())
751
LockDir.hooks.install_named_hook('lock_released',
752
self.record_hook, 'record_hook')
753
self.assertRaises(LockBroken, ld.unlock)
754
self.assertEqual([], self._calls)
756
def test_LockDir_broken_success(self):
757
# the LockDir.lock_broken hook fires when a lock is broken.
760
ld2 = self.get_lock()
761
result = ld.attempt_lock()
762
LockDir.hooks.install_named_hook('lock_broken',
763
self.record_hook, 'record_hook')
764
ld2.force_break(ld2.peek())
765
lock_path = ld.transport.abspath(ld.path)
766
self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
768
def test_LockDir_broken_failure(self):
769
# the LockDir.lock_broken hook does not fires when a lock is already
773
ld2 = self.get_lock()
774
result = ld.attempt_lock()
775
holder_info = ld2.peek()
777
LockDir.hooks.install_named_hook('lock_broken',
778
self.record_hook, 'record_hook')
779
ld2.force_break(holder_info)
780
lock_path = ld.transport.abspath(ld.path)
781
self.assertEqual([], self._calls)