~bzr-pqm/bzr/bzr.dev

2297.1.2 by Martin Pool
Cleanup imports
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
2
#
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
7
#
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
12
#
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
16
17
"""Tests for the Branch facility that are not interface  tests.
18
4523.1.1 by Martin Pool
Rename tests.branch_implementations to per_branch
19
For interface tests see tests/per_branch/*.py.
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
20
21
For concrete class tests see this file, and for meta-branch tests
22
also see this file.
23
"""
24
1534.4.7 by Robert Collins
Move downlevel check up to the Branch.open logic, removing it from the Branch constructor and deprecating relax_version_check to the same.
25
from StringIO import StringIO
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
26
2230.3.3 by Aaron Bentley
Add more config testing
27
from bzrlib import (
28
    branch as _mod_branch,
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
29
    bzrdir,
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
30
    config,
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
31
    errors,
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
32
    trace,
2230.3.3 by Aaron Bentley
Add more config testing
33
    urlutils,
34
    )
2297.1.2 by Martin Pool
Cleanup imports
35
from bzrlib.branch import (
36
    Branch,
37
    BranchHooks,
38
    BranchFormat,
39
    BranchReferenceFormat,
40
    BzrBranch5,
41
    BzrBranchFormat5,
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
42
    BzrBranchFormat6,
2297.1.3 by Martin Pool
PullResult can pretend to be an int for api compatibility with old .pull()
43
    PullResult,
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
44
    _run_with_write_locked_target,
2297.1.2 by Martin Pool
Cleanup imports
45
    )
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
46
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
47
                           BzrDir, BzrDirFormat)
1534.4.7 by Robert Collins
Move downlevel check up to the Branch.open logic, removing it from the Branch constructor and deprecating relax_version_check to the same.
48
from bzrlib.errors import (NotBranchError,
49
                           UnknownFormatError,
2245.1.3 by Robert Collins
Add install_hook to the BranchHooks class as the official means for installing a hook.
50
                           UnknownHook,
1534.4.7 by Robert Collins
Move downlevel check up to the Branch.open logic, removing it from the Branch constructor and deprecating relax_version_check to the same.
51
                           UnsupportedFormatError,
52
                           )
53
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
54
from bzrlib.tests import TestCase, TestCaseWithTransport
1534.4.4 by Robert Collins
Make BzrBranchFormat.find_format take a transport not a url for efficiency.
55
from bzrlib.transport import get_transport
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
56
3445.2.1 by John Arbash Meinel
Add tests for Branch.missing_revisions and deprecate it.
57
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
58
class TestDefaultFormat(TestCase):
59
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
60
    def test_default_format(self):
61
        # update this if you change the default branch format
62
        self.assertIsInstance(BranchFormat.get_default_format(),
63
                BzrBranchFormat6)
64
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
65
    def test_default_format_is_same_as_bzrdir_default(self):
66
        # XXX: it might be nice if there was only one place the default was
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
67
        # set, but at the moment that's not true -- mbp 20070814 --
2696.3.8 by Martin Pool
doc
68
        # https://bugs.launchpad.net/bzr/+bug/132376
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
69
        self.assertEqual(BranchFormat.get_default_format(),
70
                BzrDirFormat.get_default_format().get_branch_format())
71
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
72
    def test_get_set_default_format(self):
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
73
        # set the format and then set it back again
2297.1.2 by Martin Pool
Cleanup imports
74
        old_format = BranchFormat.get_default_format()
75
        BranchFormat.set_default_format(SampleBranchFormat())
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
76
        try:
77
            # the default branch format is used by the meta dir format
78
            # which is not the default bzrdir format at this point
1685.1.42 by John Arbash Meinel
A couple more fixes to make sure memory:/// works correctly.
79
            dir = BzrDirMetaFormat1().initialize('memory:///')
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
80
            result = dir.create_branch()
81
            self.assertEqual(result, 'A branch')
82
        finally:
2297.1.2 by Martin Pool
Cleanup imports
83
            BranchFormat.set_default_format(old_format)
84
        self.assertEqual(old_format, BranchFormat.get_default_format())
1508.1.25 by Robert Collins
Update per review comments.
85
86
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
87
class TestBranchFormat5(TestCaseWithTransport):
88
    """Tests specific to branch format 5"""
89
90
    def test_branch_format_5_uses_lockdir(self):
91
        url = self.get_url()
1553.5.72 by Martin Pool
Clean up test for Branch5 lockdirs
92
        bzrdir = BzrDirMetaFormat1().initialize(url)
93
        bzrdir.create_repository()
94
        branch = bzrdir.create_branch()
95
        t = self.get_transport()
96
        self.log("branch instance is %r" % branch)
97
        self.assert_(isinstance(branch, BzrBranch5))
98
        self.assertIsDirectory('.', t)
99
        self.assertIsDirectory('.bzr/branch', t)
100
        self.assertIsDirectory('.bzr/branch/lock', t)
1553.5.73 by Martin Pool
Additional test that Branch5 uses lockdir properly
101
        branch.lock_write()
1658.1.5 by Martin Pool
Release more locks taken during test suite
102
        try:
103
            self.assertIsDirectory('.bzr/branch/lock/held', t)
104
        finally:
105
            branch.unlock()
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
106
2230.3.3 by Aaron Bentley
Add more config testing
107
    def test_set_push_location(self):
108
        from bzrlib.config import (locations_config_filename,
109
                                   ensure_config_dir_exists)
110
        ensure_config_dir_exists()
111
        fn = locations_config_filename()
2839.3.1 by Alexander Belchenko
provide non-empty locations.conf for test_branch.TestBranchFormat5.test_set_push_location
112
        # write correct newlines to locations.conf
113
        # by default ConfigObj uses native line-endings for new files
114
        # but uses already existing line-endings if file is not empty
115
        f = open(fn, 'wb')
116
        try:
117
            f.write('# comment\n')
118
        finally:
119
            f.close()
120
2230.3.3 by Aaron Bentley
Add more config testing
121
        branch = self.make_branch('.', format='knit')
122
        branch.set_push_location('foo')
123
        local_path = urlutils.local_path_from_url(branch.base[:-1])
2839.3.1 by Alexander Belchenko
provide non-empty locations.conf for test_branch.TestBranchFormat5.test_set_push_location
124
        self.assertFileEqual("# comment\n"
125
                             "[%s]\n"
2230.3.3 by Aaron Bentley
Add more config testing
126
                             "push_location = foo\n"
3221.7.1 by Matt Nordhoff
Upgrade ConfigObj to version 4.5.1.
127
                             "push_location:policy = norecurse\n" % local_path,
2230.3.3 by Aaron Bentley
Add more config testing
128
                             fn)
129
2230.3.12 by Aaron Bentley
Clean up trailing whitespace
130
    # TODO RBC 20051029 test getting a push location from a branch in a
2230.3.3 by Aaron Bentley
Add more config testing
131
    # recursive section - that is, it appends the branch name.
132
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
133
2297.1.2 by Martin Pool
Cleanup imports
134
class SampleBranchFormat(BranchFormat):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
135
    """A sample format
136
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
137
    this format is initializable, unsupported to aid in testing the
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
138
    open and open_downlevel routines.
139
    """
140
141
    def get_format_string(self):
142
        """See BzrBranchFormat.get_format_string()."""
143
        return "Sample branch format."
144
145
    def initialize(self, a_bzrdir):
146
        """Format 4 branches cannot be created."""
147
        t = a_bzrdir.get_branch_transport(self)
1955.3.9 by John Arbash Meinel
Find more occurrances of put() and replace with put_file or put_bytes
148
        t.put_bytes('format', self.get_format_string())
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
149
        return 'A branch'
150
151
    def is_supported(self):
152
        return False
153
4160.2.16 by Andrew Bennetts
Update SampleBranchFormat in test_branch for ignore_fallbacks parameter.
154
    def open(self, transport, _found=False, ignore_fallbacks=False):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
155
        return "opened branch."
156
157
158
class TestBzrBranchFormat(TestCaseWithTransport):
159
    """Tests for the BzrBranchFormat facility."""
160
161
    def test_find_format(self):
162
        # is the right format object found for a branch?
163
        # create a branch with a few known format objects.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
164
        # this is not quite the same as
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
165
        self.build_tree(["foo/", "bar/"])
166
        def check_format(format, url):
167
            dir = format._matchingbzrdir.initialize(url)
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
168
            dir.create_repository()
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
169
            format.initialize(dir)
2297.1.2 by Martin Pool
Cleanup imports
170
            found_format = BranchFormat.find_format(dir)
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
171
            self.failUnless(isinstance(found_format, format.__class__))
2297.1.2 by Martin Pool
Cleanup imports
172
        check_format(BzrBranchFormat5(), "bar")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
173
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
174
    def test_find_format_not_branch(self):
175
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
176
        self.assertRaises(NotBranchError,
2297.1.2 by Martin Pool
Cleanup imports
177
                          BranchFormat.find_format,
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
178
                          dir)
179
180
    def test_find_format_unknown_format(self):
181
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
182
        SampleBranchFormat().initialize(dir)
183
        self.assertRaises(UnknownFormatError,
2297.1.2 by Martin Pool
Cleanup imports
184
                          BranchFormat.find_format,
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
185
                          dir)
186
187
    def test_register_unregister_format(self):
188
        format = SampleBranchFormat()
189
        # make a control dir
190
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
191
        # make a branch
192
        format.initialize(dir)
193
        # register a format for it.
2297.1.2 by Martin Pool
Cleanup imports
194
        BranchFormat.register_format(format)
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
195
        # which branch.Open will refuse (not supported)
2297.1.2 by Martin Pool
Cleanup imports
196
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
2230.3.22 by Aaron Bentley
Make test suite use format registry default, not BzrDir default
197
        self.make_branch_and_tree('foo')
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
198
        # but open_downlevel will work
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
199
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
200
        # unregister the format
2297.1.2 by Martin Pool
Cleanup imports
201
        BranchFormat.unregister_format(format)
2230.3.22 by Aaron Bentley
Make test suite use format registry default, not BzrDir default
202
        self.make_branch_and_tree('bar')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
203
204
3221.11.2 by Robert Collins
Create basic stackable branch facility.
205
class TestBranch67(object):
206
    """Common tests for both branch 6 and 7 which are mostly the same."""
207
208
    def get_format_name(self):
209
        raise NotImplementedError(self.get_format_name)
210
211
    def get_format_name_subtree(self):
212
        raise NotImplementedError(self.get_format_name)
213
214
    def get_class(self):
215
        raise NotImplementedError(self.get_class)
2230.3.1 by Aaron Bentley
Get branch6 creation working
216
217
    def test_creation(self):
218
        format = BzrDirMetaFormat1()
2230.3.55 by Aaron Bentley
Updates from review
219
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
2230.3.1 by Aaron Bentley
Get branch6 creation working
220
        branch = self.make_branch('a', format=format)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
221
        self.assertIsInstance(branch, self.get_class())
222
        branch = self.make_branch('b', format=self.get_format_name())
223
        self.assertIsInstance(branch, self.get_class())
2230.3.1 by Aaron Bentley
Get branch6 creation working
224
        branch = _mod_branch.Branch.open('a')
3221.11.2 by Robert Collins
Create basic stackable branch facility.
225
        self.assertIsInstance(branch, self.get_class())
2230.3.1 by Aaron Bentley
Get branch6 creation working
226
227
    def test_layout(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
228
        branch = self.make_branch('a', format=self.get_format_name())
2230.3.1 by Aaron Bentley
Get branch6 creation working
229
        self.failUnlessExists('a/.bzr/branch/last-revision')
230
        self.failIfExists('a/.bzr/branch/revision-history')
4273.1.12 by Aaron Bentley
Don't create reference files for older formats.
231
        self.failIfExists('a/.bzr/branch/references')
2230.3.1 by Aaron Bentley
Get branch6 creation working
232
2230.3.3 by Aaron Bentley
Add more config testing
233
    def test_config(self):
234
        """Ensure that all configuration data is stored in the branch"""
3221.11.2 by Robert Collins
Create basic stackable branch facility.
235
        branch = self.make_branch('a', format=self.get_format_name())
2230.3.3 by Aaron Bentley
Add more config testing
236
        branch.set_parent('http://bazaar-vcs.org')
237
        self.failIfExists('a/.bzr/branch/parent')
238
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
239
        branch.set_push_location('sftp://bazaar-vcs.org')
240
        config = branch.get_config()._get_branch_data_config()
2230.3.12 by Aaron Bentley
Clean up trailing whitespace
241
        self.assertEqual('sftp://bazaar-vcs.org',
2230.3.3 by Aaron Bentley
Add more config testing
242
                         config.get_user_option('push_location'))
243
        branch.set_bound_location('ftp://bazaar-vcs.org')
244
        self.failIfExists('a/.bzr/branch/bound')
245
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
246
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
247
    def test_set_revision_history(self):
3567.4.16 by John Arbash Meinel
Use the new BranchBuilder api in a Branch test
248
        builder = self.make_branch_builder('.', format=self.get_format_name())
249
        builder.build_snapshot('foo', None,
250
            [('add', ('', None, 'directory', None))],
251
            message='foo')
252
        builder.build_snapshot('bar', None, [], message='bar')
253
        branch = builder.get_branch()
254
        branch.lock_write()
255
        self.addCleanup(branch.unlock)
256
        branch.set_revision_history(['foo', 'bar'])
257
        branch.set_revision_history(['foo'])
258
        self.assertRaises(errors.NotLefthandHistory,
259
                          branch.set_revision_history, ['bar'])
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
260
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
261
    def do_checkout_test(self, lightweight=False):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
262
        tree = self.make_branch_and_tree('source',
263
            format=self.get_format_name_subtree())
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
264
        subtree = self.make_branch_and_tree('source/subtree',
3221.11.2 by Robert Collins
Create basic stackable branch facility.
265
            format=self.get_format_name_subtree())
2100.3.25 by Aaron Bentley
add subsubtree to test
266
        subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
3221.11.2 by Robert Collins
Create basic stackable branch facility.
267
            format=self.get_format_name_subtree())
2100.3.25 by Aaron Bentley
add subsubtree to test
268
        self.build_tree(['source/subtree/file',
269
                         'source/subtree/subsubtree/file'])
270
        subsubtree.add('file')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
271
        subtree.add('file')
2100.3.25 by Aaron Bentley
add subsubtree to test
272
        subtree.add_reference(subsubtree)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
273
        tree.add_reference(subtree)
274
        tree.commit('a revision')
2100.3.23 by Aaron Bentley
Nested checkouts kinda work
275
        subtree.commit('a subtree file')
2100.3.25 by Aaron Bentley
add subsubtree to test
276
        subsubtree.commit('a subsubtree file')
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
277
        tree.branch.create_checkout('target', lightweight=lightweight)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
278
        self.failUnlessExists('target')
279
        self.failUnlessExists('target/subtree')
280
        self.failUnlessExists('target/subtree/file')
2100.3.25 by Aaron Bentley
add subsubtree to test
281
        self.failUnlessExists('target/subtree/subsubtree/file')
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
282
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
283
        if lightweight:
284
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
285
        else:
286
            self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
287
288
    def test_checkout_with_references(self):
289
        self.do_checkout_test()
290
291
    def test_light_checkout_with_references(self):
292
        self.do_checkout_test(lightweight=True)
2230.3.51 by Aaron Bentley
Store revno for Branch6, set_last_revision -> set_last_revision_info
293
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
294
    def test_set_push(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
295
        branch = self.make_branch('source', format=self.get_format_name())
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
296
        branch.get_config().set_user_option('push_location', 'old',
297
            store=config.STORE_LOCATION)
298
        warnings = []
299
        def warning(*args):
300
            warnings.append(args[0] % args[1:])
301
        _warning = trace.warning
302
        trace.warning = warning
303
        try:
304
            branch.set_push_location('new')
305
        finally:
306
            trace.warning = _warning
307
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
308
                         'locations.conf')
309
3445.2.1 by John Arbash Meinel
Add tests for Branch.missing_revisions and deprecate it.
310
3221.11.2 by Robert Collins
Create basic stackable branch facility.
311
class TestBranch6(TestBranch67, TestCaseWithTransport):
312
313
    def get_class(self):
314
        return _mod_branch.BzrBranch6
315
316
    def get_format_name(self):
317
        return "dirstate-tags"
318
319
    def get_format_name_subtree(self):
320
        return "dirstate-with-subtree"
321
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
322
    def test_set_stacked_on_url_errors(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
323
        branch = self.make_branch('a', format=self.get_format_name())
324
        self.assertRaises(errors.UnstackableBranchFormat,
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
325
            branch.set_stacked_on_url, None)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
326
327
    def test_default_stacked_location(self):
328
        branch = self.make_branch('a', format=self.get_format_name())
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
329
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
330
331
332
class TestBranch7(TestBranch67, TestCaseWithTransport):
333
334
    def get_class(self):
335
        return _mod_branch.BzrBranch7
336
337
    def get_format_name(self):
4241.6.8 by Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil
Add --development6-rich-root, disabling the legacy and unneeded development2 format, and activating the tests for CHK features disabled pending this format. (Robert Collins, John Arbash Meinel, Ian Clatworthy, Vincent Ladeuil)
338
        return "1.9"
3221.11.2 by Robert Collins
Create basic stackable branch facility.
339
340
    def get_format_name_subtree(self):
341
        return "development-subtree"
342
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
343
    def test_set_stacked_on_url_unstackable_repo(self):
3221.11.6 by Robert Collins
Stackable branch fixes.
344
        repo = self.make_repository('a', format='dirstate-tags')
345
        control = repo.bzrdir
346
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
347
        target = self.make_branch('b')
348
        self.assertRaises(errors.UnstackableRepositoryFormat,
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
349
            branch.set_stacked_on_url, target.base)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
350
3242.3.21 by Jonathan Lange
Preserve stacking in clone
351
    def test_clone_stacked_on_unstackable_repo(self):
352
        repo = self.make_repository('a', format='dirstate-tags')
353
        control = repo.bzrdir
354
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
355
        # Calling clone should not raise UnstackableRepositoryFormat.
356
        cloned_bzrdir = control.clone('cloned')
357
3221.11.2 by Robert Collins
Create basic stackable branch facility.
358
    def _test_default_stacked_location(self):
359
        branch = self.make_branch('a', format=self.get_format_name())
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
360
        self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
361
3221.11.8 by Robert Collins
Minimally test stacking and unstacking a repository.
362
    def test_stack_and_unstack(self):
363
        branch = self.make_branch('a', format=self.get_format_name())
3221.11.10 by Robert Collins
Extend set_stacked_on to update the repository with the right external references.
364
        target = self.make_branch_and_tree('b', format=self.get_format_name())
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
365
        branch.set_stacked_on_url(target.branch.base)
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
366
        self.assertEqual(target.branch.base, branch.get_stacked_on_url())
3221.11.10 by Robert Collins
Extend set_stacked_on to update the repository with the right external references.
367
        revid = target.commit('foo')
368
        self.assertTrue(branch.repository.has_revision(revid))
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
369
        branch.set_stacked_on_url(None)
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
370
        self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
3221.11.10 by Robert Collins
Extend set_stacked_on to update the repository with the right external references.
371
        self.assertFalse(branch.repository.has_revision(revid))
3221.11.8 by Robert Collins
Minimally test stacking and unstacking a repository.
372
3221.11.11 by Robert Collins
Ensure opening a stacked branch gives a ready to use repository.
373
    def test_open_opens_stacked_reference(self):
374
        branch = self.make_branch('a', format=self.get_format_name())
375
        target = self.make_branch_and_tree('b', format=self.get_format_name())
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
376
        branch.set_stacked_on_url(target.branch.base)
3221.11.11 by Robert Collins
Ensure opening a stacked branch gives a ready to use repository.
377
        branch = branch.bzrdir.open_branch()
378
        revid = target.commit('foo')
379
        self.assertTrue(branch.repository.has_revision(revid))
380
3221.11.2 by Robert Collins
Create basic stackable branch facility.
381
4273.1.15 by Aaron Bentley
Add reference_info caching.
382
class BzrBranch8(TestCaseWithTransport):
383
384
    def make_branch(self, location, format=None):
385
        if format is None:
386
            format = bzrdir.format_registry.make_bzrdir('1.9')
387
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
388
        return TestCaseWithTransport.make_branch(self, location, format=format)
389
390
    def create_branch_with_reference(self):
391
        branch = self.make_branch('branch')
392
        branch._set_all_reference_info({'file-id': ('path', 'location')})
393
        return branch
394
395
    @staticmethod
396
    def instrument_branch(branch, gets):
397
        old_get = branch._transport.get
398
        def get(*args, **kwargs):
399
            gets.append((args, kwargs))
400
            return old_get(*args, **kwargs)
401
        branch._transport.get = get
402
403
    def test_reference_info_caching_read_locked(self):
404
        gets = []
405
        branch = self.create_branch_with_reference()
406
        branch.lock_read()
407
        self.addCleanup(branch.unlock)
408
        self.instrument_branch(branch, gets)
409
        branch.get_reference_info('file-id')
410
        branch.get_reference_info('file-id')
411
        self.assertEqual(1, len(gets))
412
413
    def test_reference_info_caching_read_unlocked(self):
414
        gets = []
415
        branch = self.create_branch_with_reference()
416
        self.instrument_branch(branch, gets)
417
        branch.get_reference_info('file-id')
418
        branch.get_reference_info('file-id')
419
        self.assertEqual(2, len(gets))
420
421
    def test_reference_info_caching_write_locked(self):
422
        gets = []
423
        branch = self.make_branch('branch')
424
        branch.lock_write()
425
        self.instrument_branch(branch, gets)
426
        self.addCleanup(branch.unlock)
427
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
428
        path, location = branch.get_reference_info('file-id')
429
        self.assertEqual(0, len(gets))
430
        self.assertEqual('path2', path)
431
        self.assertEqual('location2', location)
432
433
    def test_reference_info_caches_cleared(self):
434
        branch = self.make_branch('branch')
435
        branch.lock_write()
436
        branch.set_reference_info('file-id', 'path2', 'location2')
437
        branch.unlock()
438
        doppelganger = Branch.open('branch')
439
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
440
        self.assertEqual(('path3', 'location3'),
441
                         branch.get_reference_info('file-id'))
442
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
443
class TestBranchReference(TestCaseWithTransport):
444
    """Tests for the branch reference facility."""
445
446
    def test_create_open_reference(self):
447
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
448
        t = get_transport(self.get_url('.'))
449
        t.mkdir('repo')
450
        dir = bzrdirformat.initialize(self.get_url('repo'))
451
        dir.create_repository()
452
        target_branch = dir.create_branch()
453
        t.mkdir('branch')
454
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
2297.1.2 by Martin Pool
Cleanup imports
455
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
456
        self.assertEqual(made_branch.base, target_branch.base)
457
        opened_branch = branch_dir.open_branch()
458
        self.assertEqual(opened_branch.base, target_branch.base)
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
459
460
    def test_get_reference(self):
461
        """For a BranchReference, get_reference should reutrn the location."""
462
        branch = self.make_branch('target')
463
        checkout = branch.create_checkout('checkout', lightweight=True)
464
        reference_url = branch.bzrdir.root_transport.abspath('') + '/'
465
        # if the api for create_checkout changes to return different checkout types
466
        # then this file read will fail.
467
        self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
468
        self.assertEqual(reference_url,
2018.5.97 by Andrew Bennetts
Fix more tests.
469
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
2018.5.45 by Andrew Bennetts
Merge from bzr.dev
470
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
471
472
class TestHooks(TestCase):
473
2245.1.2 by Robert Collins
Remove the static DefaultHooks method from Branch, replacing it with a derived dict BranchHooks object, which is easier to use and provides a place to put the policy-checking add method discussed on list.
474
    def test_constructor(self):
475
        """Check that creating a BranchHooks instance has the right defaults."""
2297.1.2 by Martin Pool
Cleanup imports
476
        hooks = BranchHooks()
2245.1.2 by Robert Collins
Remove the static DefaultHooks method from Branch, replacing it with a derived dict BranchHooks object, which is easier to use and provides a place to put the policy-checking add method discussed on list.
477
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
478
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
479
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
2659.3.1 by NamNguyen
``Branch.hooks`` now supports ``pre_commit`` hook.
480
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
481
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
482
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
3331.1.4 by James Henstridge
Adjust my tests to pass with Ian's API.
483
        self.assertTrue("post_change_branch_tip" in hooks,
484
                        "post_change_branch_tip not in %s" % hooks)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
485
2245.1.2 by Robert Collins
Remove the static DefaultHooks method from Branch, replacing it with a derived dict BranchHooks object, which is easier to use and provides a place to put the policy-checking add method discussed on list.
486
    def test_installed_hooks_are_BranchHooks(self):
487
        """The installed hooks object should be a BranchHooks."""
488
        # the installed hooks are saved in self._preserved_hooks.
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
489
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
490
            BranchHooks)
2245.1.3 by Robert Collins
Add install_hook to the BranchHooks class as the official means for installing a hook.
491
2297.1.3 by Martin Pool
PullResult can pretend to be an int for api compatibility with old .pull()
492
493
class TestPullResult(TestCase):
494
495
    def test_pull_result_to_int(self):
496
        # to support old code, the pull result can be used as an int
497
        r = PullResult()
498
        r.old_revno = 10
499
        r.new_revno = 20
500
        # this usage of results is not recommended for new code (because it
501
        # doesn't describe very well what happened), but for api stability
502
        # it's still supported
503
        a = "%d revisions pulled" % r
504
        self.assertEqual(a, "10 revisions pulled")
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
505
506
507
508
class _StubLockable(object):
509
    """Helper for TestRunWithWriteLockedTarget."""
510
511
    def __init__(self, calls, unlock_exc=None):
512
        self.calls = calls
513
        self.unlock_exc = unlock_exc
514
515
    def lock_write(self):
516
        self.calls.append('lock_write')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
517
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
518
    def unlock(self):
519
        self.calls.append('unlock')
520
        if self.unlock_exc is not None:
521
            raise self.unlock_exc
522
523
524
class _ErrorFromCallable(Exception):
525
    """Helper for TestRunWithWriteLockedTarget."""
526
527
528
class _ErrorFromUnlock(Exception):
529
    """Helper for TestRunWithWriteLockedTarget."""
530
531
532
class TestRunWithWriteLockedTarget(TestCase):
533
    """Tests for _run_with_write_locked_target."""
534
535
    def setUp(self):
4153.1.2 by Andrew Bennetts
Add missing TestCase.setUp upcalls.
536
        TestCase.setUp(self)
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
537
        self._calls = []
538
539
    def func_that_returns_ok(self):
540
        self._calls.append('func called')
541
        return 'ok'
542
543
    def func_that_raises(self):
544
        self._calls.append('func called')
545
        raise _ErrorFromCallable()
546
547
    def test_success_unlocks(self):
548
        lockable = _StubLockable(self._calls)
549
        result = _run_with_write_locked_target(
550
            lockable, self.func_that_returns_ok)
551
        self.assertEqual('ok', result)
552
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
553
554
    def test_exception_unlocks_and_propagates(self):
555
        lockable = _StubLockable(self._calls)
556
        self.assertRaises(_ErrorFromCallable,
557
            _run_with_write_locked_target, lockable, self.func_that_raises)
558
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
559
560
    def test_callable_succeeds_but_error_during_unlock(self):
561
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
562
        self.assertRaises(_ErrorFromUnlock,
563
            _run_with_write_locked_target, lockable, self.func_that_returns_ok)
564
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
565
566
    def test_error_during_unlock_does_not_mask_original_error(self):
567
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
568
        self.assertRaises(_ErrorFromCallable,
569
            _run_with_write_locked_target, lockable, self.func_that_raises)
570
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
571
572