191
191
"took %f seconds to detect lock contention" % (after - before))
194
lock_base = lf2.transport.abspath(lf2.path)
194
195
self.assertEqual(1, len(self._logged_reports))
195
self.assertEqual(self._logged_reports[0][0],
196
'%s lock %s held by %s\n'
197
'at %s [process #%s], acquired %s.\n'
198
'Will continue to try until %s, unless '
199
'you press Ctrl-C.\n'
200
'See "bzr help break-lock" for more.')
201
start, lock_url, user, hostname, pid, time_ago, deadline_str = \
202
self._logged_reports[0][1]
203
self.assertEqual(start, u'Unable to obtain')
204
self.assertEqual(user, u'jrandom@example.com')
206
self.assertContainsRe(pid, r'\d+')
207
self.assertContainsRe(time_ago, r'.* ago')
208
self.assertContainsRe(deadline_str, r'\d{2}:\d{2}:\d{2}')
196
lock_url = lf2.transport.abspath(lf2.path)
197
self.assertEqual('%s %s\n'
199
'Will continue to try until %s, unless '
201
'If you\'re sure that it\'s not being '
202
'modified, use bzr break-lock %s',
203
self._logged_reports[0][0])
204
args = self._logged_reports[0][1]
205
self.assertEqual('Unable to obtain', args[0])
206
self.assertEqual('lock %s' % (lock_base,), args[1])
207
self.assertStartsWith(args[2], 'held by ')
208
self.assertStartsWith(args[3], 'locked ')
209
self.assertEndsWith(args[3], ' ago')
210
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
210
212
def test_31_lock_wait_easy(self):
211
213
"""Succeed when waiting on a lock with no contention.
418
420
self.assertEqual('%s %s\n'
420
422
'Will continue to try until %s, unless '
421
'you press Ctrl-C.\n'
422
'See "bzr help break-lock" for more.',
424
'If you\'re sure that it\'s not being '
425
'modified, use bzr break-lock %s',
423
426
self._logged_reports[0][0])
424
427
args = self._logged_reports[0][1]
425
428
self.assertEqual('Unable to obtain', args[0])
432
435
self.assertEqual('%s %s\n'
434
437
'Will continue to try until %s, unless '
435
'you press Ctrl-C.\n'
436
'See "bzr help break-lock" for more.',
439
'If you\'re sure that it\'s not being '
440
'modified, use bzr break-lock %s',
437
441
self._logged_reports[1][0])
438
442
args = self._logged_reports[1][1]
439
443
self.assertEqual('Lock owner changed for', args[0])
557
561
# do this without IO redirection to ensure it doesn't prompt.
558
562
self.assertRaises(AssertionError, ld1.break_lock)
559
563
orig_factory = bzrlib.ui.ui_factory
560
bzrlib.ui.ui_factory = bzrlib.ui.CannedInputUIFactory([True])
564
# silent ui - no need for stdout
565
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
566
bzrlib.ui.ui_factory.stdin = StringIO("y\n")
563
569
self.assertRaises(LockBroken, ld1.unlock)
565
571
bzrlib.ui.ui_factory = orig_factory
567
def test_break_lock_corrupt_info(self):
568
"""break_lock works even if the info file is corrupt (and tells the UI
572
ld2 = self.get_lock()
575
ld.transport.put_bytes_non_atomic('test_lock/held/info', '\0')
576
class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
579
def get_boolean(self, prompt):
580
self.prompts.append(('boolean', prompt))
582
ui = LoggingUIFactory()
583
orig_factory = bzrlib.ui.ui_factory
584
bzrlib.ui.ui_factory = ui
587
self.assertLength(1, ui.prompts)
588
self.assertEqual('boolean', ui.prompts[0][0])
589
self.assertStartsWith(ui.prompts[0][1], 'Break (corrupt LockDir')
590
self.assertRaises(LockBroken, ld.unlock)
592
bzrlib.ui.ui_factory = orig_factory
594
def test_break_lock_missing_info(self):
595
"""break_lock works even if the info file is missing (and tells the UI
599
ld2 = self.get_lock()
602
ld.transport.delete('test_lock/held/info')
603
class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
606
def get_boolean(self, prompt):
607
self.prompts.append(('boolean', prompt))
609
ui = LoggingUIFactory()
610
orig_factory = bzrlib.ui.ui_factory
611
bzrlib.ui.ui_factory = ui
614
self.assertRaises(LockBroken, ld.unlock)
615
self.assertLength(0, ui.prompts)
617
bzrlib.ui.ui_factory = orig_factory
618
# Suppress warnings due to ld not being unlocked
619
# XXX: if lock_broken hook was invoked in this case, this hack would
620
# not be necessary. - Andrew Bennetts, 2010-09-06.
621
del self._lock_actions[:]
623
573
def test_create_missing_base_directory(self):
624
574
"""If LockDir.path doesn't exist, it can be created
652
602
info_list = ld1._format_lock_info(ld1.peek())
655
self.assertEqual(info_list[0], u'jrandom@example.com')
656
# info_list[1] is hostname. we skip this.
657
self.assertContainsRe(info_list[2], '^\d+$') # pid
658
self.assertContainsRe(info_list[3], r'^\d+ seconds? ago$') # time_ago
605
self.assertEqual('lock %s' % (ld1.transport.abspath(ld1.path),),
607
self.assertContainsRe(info_list[1],
608
r'^held by .* on host .* \[process #\d*\]$')
609
self.assertContainsRe(info_list[2], r'locked \d+ seconds? ago$')
660
611
def test_lock_without_email(self):
661
612
global_config = config.GlobalConfig()
722
672
check_dir(['held'])
724
def test_no_lockdir_info(self):
725
"""We can cope with empty info files."""
726
# This seems like a fairly common failure case - see
727
# <https://bugs.launchpad.net/bzr/+bug/185103> and all its dupes.
728
# Processes are often interrupted after opening the file
729
# before the actual contents are committed.
730
t = self.get_transport()
732
t.mkdir('test_lock/held')
733
t.put_bytes('test_lock/held/info', '')
734
lf = LockDir(t, 'test_lock')
736
formatted_info = lf._format_lock_info(info)
738
['<unknown>', '<unknown>', '<unknown>', '(unknown)'],
741
def test_corrupt_lockdir_info(self):
742
"""We can cope with corrupt (and thus unparseable) info files."""
743
# This seems like a fairly common failure case too - see
744
# <https://bugs.edge.launchpad.net/bzr/+bug/619872> for instance.
745
# In particular some systems tend to fill recently created files with
746
# nul bytes after recovering from a system crash.
747
t = self.get_transport()
749
t.mkdir('test_lock/held')
750
t.put_bytes('test_lock/held/info', '\0')
751
lf = LockDir(t, 'test_lock')
752
self.assertRaises(errors.LockCorrupt, lf.peek)
753
# Currently attempt_lock gives LockContention, but LockCorrupt would be
754
# a reasonable result too.
756
(errors.LockCorrupt, errors.LockContention), lf.attempt_lock)
757
self.assertRaises(errors.LockCorrupt, lf.validate_token, 'fake token')
759
def test_missing_lockdir_info(self):
760
"""We can cope with absent info files."""
761
t = self.get_transport()
763
t.mkdir('test_lock/held')
764
lf = LockDir(t, 'test_lock')
765
# In this case we expect the 'not held' result from peek, because peek
766
# cannot be expected to notice that there is a 'held' directory with no
768
self.assertEqual(None, lf.peek())
769
# And lock/unlock may work or give LockContention (but not any other
773
except LockContention:
774
# LockContention is ok, and expected on Windows
777
# no error is ok, and expected on POSIX (because POSIX allows
778
# os.rename over an empty directory).
780
# Currently raises TokenMismatch, but LockCorrupt would be reasonable
783
(errors.TokenMismatch, errors.LockCorrupt),
784
lf.validate_token, 'fake token')
787
675
class TestLockDirHooks(TestCaseWithTransport):