191
192
"took %f seconds to detect lock contention" % (after - before))
194
lock_base = lf2.transport.abspath(lf2.path)
195
195
self.assertEqual(1, len(self._logged_reports))
196
lock_url = lf2.transport.abspath(lf2.path)
197
self.assertEqual('%s %s\n'
199
'Will continue to try until %s, unless '
200
'you press Ctrl-C.\n'
201
'See "bzr help break-lock" for more.',
202
self._logged_reports[0][0])
203
args = self._logged_reports[0][1]
204
self.assertEqual('Unable to obtain', args[0])
205
self.assertEqual('lock %s' % (lock_base,), args[1])
206
self.assertStartsWith(args[2], 'held by ')
207
self.assertStartsWith(args[3], 'locked ')
208
self.assertEndsWith(args[3], ' ago')
209
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
196
self.assertEqual(self._logged_reports[0][0],
197
'%s lock %s held by %s\n'
198
'at %s [process #%s], acquired %s.\n'
199
'Will continue to try until %s, unless '
200
'you press Ctrl-C.\n'
201
'See "bzr help break-lock" for more.')
202
start, lock_url, user, hostname, pid, time_ago, deadline_str = \
203
self._logged_reports[0][1]
204
self.assertEqual(start, u'Unable to obtain')
205
self.assertEqual(user, u'jrandom@example.com')
207
self.assertContainsRe(pid, r'\d+')
208
self.assertContainsRe(time_ago, r'.* ago')
209
self.assertContainsRe(deadline_str, r'\d{2}:\d{2}:\d{2}')
211
211
def test_31_lock_wait_easy(self):
212
212
"""Succeed when waiting on a lock with no contention.
566
566
bzrlib.ui.ui_factory = orig_factory
568
def test_break_lock_corrupt_info(self):
569
"""break_lock works even if the info file is corrupt (and tells the UI
573
ld2 = self.get_lock()
576
ld.transport.put_bytes_non_atomic('test_lock/held/info', '\0')
577
class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
580
def get_boolean(self, prompt):
581
self.prompts.append(('boolean', prompt))
583
ui = LoggingUIFactory()
584
self.overrideAttr(bzrlib.ui, 'ui_factory', ui)
586
self.assertLength(1, ui.prompts)
587
self.assertEqual('boolean', ui.prompts[0][0])
588
self.assertStartsWith(ui.prompts[0][1], 'Break (corrupt LockDir')
589
self.assertRaises(LockBroken, ld.unlock)
591
def test_break_lock_missing_info(self):
592
"""break_lock works even if the info file is missing (and tells the UI
596
ld2 = self.get_lock()
599
ld.transport.delete('test_lock/held/info')
600
class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
603
def get_boolean(self, prompt):
604
self.prompts.append(('boolean', prompt))
606
ui = LoggingUIFactory()
607
orig_factory = bzrlib.ui.ui_factory
608
bzrlib.ui.ui_factory = ui
611
self.assertRaises(LockBroken, ld.unlock)
612
self.assertLength(0, ui.prompts)
614
bzrlib.ui.ui_factory = orig_factory
615
# Suppress warnings due to ld not being unlocked
616
# XXX: if lock_broken hook was invoked in this case, this hack would
617
# not be necessary. - Andrew Bennetts, 2010-09-06.
618
del self._lock_actions[:]
568
620
def test_create_missing_base_directory(self):
569
621
"""If LockDir.path doesn't exist, it can be created
597
649
info_list = ld1._format_lock_info(ld1.peek())
600
self.assertEqual('lock %s' % (ld1.transport.abspath(ld1.path),),
602
self.assertContainsRe(info_list[1],
603
r'^held by .* on host .* \[process #\d*\]$')
604
self.assertContainsRe(info_list[2], r'locked \d+ seconds? ago$')
652
self.assertEqual(info_list[0], u'jrandom@example.com')
653
# info_list[1] is hostname. we skip this.
654
self.assertContainsRe(info_list[2], '^\d+$') # pid
655
self.assertContainsRe(info_list[3], r'^\d+ seconds? ago$') # time_ago
606
657
def test_lock_without_email(self):
607
658
global_config = config.GlobalConfig()
669
721
def test_no_lockdir_info(self):
670
722
"""We can cope with empty info files."""
671
723
# This seems like a fairly common failure case - see
672
# <https://bugs.edge.launchpad.net/bzr/+bug/185103> and all its dupes.
724
# <https://bugs.launchpad.net/bzr/+bug/185103> and all its dupes.
673
725
# Processes are often interrupted after opening the file
674
726
# before the actual contents are committed.
675
727
t = self.get_transport()
681
733
formatted_info = lf._format_lock_info(info)
682
734
self.assertEquals(
683
['lock %s' % t.abspath('test_lock'),
684
'held by <unknown> on host <unknown> [process #<unknown>]',
735
['<unknown>', '<unknown>', '<unknown>', '(unknown)'],
738
def test_corrupt_lockdir_info(self):
739
"""We can cope with corrupt (and thus unparseable) info files."""
740
# This seems like a fairly common failure case too - see
741
# <https://bugs.launchpad.net/bzr/+bug/619872> for instance.
742
# In particular some systems tend to fill recently created files with
743
# nul bytes after recovering from a system crash.
744
t = self.get_transport()
746
t.mkdir('test_lock/held')
747
t.put_bytes('test_lock/held/info', '\0')
748
lf = LockDir(t, 'test_lock')
749
self.assertRaises(errors.LockCorrupt, lf.peek)
750
# Currently attempt_lock gives LockContention, but LockCorrupt would be
751
# a reasonable result too.
753
(errors.LockCorrupt, errors.LockContention), lf.attempt_lock)
754
self.assertRaises(errors.LockCorrupt, lf.validate_token, 'fake token')
756
def test_missing_lockdir_info(self):
757
"""We can cope with absent info files."""
758
t = self.get_transport()
760
t.mkdir('test_lock/held')
761
lf = LockDir(t, 'test_lock')
762
# In this case we expect the 'not held' result from peek, because peek
763
# cannot be expected to notice that there is a 'held' directory with no
765
self.assertEqual(None, lf.peek())
766
# And lock/unlock may work or give LockContention (but not any other
770
except LockContention:
771
# LockContention is ok, and expected on Windows
774
# no error is ok, and expected on POSIX (because POSIX allows
775
# os.rename over an empty directory).
777
# Currently raises TokenMismatch, but LockCorrupt would be reasonable
780
(errors.TokenMismatch, errors.LockCorrupt),
781
lf.validate_token, 'fake token')
689
784
class TestLockDirHooks(TestCaseWithTransport):