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
orig_factory = bzrlib.ui.ui_factory
585
bzrlib.ui.ui_factory = ui
588
self.assertLength(1, ui.prompts)
589
self.assertEqual('boolean', ui.prompts[0][0])
590
self.assertStartsWith(ui.prompts[0][1], 'Break (corrupt LockDir')
591
self.assertRaises(LockBroken, ld.unlock)
593
bzrlib.ui.ui_factory = orig_factory
595
def test_break_lock_missing_info(self):
596
"""break_lock works even if the info file is missing (and tells the UI
600
ld2 = self.get_lock()
603
ld.transport.delete('test_lock/held/info')
604
class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
607
def get_boolean(self, prompt):
608
self.prompts.append(('boolean', prompt))
610
ui = LoggingUIFactory()
611
orig_factory = bzrlib.ui.ui_factory
612
bzrlib.ui.ui_factory = ui
615
self.assertRaises(LockBroken, ld.unlock)
616
self.assertLength(0, ui.prompts)
618
bzrlib.ui.ui_factory = orig_factory
619
# Suppress warnings due to ld not being unlocked
620
# XXX: if lock_broken hook was invoked in this case, this hack would
621
# not be necessary. - Andrew Bennetts, 2010-09-06.
622
del self._lock_actions[:]
568
624
def test_create_missing_base_directory(self):
569
625
"""If LockDir.path doesn't exist, it can be created
597
653
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$')
656
self.assertEqual(info_list[0], u'jrandom@example.com')
657
# info_list[1] is hostname. we skip this.
658
self.assertContainsRe(info_list[2], '^\d+$') # pid
659
self.assertContainsRe(info_list[3], r'^\d+ seconds? ago$') # time_ago
606
661
def test_lock_without_email(self):
607
662
global_config = config.GlobalConfig()
669
725
def test_no_lockdir_info(self):
670
726
"""We can cope with empty info files."""
671
727
# This seems like a fairly common failure case - see
672
# <https://bugs.edge.launchpad.net/bzr/+bug/185103> and all its dupes.
728
# <https://bugs.launchpad.net/bzr/+bug/185103> and all its dupes.
673
729
# Processes are often interrupted after opening the file
674
730
# before the actual contents are committed.
675
731
t = self.get_transport()
681
737
formatted_info = lf._format_lock_info(info)
682
738
self.assertEquals(
683
['lock %s' % t.abspath('test_lock'),
684
'held by <unknown> on host <unknown> [process #<unknown>]',
739
['<unknown>', '<unknown>', '<unknown>', '(unknown)'],
742
def test_corrupt_lockdir_info(self):
743
"""We can cope with corrupt (and thus unparseable) info files."""
744
# This seems like a fairly common failure case too - see
745
# <https://bugs.launchpad.net/bzr/+bug/619872> for instance.
746
# In particular some systems tend to fill recently created files with
747
# nul bytes after recovering from a system crash.
748
t = self.get_transport()
750
t.mkdir('test_lock/held')
751
t.put_bytes('test_lock/held/info', '\0')
752
lf = LockDir(t, 'test_lock')
753
self.assertRaises(errors.LockCorrupt, lf.peek)
754
# Currently attempt_lock gives LockContention, but LockCorrupt would be
755
# a reasonable result too.
757
(errors.LockCorrupt, errors.LockContention), lf.attempt_lock)
758
self.assertRaises(errors.LockCorrupt, lf.validate_token, 'fake token')
760
def test_missing_lockdir_info(self):
761
"""We can cope with absent info files."""
762
t = self.get_transport()
764
t.mkdir('test_lock/held')
765
lf = LockDir(t, 'test_lock')
766
# In this case we expect the 'not held' result from peek, because peek
767
# cannot be expected to notice that there is a 'held' directory with no
769
self.assertEqual(None, lf.peek())
770
# And lock/unlock may work or give LockContention (but not any other
774
except LockContention:
775
# LockContention is ok, and expected on Windows
778
# no error is ok, and expected on POSIX (because POSIX allows
779
# os.rename over an empty directory).
781
# Currently raises TokenMismatch, but LockCorrupt would be reasonable
784
(errors.TokenMismatch, errors.LockCorrupt),
785
lf.validate_token, 'fake token')
689
788
class TestLockDirHooks(TestCaseWithTransport):