~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-03-11 13:47:06 UTC
  • mfrom: (5051.3.16 use-branch-open)
  • Revision ID: pqm@pqm.ubuntu.com-20100311134706-kaerqhx3lf7xn6rh
(Jelmer) Pass colocated branch names further down the call stack.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests for the Branch facility that are not interface  tests.
18
18
 
19
 
For interface tests see tests/branch_implementations/*.py.
 
19
For interface tests see tests/per_branch/*.py.
20
20
 
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
23
23
"""
24
24
 
25
 
from StringIO import StringIO
 
25
from cStringIO import StringIO
26
26
 
27
27
from bzrlib import (
28
28
    branch as _mod_branch,
29
29
    bzrdir,
30
30
    config,
31
31
    errors,
 
32
    tests,
32
33
    trace,
 
34
    transport,
33
35
    urlutils,
34
36
    )
35
 
from bzrlib.branch import (
36
 
    Branch,
37
 
    BranchHooks,
38
 
    BranchFormat,
39
 
    BranchReferenceFormat,
40
 
    BzrBranch5,
41
 
    BzrBranchFormat5,
42
 
    BzrBranchFormat6,
43
 
    PullResult,
44
 
    )
45
 
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1, 
46
 
                           BzrDir, BzrDirFormat)
47
 
from bzrlib.errors import (NotBranchError,
48
 
                           UnknownFormatError,
49
 
                           UnknownHook,
50
 
                           UnsupportedFormatError,
51
 
                           )
52
 
 
53
 
from bzrlib.tests import TestCase, TestCaseWithTransport
54
 
from bzrlib.transport import get_transport
55
 
 
56
 
 
57
 
class TestDefaultFormat(TestCase):
 
37
 
 
38
 
 
39
class TestDefaultFormat(tests.TestCase):
58
40
 
59
41
    def test_default_format(self):
60
42
        # update this if you change the default branch format
61
 
        self.assertIsInstance(BranchFormat.get_default_format(),
62
 
                BzrBranchFormat6)
 
43
        self.assertIsInstance(_mod_branch.BranchFormat.get_default_format(),
 
44
                _mod_branch.BzrBranchFormat7)
63
45
 
64
46
    def test_default_format_is_same_as_bzrdir_default(self):
65
47
        # XXX: it might be nice if there was only one place the default was
66
 
        # set, but at the moment that's not true -- mbp 20070814 -- 
 
48
        # set, but at the moment that's not true -- mbp 20070814 --
67
49
        # https://bugs.launchpad.net/bzr/+bug/132376
68
 
        self.assertEqual(BranchFormat.get_default_format(),
69
 
                BzrDirFormat.get_default_format().get_branch_format())
 
50
        self.assertEqual(
 
51
            _mod_branch.BranchFormat.get_default_format(),
 
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
70
53
 
71
54
    def test_get_set_default_format(self):
72
55
        # set the format and then set it back again
73
 
        old_format = BranchFormat.get_default_format()
74
 
        BranchFormat.set_default_format(SampleBranchFormat())
 
56
        old_format = _mod_branch.BranchFormat.get_default_format()
 
57
        _mod_branch.BranchFormat.set_default_format(SampleBranchFormat())
75
58
        try:
76
59
            # the default branch format is used by the meta dir format
77
60
            # which is not the default bzrdir format at this point
78
 
            dir = BzrDirMetaFormat1().initialize('memory:///')
 
61
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
79
62
            result = dir.create_branch()
80
63
            self.assertEqual(result, 'A branch')
81
64
        finally:
82
 
            BranchFormat.set_default_format(old_format)
83
 
        self.assertEqual(old_format, BranchFormat.get_default_format())
84
 
 
85
 
 
86
 
class TestBranchFormat5(TestCaseWithTransport):
 
65
            _mod_branch.BranchFormat.set_default_format(old_format)
 
66
        self.assertEqual(old_format,
 
67
                         _mod_branch.BranchFormat.get_default_format())
 
68
 
 
69
 
 
70
class TestBranchFormat5(tests.TestCaseWithTransport):
87
71
    """Tests specific to branch format 5"""
88
72
 
89
73
    def test_branch_format_5_uses_lockdir(self):
90
74
        url = self.get_url()
91
 
        bzrdir = BzrDirMetaFormat1().initialize(url)
92
 
        bzrdir.create_repository()
93
 
        branch = bzrdir.create_branch()
 
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
 
76
        bdir.create_repository()
 
77
        branch = bdir.create_branch()
94
78
        t = self.get_transport()
95
79
        self.log("branch instance is %r" % branch)
96
 
        self.assert_(isinstance(branch, BzrBranch5))
 
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
97
81
        self.assertIsDirectory('.', t)
98
82
        self.assertIsDirectory('.bzr/branch', t)
99
83
        self.assertIsDirectory('.bzr/branch/lock', t)
100
84
        branch.lock_write()
101
 
        try:
102
 
            self.assertIsDirectory('.bzr/branch/lock/held', t)
103
 
        finally:
104
 
            branch.unlock()
 
85
        self.addCleanup(branch.unlock)
 
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
105
87
 
106
88
    def test_set_push_location(self):
107
89
        from bzrlib.config import (locations_config_filename,
130
112
    # recursive section - that is, it appends the branch name.
131
113
 
132
114
 
133
 
class SampleBranchFormat(BranchFormat):
 
115
class SampleBranchFormat(_mod_branch.BranchFormat):
134
116
    """A sample format
135
117
 
136
 
    this format is initializable, unsupported to aid in testing the 
 
118
    this format is initializable, unsupported to aid in testing the
137
119
    open and open_downlevel routines.
138
120
    """
139
121
 
141
123
        """See BzrBranchFormat.get_format_string()."""
142
124
        return "Sample branch format."
143
125
 
144
 
    def initialize(self, a_bzrdir):
 
126
    def initialize(self, a_bzrdir, name=None):
145
127
        """Format 4 branches cannot be created."""
146
 
        t = a_bzrdir.get_branch_transport(self)
 
128
        t = a_bzrdir.get_branch_transport(self, name=name)
147
129
        t.put_bytes('format', self.get_format_string())
148
130
        return 'A branch'
149
131
 
150
132
    def is_supported(self):
151
133
        return False
152
134
 
153
 
    def open(self, transport, _found=False):
 
135
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
154
136
        return "opened branch."
155
137
 
156
138
 
157
 
class TestBzrBranchFormat(TestCaseWithTransport):
 
139
class TestBzrBranchFormat(tests.TestCaseWithTransport):
158
140
    """Tests for the BzrBranchFormat facility."""
159
141
 
160
142
    def test_find_format(self):
161
143
        # is the right format object found for a branch?
162
144
        # create a branch with a few known format objects.
163
 
        # this is not quite the same as 
 
145
        # this is not quite the same as
164
146
        self.build_tree(["foo/", "bar/"])
165
147
        def check_format(format, url):
166
148
            dir = format._matchingbzrdir.initialize(url)
167
149
            dir.create_repository()
168
150
            format.initialize(dir)
169
 
            found_format = BranchFormat.find_format(dir)
 
151
            found_format = _mod_branch.BranchFormat.find_format(dir)
170
152
            self.failUnless(isinstance(found_format, format.__class__))
171
 
        check_format(BzrBranchFormat5(), "bar")
172
 
        
 
153
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
 
154
 
173
155
    def test_find_format_not_branch(self):
174
156
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
175
 
        self.assertRaises(NotBranchError,
176
 
                          BranchFormat.find_format,
 
157
        self.assertRaises(errors.NotBranchError,
 
158
                          _mod_branch.BranchFormat.find_format,
177
159
                          dir)
178
160
 
179
161
    def test_find_format_unknown_format(self):
180
162
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
181
163
        SampleBranchFormat().initialize(dir)
182
 
        self.assertRaises(UnknownFormatError,
183
 
                          BranchFormat.find_format,
 
164
        self.assertRaises(errors.UnknownFormatError,
 
165
                          _mod_branch.BranchFormat.find_format,
184
166
                          dir)
185
167
 
186
168
    def test_register_unregister_format(self):
190
172
        # make a branch
191
173
        format.initialize(dir)
192
174
        # register a format for it.
193
 
        BranchFormat.register_format(format)
 
175
        _mod_branch.BranchFormat.register_format(format)
194
176
        # which branch.Open will refuse (not supported)
195
 
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
 
177
        self.assertRaises(errors.UnsupportedFormatError,
 
178
                          _mod_branch.Branch.open, self.get_url())
196
179
        self.make_branch_and_tree('foo')
197
180
        # but open_downlevel will work
198
 
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
181
        self.assertEqual(
 
182
            format.open(dir),
 
183
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
199
184
        # unregister the format
200
 
        BranchFormat.unregister_format(format)
 
185
        _mod_branch.BranchFormat.unregister_format(format)
201
186
        self.make_branch_and_tree('bar')
202
187
 
203
188
 
214
199
        raise NotImplementedError(self.get_class)
215
200
 
216
201
    def test_creation(self):
217
 
        format = BzrDirMetaFormat1()
 
202
        format = bzrdir.BzrDirMetaFormat1()
218
203
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
219
204
        branch = self.make_branch('a', format=format)
220
205
        self.assertIsInstance(branch, self.get_class())
227
212
        branch = self.make_branch('a', format=self.get_format_name())
228
213
        self.failUnlessExists('a/.bzr/branch/last-revision')
229
214
        self.failIfExists('a/.bzr/branch/revision-history')
 
215
        self.failIfExists('a/.bzr/branch/references')
230
216
 
231
217
    def test_config(self):
232
218
        """Ensure that all configuration data is stored in the branch"""
306
292
                         'locations.conf')
307
293
 
308
294
 
309
 
class TestBranch6(TestBranch67, TestCaseWithTransport):
 
295
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
310
296
 
311
297
    def get_class(self):
312
298
        return _mod_branch.BzrBranch6
327
313
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
328
314
 
329
315
 
330
 
class TestBranch7(TestBranch67, TestCaseWithTransport):
 
316
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
331
317
 
332
318
    def get_class(self):
333
319
        return _mod_branch.BzrBranch7
334
320
 
335
321
    def get_format_name(self):
336
 
        return "development"
 
322
        return "1.9"
337
323
 
338
324
    def get_format_name_subtree(self):
339
325
        return "development-subtree"
377
363
        self.assertTrue(branch.repository.has_revision(revid))
378
364
 
379
365
 
380
 
class TestBranchReference(TestCaseWithTransport):
 
366
class BzrBranch8(tests.TestCaseWithTransport):
 
367
 
 
368
    def make_branch(self, location, format=None):
 
369
        if format is None:
 
370
            format = bzrdir.format_registry.make_bzrdir('1.9')
 
371
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
 
372
        return tests.TestCaseWithTransport.make_branch(
 
373
            self, location, format=format)
 
374
 
 
375
    def create_branch_with_reference(self):
 
376
        branch = self.make_branch('branch')
 
377
        branch._set_all_reference_info({'file-id': ('path', 'location')})
 
378
        return branch
 
379
 
 
380
    @staticmethod
 
381
    def instrument_branch(branch, gets):
 
382
        old_get = branch._transport.get
 
383
        def get(*args, **kwargs):
 
384
            gets.append((args, kwargs))
 
385
            return old_get(*args, **kwargs)
 
386
        branch._transport.get = get
 
387
 
 
388
    def test_reference_info_caching_read_locked(self):
 
389
        gets = []
 
390
        branch = self.create_branch_with_reference()
 
391
        branch.lock_read()
 
392
        self.addCleanup(branch.unlock)
 
393
        self.instrument_branch(branch, gets)
 
394
        branch.get_reference_info('file-id')
 
395
        branch.get_reference_info('file-id')
 
396
        self.assertEqual(1, len(gets))
 
397
 
 
398
    def test_reference_info_caching_read_unlocked(self):
 
399
        gets = []
 
400
        branch = self.create_branch_with_reference()
 
401
        self.instrument_branch(branch, gets)
 
402
        branch.get_reference_info('file-id')
 
403
        branch.get_reference_info('file-id')
 
404
        self.assertEqual(2, len(gets))
 
405
 
 
406
    def test_reference_info_caching_write_locked(self):
 
407
        gets = []
 
408
        branch = self.make_branch('branch')
 
409
        branch.lock_write()
 
410
        self.instrument_branch(branch, gets)
 
411
        self.addCleanup(branch.unlock)
 
412
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
 
413
        path, location = branch.get_reference_info('file-id')
 
414
        self.assertEqual(0, len(gets))
 
415
        self.assertEqual('path2', path)
 
416
        self.assertEqual('location2', location)
 
417
 
 
418
    def test_reference_info_caches_cleared(self):
 
419
        branch = self.make_branch('branch')
 
420
        branch.lock_write()
 
421
        branch.set_reference_info('file-id', 'path2', 'location2')
 
422
        branch.unlock()
 
423
        doppelganger = _mod_branch.Branch.open('branch')
 
424
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
 
425
        self.assertEqual(('path3', 'location3'),
 
426
                         branch.get_reference_info('file-id'))
 
427
 
 
428
class TestBranchReference(tests.TestCaseWithTransport):
381
429
    """Tests for the branch reference facility."""
382
430
 
383
431
    def test_create_open_reference(self):
384
432
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
385
 
        t = get_transport(self.get_url('.'))
 
433
        t = transport.get_transport(self.get_url('.'))
386
434
        t.mkdir('repo')
387
435
        dir = bzrdirformat.initialize(self.get_url('repo'))
388
436
        dir.create_repository()
389
437
        target_branch = dir.create_branch()
390
438
        t.mkdir('branch')
391
439
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
392
 
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
 
440
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
 
441
            branch_dir, target_branch=target_branch)
393
442
        self.assertEqual(made_branch.base, target_branch.base)
394
443
        opened_branch = branch_dir.open_branch()
395
444
        self.assertEqual(opened_branch.base, target_branch.base)
406
455
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
407
456
 
408
457
 
409
 
class TestHooks(TestCase):
 
458
class TestHooks(tests.TestCase):
410
459
 
411
460
    def test_constructor(self):
412
461
        """Check that creating a BranchHooks instance has the right defaults."""
413
 
        hooks = BranchHooks()
 
462
        hooks = _mod_branch.BranchHooks()
414
463
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
415
464
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
416
465
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
417
466
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
418
467
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
419
 
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
 
468
        self.assertTrue("post_uncommit" in hooks,
 
469
                        "post_uncommit not in %s" % hooks)
420
470
        self.assertTrue("post_change_branch_tip" in hooks,
421
471
                        "post_change_branch_tip not in %s" % hooks)
422
472
 
423
473
    def test_installed_hooks_are_BranchHooks(self):
424
474
        """The installed hooks object should be a BranchHooks."""
425
475
        # the installed hooks are saved in self._preserved_hooks.
426
 
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
427
 
 
428
 
 
429
 
class TestPullResult(TestCase):
 
476
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
 
477
                              _mod_branch.BranchHooks)
 
478
 
 
479
 
 
480
class TestPullResult(tests.TestCase):
430
481
 
431
482
    def test_pull_result_to_int(self):
432
483
        # to support old code, the pull result can be used as an int
433
 
        r = PullResult()
 
484
        r = _mod_branch.PullResult()
434
485
        r.old_revno = 10
435
486
        r.new_revno = 20
436
487
        # this usage of results is not recommended for new code (because it
438
489
        # it's still supported
439
490
        a = "%d revisions pulled" % r
440
491
        self.assertEqual(a, "10 revisions pulled")
 
492
 
 
493
    def test_report_changed(self):
 
494
        r = _mod_branch.PullResult()
 
495
        r.old_revid = "old-revid"
 
496
        r.old_revno = 10
 
497
        r.new_revid = "new-revid"
 
498
        r.new_revno = 20
 
499
        f = StringIO()
 
500
        r.report(f)
 
501
        self.assertEqual("Now on revision 20.\n", f.getvalue())
 
502
 
 
503
    def test_report_unchanged(self):
 
504
        r = _mod_branch.PullResult()
 
505
        r.old_revid = "same-revid"
 
506
        r.new_revid = "same-revid"
 
507
        f = StringIO()
 
508
        r.report(f)
 
509
        self.assertEqual("No revisions to pull.\n", f.getvalue())
 
510
 
 
511
 
 
512
class _StubLockable(object):
 
513
    """Helper for TestRunWithWriteLockedTarget."""
 
514
 
 
515
    def __init__(self, calls, unlock_exc=None):
 
516
        self.calls = calls
 
517
        self.unlock_exc = unlock_exc
 
518
 
 
519
    def lock_write(self):
 
520
        self.calls.append('lock_write')
 
521
 
 
522
    def unlock(self):
 
523
        self.calls.append('unlock')
 
524
        if self.unlock_exc is not None:
 
525
            raise self.unlock_exc
 
526
 
 
527
 
 
528
class _ErrorFromCallable(Exception):
 
529
    """Helper for TestRunWithWriteLockedTarget."""
 
530
 
 
531
 
 
532
class _ErrorFromUnlock(Exception):
 
533
    """Helper for TestRunWithWriteLockedTarget."""
 
534
 
 
535
 
 
536
class TestRunWithWriteLockedTarget(tests.TestCase):
 
537
    """Tests for _run_with_write_locked_target."""
 
538
 
 
539
    def setUp(self):
 
540
        tests.TestCase.setUp(self)
 
541
        self._calls = []
 
542
 
 
543
    def func_that_returns_ok(self):
 
544
        self._calls.append('func called')
 
545
        return 'ok'
 
546
 
 
547
    def func_that_raises(self):
 
548
        self._calls.append('func called')
 
549
        raise _ErrorFromCallable()
 
550
 
 
551
    def test_success_unlocks(self):
 
552
        lockable = _StubLockable(self._calls)
 
553
        result = _mod_branch._run_with_write_locked_target(
 
554
            lockable, self.func_that_returns_ok)
 
555
        self.assertEqual('ok', result)
 
556
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
557
 
 
558
    def test_exception_unlocks_and_propagates(self):
 
559
        lockable = _StubLockable(self._calls)
 
560
        self.assertRaises(_ErrorFromCallable,
 
561
                          _mod_branch._run_with_write_locked_target,
 
562
                          lockable, self.func_that_raises)
 
563
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
564
 
 
565
    def test_callable_succeeds_but_error_during_unlock(self):
 
566
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
567
        self.assertRaises(_ErrorFromUnlock,
 
568
                          _mod_branch._run_with_write_locked_target,
 
569
                          lockable, self.func_that_returns_ok)
 
570
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
571
 
 
572
    def test_error_during_unlock_does_not_mask_original_error(self):
 
573
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
 
574
        self.assertRaises(_ErrorFromCallable,
 
575
                          _mod_branch._run_with_write_locked_target,
 
576
                          lockable, self.func_that_raises)
 
577
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
 
578
 
 
579