~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_lockdir.py

  • Committer: Martin Pool
  • Date: 2007-04-04 06:17:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2397.
  • Revision ID: mbp@sourcefrog.net-20070404061731-tt2xrzllqhbodn83
Contents of TODO file moved into bug tracker

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
from bzrlib import (
26
26
    config,
27
27
    errors,
28
 
    lock,
29
28
    osutils,
30
29
    tests,
31
 
    transport,
32
30
    )
33
31
from bzrlib.errors import (
34
 
    LockBreakMismatch,
35
 
    LockBroken,
36
 
    LockContention,
37
 
    LockError,
38
 
    LockFailed,
39
 
    LockNotHeld,
40
 
    )
 
32
        LockBreakMismatch,
 
33
        LockContention, LockError, UnlockableTransport,
 
34
        LockNotHeld, LockBroken
 
35
        )
41
36
from bzrlib.lockdir import LockDir
42
37
from bzrlib.tests import TestCaseWithTransport
43
38
from bzrlib.trace import note
109
104
        """Fail to create lock on readonly transport"""
110
105
        t = self.get_readonly_transport()
111
106
        lf = LockDir(t, 'test_lock')
112
 
        self.assertRaises(LockFailed, lf.create)
 
107
        self.assertRaises(UnlockableTransport, lf.create)
113
108
 
114
109
    def test_12_lock_readonly_transport(self):
115
110
        """Fail to lock on readonly transport"""
116
111
        lf = LockDir(self.get_transport(), 'test_lock')
117
112
        lf.create()
118
113
        lf = LockDir(self.get_readonly_transport(), 'test_lock')
119
 
        self.assertRaises(LockFailed, lf.attempt_lock)
 
114
        self.assertRaises(UnlockableTransport, lf.attempt_lock)
120
115
 
121
116
    def test_20_lock_contested(self):
122
117
        """Contention to get a lock"""
191
186
            lf1.unlock()
192
187
        lock_base = lf2.transport.abspath(lf2.path)
193
188
        self.assertEqual(1, len(self._logged_reports))
194
 
        lock_url = lf2.transport.abspath(lf2.path)
195
189
        self.assertEqual('%s %s\n'
196
190
                         '%s\n%s\n'
197
 
                         'Will continue to try until %s, unless '
198
 
                         'you press Ctrl-C\n'
199
 
                         'If you\'re sure that it\'s not being '
200
 
                         'modified, use bzr break-lock %s',
 
191
                         'Will continue to try until %s\n',
201
192
                         self._logged_reports[0][0])
202
193
        args = self._logged_reports[0][1]
203
194
        self.assertEqual('Unable to obtain', args[0])
229
220
        One thread holds on a lock and then releases it; another 
230
221
        tries to lock it.
231
222
        """
232
 
        # This test sometimes fails like this:
233
 
        # Traceback (most recent call last):
234
 
 
235
 
        #   File "/home/pqm/bzr-pqm-workdir/home/+trunk/bzrlib/tests/
236
 
        # test_lockdir.py", line 247, in test_32_lock_wait_succeed
237
 
        #     self.assertEqual(1, len(self._logged_reports))
238
 
        # AssertionError: not equal:
239
 
        # a = 1
240
 
        # b = 0
241
 
        raise tests.TestSkipped("Test fails intermittently")
242
223
        t = self.get_transport()
243
224
        lf1 = LockDir(t, 'test_lock')
244
225
        lf1.create()
276
257
        self.assertEndsWith(args[3], ' ago')
277
258
        self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
278
259
 
 
260
    def test_33_wait(self):
 
261
        """Succeed when waiting on a lock that gets released
 
262
 
 
263
        The difference from test_32_lock_wait_succeed is that the second 
 
264
        caller does not actually acquire the lock, but just waits for it
 
265
        to be released.  This is done over a readonly transport.
 
266
        """
 
267
        t = self.get_transport()
 
268
        lf1 = LockDir(t, 'test_lock')
 
269
        lf1.create()
 
270
        lf1.attempt_lock()
 
271
 
 
272
        def wait_and_unlock():
 
273
            time.sleep(0.1)
 
274
            lf1.unlock()
 
275
        unlocker = Thread(target=wait_and_unlock)
 
276
        unlocker.start()
 
277
        try:
 
278
            lf2 = LockDir(self.get_readonly_transport(), 'test_lock')
 
279
            before = time.time()
 
280
            # wait but don't lock
 
281
            lf2.wait(timeout=0.4, poll=0.1)
 
282
            after = time.time()
 
283
            self.assertTrue(after - before <= 1.0)
 
284
        finally:
 
285
            unlocker.join()
 
286
 
279
287
    def test_34_lock_write_waits(self):
280
288
        """LockDir.lock_write() will wait for the lock.""" 
281
289
        # the test suite sets the default to 0 to make deadlocks fail fast.
282
290
        # change it for this test, as we want to try a manual deadlock.
283
 
        raise tests.TestSkipped('Timing-sensitive test')
284
291
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 300
285
292
        t = self.get_transport()
286
293
        lf1 = LockDir(t, 'test_lock')
338
345
           unlocks the lockdir, allowing Lock2 to acquire the lock.
339
346
        """
340
347
 
341
 
        raise tests.KnownFailure(
342
 
            "timing dependency in lock tests (#213182)")
343
 
 
344
348
        wait_to_check_lock = Lock()
345
349
        wait_until_checked_lock = Lock()
346
350
 
406
410
        unlocker.start()
407
411
        try:
408
412
            # Wait and play against the other thread
409
 
            lf2.wait_lock(timeout=20.0, poll=0.01)
 
413
            lf2.wait_lock(timeout=1.0, poll=0.01)
410
414
        finally:
411
415
            unlocker.join()
412
416
        lf2.unlock()
414
418
        # There should be 2 reports, because the lock changed
415
419
        lock_base = lf2.transport.abspath(lf2.path)
416
420
        self.assertEqual(2, len(self._logged_reports))
417
 
        lock_url = lf2.transport.abspath(lf2.path)
 
421
 
418
422
        self.assertEqual('%s %s\n'
419
423
                         '%s\n%s\n'
420
 
                         'Will continue to try until %s, unless '
421
 
                         'you press Ctrl-C\n'
422
 
                         'If you\'re sure that it\'s not being '
423
 
                         'modified, use bzr break-lock %s',
 
424
                         'Will continue to try until %s\n',
424
425
                         self._logged_reports[0][0])
425
426
        args = self._logged_reports[0][1]
426
427
        self.assertEqual('Unable to obtain', args[0])
432
433
 
433
434
        self.assertEqual('%s %s\n'
434
435
                         '%s\n%s\n'
435
 
                         'Will continue to try until %s, unless '
436
 
                         'you press Ctrl-C\n'
437
 
                         'If you\'re sure that it\'s not being '
438
 
                         'modified, use bzr break-lock %s',
 
436
                         'Will continue to try until %s\n',
439
437
                         self._logged_reports[1][0])
440
438
        args = self._logged_reports[1][1]
441
439
        self.assertEqual('Lock owner changed for', args[0])
616
614
        lock_path = ld1.transport.local_abspath('test_lock')
617
615
        os.mkdir(lock_path)
618
616
        osutils.make_readonly(lock_path)
619
 
        self.assertRaises(errors.LockFailed, ld1.attempt_lock)
620
 
 
621
 
    def test_lock_by_token(self):
622
 
        ld1 = self.get_lock()
623
 
        token = ld1.lock_write()
624
 
        self.assertNotEqual(None, token)
625
 
        ld2 = self.get_lock()
626
 
        t2 = ld2.lock_write(token)
627
 
        self.assertEqual(token, t2)
628
 
 
629
 
    def test_lock_with_buggy_rename(self):
630
 
        # test that lock acquisition handles servers which pretend they
631
 
        # renamed correctly but that actually fail
632
 
        t = transport.get_transport('brokenrename+' + self.get_url())
633
 
        ld1 = LockDir(t, 'test_lock')
634
 
        ld1.create()
635
 
        ld1.attempt_lock()
636
 
        ld2 = LockDir(t, 'test_lock')
637
 
        # we should fail to lock
638
 
        e = self.assertRaises(errors.LockContention, ld2.attempt_lock)
639
 
        # now the original caller should succeed in unlocking
640
 
        ld1.unlock()
641
 
        # and there should be nothing left over
642
 
        self.assertEquals([], t.list_dir('test_lock'))
643
 
 
644
 
    def test_failed_lock_leaves_no_trash(self):
645
 
        # if we fail to acquire the lock, we don't leave pending directories
646
 
        # behind -- https://bugs.launchpad.net/bzr/+bug/109169
647
 
        ld1 = self.get_lock()
648
 
        ld2 = self.get_lock()
649
 
        # should be nothing before we start
650
 
        ld1.create()
651
 
        t = self.get_transport().clone('test_lock')
652
 
        def check_dir(a):
653
 
            self.assertEquals(a, t.list_dir('.'))
654
 
        check_dir([])
655
 
        # when held, that's all we see
656
 
        ld1.attempt_lock()
657
 
        check_dir(['held'])
658
 
        # second guy should fail
659
 
        self.assertRaises(errors.LockContention, ld2.attempt_lock)
660
 
        # no kibble
661
 
        check_dir(['held'])
662
 
 
663
 
    def record_hook(self, result):
664
 
        self._calls.append(result)
665
 
 
666
 
    def reset_hooks(self):
667
 
        self._old_hooks = lock.Lock.hooks
668
 
        self.addCleanup(self.restore_hooks)
669
 
        lock.Lock.hooks = lock.LockHooks()
670
 
 
671
 
    def restore_hooks(self):
672
 
        lock.Lock.hooks = self._old_hooks
673
 
 
674
 
    def test_LockDir_acquired_success(self):
675
 
        # the LockDir.lock_acquired hook fires when a lock is acquired.
676
 
        self._calls = []
677
 
        self.reset_hooks()
678
 
        LockDir.hooks.install_named_hook('lock_acquired',
679
 
            self.record_hook, 'record_hook')
680
 
        ld = self.get_lock()
681
 
        ld.create()
682
 
        self.assertEqual([], self._calls)
683
 
        result = ld.attempt_lock()
684
 
        lock_path = ld.transport.abspath(ld.path)
685
 
        self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
686
 
        ld.unlock()
687
 
        self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
688
 
 
689
 
    def test_LockDir_acquired_fail(self):
690
 
        # the LockDir.lock_acquired hook does not fire on failure.
691
 
        self._calls = []
692
 
        self.reset_hooks()
693
 
        ld = self.get_lock()
694
 
        ld.create()
695
 
        ld2 = self.get_lock()
696
 
        ld2.attempt_lock()
697
 
        # install a lock hook now, when the disk lock is locked
698
 
        LockDir.hooks.install_named_hook('lock_acquired',
699
 
            self.record_hook, 'record_hook')
700
 
        self.assertRaises(errors.LockContention, ld.attempt_lock)
701
 
        self.assertEqual([], self._calls)
702
 
        ld2.unlock()
703
 
        self.assertEqual([], self._calls)
704
 
 
705
 
    def test_LockDir_released_success(self):
706
 
        # the LockDir.lock_released hook fires when a lock is acquired.
707
 
        self._calls = []
708
 
        self.reset_hooks()
709
 
        LockDir.hooks.install_named_hook('lock_released',
710
 
            self.record_hook, 'record_hook')
711
 
        ld = self.get_lock()
712
 
        ld.create()
713
 
        self.assertEqual([], self._calls)
714
 
        result = ld.attempt_lock()
715
 
        self.assertEqual([], self._calls)
716
 
        ld.unlock()
717
 
        lock_path = ld.transport.abspath(ld.path)
718
 
        self.assertEqual([lock.LockResult(lock_path, result)], self._calls)
719
 
 
720
 
    def test_LockDir_released_fail(self):
721
 
        # the LockDir.lock_released hook does not fire on failure.
722
 
        self._calls = []
723
 
        self.reset_hooks()
724
 
        ld = self.get_lock()
725
 
        ld.create()
726
 
        ld2 = self.get_lock()
727
 
        ld.attempt_lock()
728
 
        ld2.force_break(ld2.peek())
729
 
        LockDir.hooks.install_named_hook('lock_released',
730
 
            self.record_hook, 'record_hook')
731
 
        self.assertRaises(LockBroken, ld.unlock)
732
 
        self.assertEqual([], self._calls)
 
617
        self.assertRaises(errors.PermissionDenied, ld1.attempt_lock)