~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_lockdir.py

  • Committer: Martin von Gagern
  • Date: 2011-06-01 12:53:56 UTC
  • mto: This revision was merged to the branch mainline in revision 6009.
  • Revision ID: martin.vgagern@gmx.net-20110601125356-lwozv2vecea6hxfz
Change from no_decorate to classify as name for the argument.

The command line switch remains as --no-classify, to keep backwards
compatibility.  Users are free to include --no-classify in an alias, and
still use --classify to change back.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
    config,
25
25
    errors,
26
26
    lock,
27
 
    lockdir,
28
27
    osutils,
29
28
    tests,
30
29
    transport,
36
35
    LockFailed,
37
36
    LockNotHeld,
38
37
    )
39
 
from bzrlib.lockdir import (
40
 
    LockDir,
41
 
    LockHeldInfo,
42
 
    )
 
38
from bzrlib.lockdir import LockDir
43
39
from bzrlib.tests import (
44
40
    features,
45
 
    TestCase,
46
41
    TestCaseWithTransport,
47
42
    )
 
43
from bzrlib.trace import note
48
44
 
49
45
# These tests are run on the default transport provided by the test framework
50
46
# (typically a local disk transport).  That can be changed by the --transport
52
48
# implementation are tested separately.  (The main requirement is just that
53
49
# they don't allow overwriting nonempty directories.)
54
50
 
55
 
 
56
51
class TestLockDir(TestCaseWithTransport):
57
52
    """Test LockDir operations"""
58
53
 
146
141
        self.addCleanup(lf1.unlock)
147
142
        # lock is held, should get some info on it
148
143
        info1 = lf1.peek()
149
 
        self.assertEqual(set(info1.info_dict.keys()),
150
 
            set(['user', 'nonce', 'hostname', 'pid', 'start_time']))
 
144
        self.assertEqual(set(info1.keys()),
 
145
                         set(['user', 'nonce', 'hostname', 'pid', 'start_time']))
151
146
        # should get the same info if we look at it through a different
152
147
        # instance
153
148
        info2 = LockDir(t, 'test_lock').peek()
166
161
        self.addCleanup(lf1.unlock)
167
162
        info2 = lf2.peek()
168
163
        self.assertTrue(info2)
169
 
        self.assertEqual(info2.get('nonce'), lf1.nonce)
 
164
        self.assertEqual(info2['nonce'], lf1.nonce)
170
165
 
171
166
    def test_30_lock_wait_fail(self):
172
167
        """Wait on a lock, then fail
189
184
            # it should only take about 0.4 seconds, but we allow more time in
190
185
            # case the machine is heavily loaded
191
186
            self.assertTrue(after - before <= 8.0,
192
 
                "took %f seconds to detect lock contention" % (after - before))
 
187
                    "took %f seconds to detect lock contention" % (after - before))
193
188
        finally:
194
189
            lf1.unlock()
195
190
        self.assertEqual(1, len(self._logged_reports))
196
 
        self.assertContainsRe(self._logged_reports[0][0],
197
 
            r'Unable to obtain lock .* held by jrandom@example\.com on .*'
198
 
            r' \(process #\d+\), acquired .* ago\.\n'
199
 
            r'Will continue to try until \d{2}:\d{2}:\d{2}, unless '
200
 
            r'you press Ctrl-C.\n'
201
 
            r'See "bzr help break-lock" for more.')
 
191
        self.assertEqual(self._logged_reports[0][0],
 
192
            '%s lock %s held by %s\n'
 
193
            'at %s [process #%s], acquired %s.\n'
 
194
            'Will continue to try until %s, unless '
 
195
            'you press Ctrl-C.\n'
 
196
            'See "bzr help break-lock" for more.')
 
197
        start, lock_url, user, hostname, pid, time_ago, deadline_str = \
 
198
            self._logged_reports[0][1]
 
199
        self.assertEqual(start, u'Unable to obtain')
 
200
        self.assertEqual(user, u'jrandom@example.com')
 
201
        # skip hostname
 
202
        self.assertContainsRe(pid, r'\d+')
 
203
        self.assertContainsRe(time_ago, r'.* ago')
 
204
        self.assertContainsRe(deadline_str, r'\d{2}:\d{2}:\d{2}')
202
205
 
203
206
    def test_31_lock_wait_easy(self):
204
207
        """Succeed when waiting on a lock with no contention.
346
349
        ld.create()
347
350
        ld.lock_write()
348
351
        ld.transport.put_bytes_non_atomic('test_lock/held/info', '\0')
349
 
 
350
352
        class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
351
353
            def __init__(self):
352
354
                self.prompts = []
353
 
 
354
355
            def get_boolean(self, prompt):
355
356
                self.prompts.append(('boolean', prompt))
356
357
                return True
357
 
 
358
358
        ui = LoggingUIFactory()
359
359
        self.overrideAttr(bzrlib.ui, 'ui_factory', ui)
360
360
        ld2.break_lock()
372
372
        ld.create()
373
373
        ld.lock_write()
374
374
        ld.transport.delete('test_lock/held/info')
375
 
 
376
375
        class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
377
376
            def __init__(self):
378
377
                self.prompts = []
379
 
 
380
378
            def get_boolean(self, prompt):
381
379
                self.prompts.append(('boolean', prompt))
382
380
                return True
383
 
 
384
381
        ui = LoggingUIFactory()
385
382
        orig_factory = bzrlib.ui.ui_factory
386
383
        bzrlib.ui.ui_factory = ui
419
416
        lf1.unlock()
420
417
        self.assertFalse(t.has('test_lock/held/info'))
421
418
 
422
 
    def test_display_form(self):
 
419
    def test__format_lock_info(self):
423
420
        ld1 = self.get_lock()
424
421
        ld1.create()
425
422
        ld1.lock_write()
426
423
        try:
427
 
            info_list = ld1.peek().to_readable_dict()
 
424
            info_list = ld1._format_lock_info(ld1.peek())
428
425
        finally:
429
426
            ld1.unlock()
430
 
        self.assertEqual(info_list['user'], u'jrandom@example.com')
431
 
        self.assertContainsRe(info_list['pid'], '^\d+$')
432
 
        self.assertContainsRe(info_list['time_ago'], r'^\d+ seconds? ago$')
 
427
        self.assertEqual(info_list[0], u'jrandom@example.com')
 
428
        # info_list[1] is hostname. we skip this.
 
429
        self.assertContainsRe(info_list[2], '^\d+$') # pid
 
430
        self.assertContainsRe(info_list[3], r'^\d+ seconds? ago$') # time_ago
433
431
 
434
432
    def test_lock_without_email(self):
435
433
        global_config = config.GlobalConfig()
463
461
    def test_lock_with_buggy_rename(self):
464
462
        # test that lock acquisition handles servers which pretend they
465
463
        # renamed correctly but that actually fail
466
 
        t = transport.get_transport_from_url(
467
 
            'brokenrename+' + self.get_url())
 
464
        t = transport.get_transport('brokenrename+' + self.get_url())
468
465
        ld1 = LockDir(t, 'test_lock')
469
466
        ld1.create()
470
467
        ld1.attempt_lock()
484
481
        # should be nothing before we start
485
482
        ld1.create()
486
483
        t = self.get_transport().clone('test_lock')
487
 
 
488
484
        def check_dir(a):
489
485
            self.assertEquals(a, t.list_dir('.'))
490
 
 
491
486
        check_dir([])
492
487
        # when held, that's all we see
493
488
        ld1.attempt_lock()
510
505
        t.put_bytes('test_lock/held/info', '')
511
506
        lf = LockDir(t, 'test_lock')
512
507
        info = lf.peek()
513
 
        formatted_info = info.to_readable_dict()
 
508
        formatted_info = lf._format_lock_info(info)
514
509
        self.assertEquals(
515
 
            dict(user='<unknown>', hostname='<unknown>', pid='<unknown>',
516
 
                time_ago='(unknown)'),
 
510
            ['<unknown>', '<unknown>', '<unknown>', '(unknown)'],
517
511
            formatted_info)
518
512
 
519
513
    def test_corrupt_lockdir_info(self):
652
646
        ld2.force_break(holder_info)
653
647
        lock_path = ld.transport.abspath(ld.path)
654
648
        self.assertEqual([], self._calls)
655
 
 
656
 
 
657
 
class TestLockHeldInfo(TestCase):
658
 
    """Can get information about the lock holder, and detect whether they're
659
 
    still alive."""
660
 
 
661
 
    def test_repr(self):
662
 
        info = LockHeldInfo.for_this_process(None)
663
 
        self.assertContainsRe(repr(info), r"LockHeldInfo\(.*\)")
664
 
 
665
 
    def test_unicode(self):
666
 
        info = LockHeldInfo.for_this_process(None)
667
 
        self.assertContainsRe(unicode(info),
668
 
            r'held by .* on .* \(process #\d+\), acquired .* ago')
669
 
 
670
 
    def test_is_locked_by_this_process(self):
671
 
        info = LockHeldInfo.for_this_process(None)
672
 
        self.assertTrue(info.is_locked_by_this_process())
673
 
 
674
 
    def test_is_not_locked_by_this_process(self):
675
 
        info = LockHeldInfo.for_this_process(None)
676
 
        info.info_dict['pid'] = '123123123123123'
677
 
        self.assertFalse(info.is_locked_by_this_process())
678
 
 
679
 
    def test_lock_holder_live_process(self):
680
 
        """Detect that the holder (this process) is still running."""
681
 
        info = LockHeldInfo.for_this_process(None)
682
 
        self.assertFalse(info.is_lock_holder_known_dead())
683
 
 
684
 
    def test_lock_holder_dead_process(self):
685
 
        """Detect that the holder (this process) is still running."""
686
 
        self.overrideAttr(lockdir, 'get_host_name',
687
 
            lambda: 'aproperhostname')
688
 
        info = LockHeldInfo.for_this_process(None)
689
 
        info.info_dict['pid'] = '123123123'
690
 
        self.assertTrue(info.is_lock_holder_known_dead())
691
 
 
692
 
    def test_lock_holder_other_machine(self):
693
 
        """The lock holder isn't here so we don't know if they're alive."""
694
 
        info = LockHeldInfo.for_this_process(None)
695
 
        info.info_dict['hostname'] = 'egg.example.com'
696
 
        info.info_dict['pid'] = '123123123'
697
 
        self.assertFalse(info.is_lock_holder_known_dead())
698
 
 
699
 
    def test_lock_holder_other_user(self):
700
 
        """Only auto-break locks held by this user."""
701
 
        info = LockHeldInfo.for_this_process(None)
702
 
        info.info_dict['user'] = 'notme@example.com'
703
 
        info.info_dict['pid'] = '123123123'
704
 
        self.assertFalse(info.is_lock_holder_known_dead())
705
 
 
706
 
    def test_no_good_hostname(self):
707
 
        """Correctly handle ambiguous hostnames.
708
 
 
709
 
        If the lock's recorded with just 'localhost' we can't really trust
710
 
        it's the same 'localhost'.  (There are quite a few of them. :-)
711
 
        So even if the process is known not to be alive, we can't say that's
712
 
        known for sure.
713
 
        """
714
 
        self.overrideAttr(lockdir, 'get_host_name',
715
 
            lambda: 'localhost')
716
 
        info = LockHeldInfo.for_this_process(None)
717
 
        info.info_dict['pid'] = '123123123'
718
 
        self.assertFalse(info.is_lock_holder_known_dead())
719
 
 
720
 
 
721
 
class TestStaleLockDir(TestCaseWithTransport):
722
 
    """Can automatically break stale locks.
723
 
 
724
 
    :see: https://bugs.launchpad.net/bzr/+bug/220464
725
 
    """
726
 
 
727
 
    def test_auto_break_stale_lock(self):
728
 
        """Locks safely known to be stale are just cleaned up.
729
 
 
730
 
        This generates a warning but no other user interaction.
731
 
        """
732
 
        self.overrideAttr(lockdir, 'get_host_name',
733
 
            lambda: 'aproperhostname')
734
 
        # This is off by default at present; see the discussion in the bug.
735
 
        # If you change the default, don't forget to update the docs.
736
 
        config.GlobalConfig().set_user_option('locks.steal_dead', True)
737
 
        # Create a lock pretending to come from a different nonexistent
738
 
        # process on the same machine.
739
 
        l1 = LockDir(self.get_transport(), 'a',
740
 
            extra_holder_info={'pid': '12312313'})
741
 
        token_1 = l1.attempt_lock()
742
 
        l2 = LockDir(self.get_transport(), 'a')
743
 
        token_2 = l2.attempt_lock()
744
 
        # l1 will notice its lock was stolen.
745
 
        self.assertRaises(errors.LockBroken,
746
 
            l1.unlock)
747
 
        l2.unlock()
748
 
 
749
 
    def test_auto_break_stale_lock_configured_off(self):
750
 
        """Automatic breaking can be turned off"""
751
 
        l1 = LockDir(self.get_transport(), 'a',
752
 
            extra_holder_info={'pid': '12312313'})
753
 
        token_1 = l1.attempt_lock()
754
 
        self.addCleanup(l1.unlock)
755
 
        l2 = LockDir(self.get_transport(), 'a')
756
 
        # This fails now, because dead lock breaking is off by default.
757
 
        self.assertRaises(LockContention,
758
 
            l2.attempt_lock)
759
 
        # and it's in fact not broken
760
 
        l1.confirm()