/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_lockdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-01-14 17:18:23 UTC
  • mfrom: (5536.2.9 fetch-dev-docs)
  • Revision ID: pqm@pqm.ubuntu.com-20110114171823-5gx64sero62ag6r4
(jelmer) Add a developer doc on the topic of fetch. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
16
16
 
17
17
"""Tests for LockDir"""
18
18
 
19
 
from cStringIO import StringIO
20
19
import os
21
20
from threading import Thread, Lock
22
21
import time
34
33
    LockBreakMismatch,
35
34
    LockBroken,
36
35
    LockContention,
37
 
    LockError,
38
36
    LockFailed,
39
37
    LockNotHeld,
40
38
    )
41
39
from bzrlib.lockdir import LockDir
42
 
from bzrlib.tests import TestCaseWithTransport
 
40
from bzrlib.tests import (
 
41
    features,
 
42
    TestCaseWithTransport,
 
43
    )
43
44
from bzrlib.trace import note
44
45
 
45
46
# These tests sometimes use threads to test the behaviour of lock files with
191
192
                    "took %f seconds to detect lock contention" % (after - before))
192
193
        finally:
193
194
            lf1.unlock()
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'
198
 
                         '%s\n%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')
 
206
        # skip hostname
 
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}')
210
210
 
211
211
    def test_31_lock_wait_easy(self):
212
212
        """Succeed when waiting on a lock with no contention.
565
565
        finally:
566
566
            bzrlib.ui.ui_factory = orig_factory
567
567
 
 
568
    def test_break_lock_corrupt_info(self):
 
569
        """break_lock works even if the info file is corrupt (and tells the UI
 
570
        that it is corrupt).
 
571
        """
 
572
        ld = self.get_lock()
 
573
        ld2 = self.get_lock()
 
574
        ld.create()
 
575
        ld.lock_write()
 
576
        ld.transport.put_bytes_non_atomic('test_lock/held/info', '\0')
 
577
        class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
 
578
            def __init__(self):
 
579
                self.prompts = []
 
580
            def get_boolean(self, prompt):
 
581
                self.prompts.append(('boolean', prompt))
 
582
                return True
 
583
        ui = LoggingUIFactory()
 
584
        self.overrideAttr(bzrlib.ui, 'ui_factory', ui)
 
585
        ld2.break_lock()
 
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)
 
590
 
 
591
    def test_break_lock_missing_info(self):
 
592
        """break_lock works even if the info file is missing (and tells the UI
 
593
        that it is corrupt).
 
594
        """
 
595
        ld = self.get_lock()
 
596
        ld2 = self.get_lock()
 
597
        ld.create()
 
598
        ld.lock_write()
 
599
        ld.transport.delete('test_lock/held/info')
 
600
        class LoggingUIFactory(bzrlib.ui.SilentUIFactory):
 
601
            def __init__(self):
 
602
                self.prompts = []
 
603
            def get_boolean(self, prompt):
 
604
                self.prompts.append(('boolean', prompt))
 
605
                return True
 
606
        ui = LoggingUIFactory()
 
607
        orig_factory = bzrlib.ui.ui_factory
 
608
        bzrlib.ui.ui_factory = ui
 
609
        try:
 
610
            ld2.break_lock()
 
611
            self.assertRaises(LockBroken, ld.unlock)
 
612
            self.assertLength(0, ui.prompts)
 
613
        finally:
 
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[:]
 
619
 
568
620
    def test_create_missing_base_directory(self):
569
621
        """If LockDir.path doesn't exist, it can be created
570
622
 
597
649
            info_list = ld1._format_lock_info(ld1.peek())
598
650
        finally:
599
651
            ld1.unlock()
600
 
        self.assertEqual('lock %s' % (ld1.transport.abspath(ld1.path),),
601
 
                         info_list[0])
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
605
656
 
606
657
    def test_lock_without_email(self):
607
658
        global_config = config.GlobalConfig()
613
664
        ld1.unlock()
614
665
 
615
666
    def test_lock_permission(self):
 
667
        self.requireFeature(features.not_running_as_root)
616
668
        if not osutils.supports_posix_readonly():
617
669
            raise tests.TestSkipped('Cannot induce a permission failure')
618
670
        ld1 = self.get_lock()
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()
680
732
        info = lf.peek()
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>]',
685
 
             'locked (unknown)'],
 
735
            ['<unknown>', '<unknown>', '<unknown>', '(unknown)'],
686
736
            formatted_info)
687
737
 
 
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()
 
745
        t.mkdir('test_lock')
 
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.
 
752
        self.assertRaises(
 
753
            (errors.LockCorrupt, errors.LockContention), lf.attempt_lock)
 
754
        self.assertRaises(errors.LockCorrupt, lf.validate_token, 'fake token')
 
755
 
 
756
    def test_missing_lockdir_info(self):
 
757
        """We can cope with absent info files."""
 
758
        t = self.get_transport()
 
759
        t.mkdir('test_lock')
 
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
 
764
        # 'info' file.
 
765
        self.assertEqual(None, lf.peek())
 
766
        # And lock/unlock may work or give LockContention (but not any other
 
767
        # error).
 
768
        try:
 
769
            lf.attempt_lock()
 
770
        except LockContention:
 
771
            # LockContention is ok, and expected on Windows
 
772
            pass
 
773
        else:
 
774
            # no error is ok, and expected on POSIX (because POSIX allows
 
775
            # os.rename over an empty directory).
 
776
            lf.unlock()
 
777
        # Currently raises TokenMismatch, but LockCorrupt would be reasonable
 
778
        # too.
 
779
        self.assertRaises(
 
780
            (errors.TokenMismatch, errors.LockCorrupt),
 
781
            lf.validate_token, 'fake token')
 
782
 
688
783
 
689
784
class TestLockDirHooks(TestCaseWithTransport):
690
785