~bzr-pqm/bzr/bzr.dev

4988.10.5 by John Arbash Meinel
Merge bzr.dev 5021 to resolve NEWS
1
# Copyright (C) 2006-2010 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
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
25
from cStringIO 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,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
32
    tests,
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
33
    trace,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
34
    transport,
2230.3.3 by Aaron Bentley
Add more config testing
35
    urlutils,
36
    )
1534.4.3 by Robert Collins
Implement BranchTestProviderAdapter, so tests now run across all branch formats.
37
3445.2.1 by John Arbash Meinel
Add tests for Branch.missing_revisions and deprecate it.
38
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
39
class TestDefaultFormat(tests.TestCase):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
40
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
41
    def test_default_format(self):
42
        # update this if you change the default branch format
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
43
        self.assertIsInstance(_mod_branch.BranchFormat.get_default_format(),
44
                _mod_branch.BzrBranchFormat7)
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
45
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
46
    def test_default_format_is_same_as_bzrdir_default(self):
47
        # 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
48
        # set, but at the moment that's not true -- mbp 20070814 --
2696.3.8 by Martin Pool
doc
49
        # https://bugs.launchpad.net/bzr/+bug/132376
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
50
        self.assertEqual(
51
            _mod_branch.BranchFormat.get_default_format(),
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
2696.3.3 by Martin Pool
Start setting the default format to dirstate-tags
53
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
54
    def test_get_set_default_format(self):
2696.3.1 by Martin Pool
(broken) start switching format to dirstate-tags
55
        # set the format and then set it back again
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
56
        old_format = _mod_branch.BranchFormat.get_default_format()
57
        _mod_branch.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.
58
        try:
59
            # the default branch format is used by the meta dir format
60
            # which is not the default bzrdir format at this point
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
61
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
62
            result = dir.create_branch()
63
            self.assertEqual(result, 'A branch')
64
        finally:
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
65
            _mod_branch.BranchFormat.set_default_format(old_format)
66
        self.assertEqual(old_format,
67
                         _mod_branch.BranchFormat.get_default_format())
1508.1.25 by Robert Collins
Update per review comments.
68
69
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
70
class TestBranchFormat5(tests.TestCaseWithTransport):
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
71
    """Tests specific to branch format 5"""
72
73
    def test_branch_format_5_uses_lockdir(self):
74
        url = self.get_url()
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
76
        bdir.create_repository()
77
        branch = bdir.create_branch()
1553.5.72 by Martin Pool
Clean up test for Branch5 lockdirs
78
        t = self.get_transport()
79
        self.log("branch instance is %r" % branch)
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
1553.5.72 by Martin Pool
Clean up test for Branch5 lockdirs
81
        self.assertIsDirectory('.', t)
82
        self.assertIsDirectory('.bzr/branch', t)
83
        self.assertIsDirectory('.bzr/branch/lock', t)
1553.5.73 by Martin Pool
Additional test that Branch5 uses lockdir properly
84
        branch.lock_write()
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
85
        self.addCleanup(branch.unlock)
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
87
2230.3.3 by Aaron Bentley
Add more config testing
88
    def test_set_push_location(self):
89
        from bzrlib.config import (locations_config_filename,
90
                                   ensure_config_dir_exists)
91
        ensure_config_dir_exists()
92
        fn = locations_config_filename()
2839.3.1 by Alexander Belchenko
provide non-empty locations.conf for test_branch.TestBranchFormat5.test_set_push_location
93
        # write correct newlines to locations.conf
94
        # by default ConfigObj uses native line-endings for new files
95
        # but uses already existing line-endings if file is not empty
96
        f = open(fn, 'wb')
97
        try:
98
            f.write('# comment\n')
99
        finally:
100
            f.close()
101
2230.3.3 by Aaron Bentley
Add more config testing
102
        branch = self.make_branch('.', format='knit')
103
        branch.set_push_location('foo')
104
        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
105
        self.assertFileEqual("# comment\n"
106
                             "[%s]\n"
2230.3.3 by Aaron Bentley
Add more config testing
107
                             "push_location = foo\n"
3221.7.1 by Matt Nordhoff
Upgrade ConfigObj to version 4.5.1.
108
                             "push_location:policy = norecurse\n" % local_path,
2230.3.3 by Aaron Bentley
Add more config testing
109
                             fn)
110
2230.3.12 by Aaron Bentley
Clean up trailing whitespace
111
    # TODO RBC 20051029 test getting a push location from a branch in a
2230.3.3 by Aaron Bentley
Add more config testing
112
    # recursive section - that is, it appends the branch name.
113
1553.5.71 by Martin Pool
Change branch format 5 to use LockDirs, not transport locks
114
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
115
class SampleBranchFormat(_mod_branch.BranchFormat):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
116
    """A sample format
117
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
118
    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.
119
    open and open_downlevel routines.
120
    """
121
122
    def get_format_string(self):
123
        """See BzrBranchFormat.get_format_string()."""
124
        return "Sample branch format."
125
5051.3.10 by Jelmer Vernooij
Pass colocated branch name around in more places.
126
    def initialize(self, a_bzrdir, name=None):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
127
        """Format 4 branches cannot be created."""
5051.3.10 by Jelmer Vernooij
Pass colocated branch name around in more places.
128
        t = a_bzrdir.get_branch_transport(self, name=name)
1955.3.9 by John Arbash Meinel
Find more occurrances of put() and replace with put_file or put_bytes
129
        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.
130
        return 'A branch'
131
132
    def is_supported(self):
133
        return False
134
5051.3.16 by Jelmer Vernooij
Fix tests - missing argument.
135
    def open(self, transport, name=None, _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.
136
        return "opened branch."
137
138
5305.1.2 by Robert Collins
More clarity about how to use the lazy registration feature.
139
# Demonstrating how lazy loading is often implemented:
140
# A constant string is created.
141
SampleSupportedBranchFormatString = "Sample supported branch format."
142
143
# And the format class can then reference the constant to avoid skew.
5305.1.1 by Robert Collins
``Branch`` formats can now be loaded lazily by registering a
144
class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
145
    """A sample supported format."""
146
147
    def get_format_string(self):
148
        """See BzrBranchFormat.get_format_string()."""
5305.1.2 by Robert Collins
More clarity about how to use the lazy registration feature.
149
        return SampleSupportedBranchFormatString
5305.1.1 by Robert Collins
``Branch`` formats can now be loaded lazily by registering a
150
151
    def initialize(self, a_bzrdir, name=None):
152
        t = a_bzrdir.get_branch_transport(self, name=name)
153
        t.put_bytes('format', self.get_format_string())
154
        return 'A branch'
155
156
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
157
        return "opened supported branch."
158
159
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
160
class TestBzrBranchFormat(tests.TestCaseWithTransport):
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
161
    """Tests for the BzrBranchFormat facility."""
162
163
    def test_find_format(self):
164
        # is the right format object found for a branch?
165
        # create a branch with a few known format objects.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
166
        # 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.
167
        self.build_tree(["foo/", "bar/"])
168
        def check_format(format, url):
169
            dir = format._matchingbzrdir.initialize(url)
1534.4.47 by Robert Collins
Split out repository into .bzr/repository
170
            dir.create_repository()
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
171
            format.initialize(dir)
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
172
            found_format = _mod_branch.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.
173
            self.failUnless(isinstance(found_format, format.__class__))
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
174
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
175
5305.1.1 by Robert Collins
``Branch`` formats can now be loaded lazily by registering a
176
    def test_find_format_factory(self):
177
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
178
        SampleSupportedBranchFormat().initialize(dir)
179
        factory = _mod_branch.MetaDirBranchFormatFactory(
5305.1.2 by Robert Collins
More clarity about how to use the lazy registration feature.
180
            SampleSupportedBranchFormatString,
5305.1.1 by Robert Collins
``Branch`` formats can now be loaded lazily by registering a
181
            "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
182
        _mod_branch.BranchFormat.register_format(factory)
183
        self.addCleanup(_mod_branch.BranchFormat.unregister_format, factory)
184
        b = _mod_branch.Branch.open(self.get_url())
185
        self.assertEqual(b, "opened supported branch.")
186
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
187
    def test_find_format_not_branch(self):
188
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
189
        self.assertRaises(errors.NotBranchError,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
190
                          _mod_branch.BranchFormat.find_format,
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
191
                          dir)
192
193
    def test_find_format_unknown_format(self):
194
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
195
        SampleBranchFormat().initialize(dir)
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
196
        self.assertRaises(errors.UnknownFormatError,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
197
                          _mod_branch.BranchFormat.find_format,
1534.4.44 by Robert Collins
Make a new BzrDir format that uses a versioned branch format in a branch/ subdirectory.
198
                          dir)
199
200
    def test_register_unregister_format(self):
201
        format = SampleBranchFormat()
202
        # make a control dir
203
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
204
        # make a branch
205
        format.initialize(dir)
206
        # register a format for it.
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
207
        _mod_branch.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.
208
        # which branch.Open will refuse (not supported)
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
209
        self.assertRaises(errors.UnsupportedFormatError,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
210
                          _mod_branch.Branch.open, self.get_url())
2230.3.22 by Aaron Bentley
Make test suite use format registry default, not BzrDir default
211
        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.
212
        # but open_downlevel will work
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
213
        self.assertEqual(
214
            format.open(dir),
215
            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.
216
        # unregister the format
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
217
        _mod_branch.BranchFormat.unregister_format(format)
2230.3.22 by Aaron Bentley
Make test suite use format registry default, not BzrDir default
218
        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.
219
220
5305.1.1 by Robert Collins
``Branch`` formats can now be loaded lazily by registering a
221
#Used by TestMetaDirBranchFormatFactory 
222
FakeLazyFormat = None
223
224
225
class TestMetaDirBranchFormatFactory(tests.TestCase):
226
227
    def test_get_format_string_does_not_load(self):
228
        """Formats have a static format string."""
229
        factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
230
        self.assertEqual("yo", factory.get_format_string())
231
232
    def test_call_loads(self):
233
        # __call__ is used by the network_format_registry interface to get a
234
        # Format.
235
        global FakeLazyFormat
236
        del FakeLazyFormat
237
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
238
            "bzrlib.tests.test_branch", "FakeLazyFormat")
239
        self.assertRaises(AttributeError, factory)
240
241
    def test_call_returns_call_of_referenced_object(self):
242
        global FakeLazyFormat
243
        FakeLazyFormat = lambda:'called'
244
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
245
            "bzrlib.tests.test_branch", "FakeLazyFormat")
246
        self.assertEqual('called', factory())
247
248
3221.11.2 by Robert Collins
Create basic stackable branch facility.
249
class TestBranch67(object):
250
    """Common tests for both branch 6 and 7 which are mostly the same."""
251
252
    def get_format_name(self):
253
        raise NotImplementedError(self.get_format_name)
254
255
    def get_format_name_subtree(self):
256
        raise NotImplementedError(self.get_format_name)
257
258
    def get_class(self):
259
        raise NotImplementedError(self.get_class)
2230.3.1 by Aaron Bentley
Get branch6 creation working
260
261
    def test_creation(self):
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
262
        format = bzrdir.BzrDirMetaFormat1()
2230.3.55 by Aaron Bentley
Updates from review
263
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
2230.3.1 by Aaron Bentley
Get branch6 creation working
264
        branch = self.make_branch('a', format=format)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
265
        self.assertIsInstance(branch, self.get_class())
266
        branch = self.make_branch('b', format=self.get_format_name())
267
        self.assertIsInstance(branch, self.get_class())
2230.3.1 by Aaron Bentley
Get branch6 creation working
268
        branch = _mod_branch.Branch.open('a')
3221.11.2 by Robert Collins
Create basic stackable branch facility.
269
        self.assertIsInstance(branch, self.get_class())
2230.3.1 by Aaron Bentley
Get branch6 creation working
270
271
    def test_layout(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
272
        branch = self.make_branch('a', format=self.get_format_name())
2230.3.1 by Aaron Bentley
Get branch6 creation working
273
        self.failUnlessExists('a/.bzr/branch/last-revision')
274
        self.failIfExists('a/.bzr/branch/revision-history')
4273.1.12 by Aaron Bentley
Don't create reference files for older formats.
275
        self.failIfExists('a/.bzr/branch/references')
2230.3.1 by Aaron Bentley
Get branch6 creation working
276
2230.3.3 by Aaron Bentley
Add more config testing
277
    def test_config(self):
278
        """Ensure that all configuration data is stored in the branch"""
3221.11.2 by Robert Collins
Create basic stackable branch facility.
279
        branch = self.make_branch('a', format=self.get_format_name())
2230.3.3 by Aaron Bentley
Add more config testing
280
        branch.set_parent('http://bazaar-vcs.org')
281
        self.failIfExists('a/.bzr/branch/parent')
282
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
283
        branch.set_push_location('sftp://bazaar-vcs.org')
284
        config = branch.get_config()._get_branch_data_config()
2230.3.12 by Aaron Bentley
Clean up trailing whitespace
285
        self.assertEqual('sftp://bazaar-vcs.org',
2230.3.3 by Aaron Bentley
Add more config testing
286
                         config.get_user_option('push_location'))
287
        branch.set_bound_location('ftp://bazaar-vcs.org')
288
        self.failIfExists('a/.bzr/branch/bound')
289
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
290
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
291
    def test_set_revision_history(self):
3567.4.16 by John Arbash Meinel
Use the new BranchBuilder api in a Branch test
292
        builder = self.make_branch_builder('.', format=self.get_format_name())
293
        builder.build_snapshot('foo', None,
294
            [('add', ('', None, 'directory', None))],
295
            message='foo')
296
        builder.build_snapshot('bar', None, [], message='bar')
297
        branch = builder.get_branch()
298
        branch.lock_write()
299
        self.addCleanup(branch.unlock)
300
        branch.set_revision_history(['foo', 'bar'])
301
        branch.set_revision_history(['foo'])
302
        self.assertRaises(errors.NotLefthandHistory,
303
                          branch.set_revision_history, ['bar'])
2230.3.44 by Aaron Bentley
Change asserts to specific errors for left-hand history violations
304
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
305
    def do_checkout_test(self, lightweight=False):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
306
        tree = self.make_branch_and_tree('source',
307
            format=self.get_format_name_subtree())
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
308
        subtree = self.make_branch_and_tree('source/subtree',
3221.11.2 by Robert Collins
Create basic stackable branch facility.
309
            format=self.get_format_name_subtree())
2100.3.25 by Aaron Bentley
add subsubtree to test
310
        subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
3221.11.2 by Robert Collins
Create basic stackable branch facility.
311
            format=self.get_format_name_subtree())
2100.3.25 by Aaron Bentley
add subsubtree to test
312
        self.build_tree(['source/subtree/file',
313
                         'source/subtree/subsubtree/file'])
314
        subsubtree.add('file')
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
315
        subtree.add('file')
2100.3.25 by Aaron Bentley
add subsubtree to test
316
        subtree.add_reference(subsubtree)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
317
        tree.add_reference(subtree)
318
        tree.commit('a revision')
2100.3.23 by Aaron Bentley
Nested checkouts kinda work
319
        subtree.commit('a subtree file')
2100.3.25 by Aaron Bentley
add subsubtree to test
320
        subsubtree.commit('a subsubtree file')
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
321
        tree.branch.create_checkout('target', lightweight=lightweight)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
322
        self.failUnlessExists('target')
323
        self.failUnlessExists('target/subtree')
324
        self.failUnlessExists('target/subtree/file')
2100.3.25 by Aaron Bentley
add subsubtree to test
325
        self.failUnlessExists('target/subtree/subsubtree/file')
2100.3.31 by Aaron Bentley
Merged bzr.dev (17 tests failing)
326
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
2100.3.26 by Aaron Bentley
checkout type is maintained for subtrees
327
        if lightweight:
328
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
329
        else:
330
            self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
331
332
    def test_checkout_with_references(self):
333
        self.do_checkout_test()
334
335
    def test_light_checkout_with_references(self):
336
        self.do_checkout_test(lightweight=True)
2230.3.51 by Aaron Bentley
Store revno for Branch6, set_last_revision -> set_last_revision_info
337
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
338
    def test_set_push(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
339
        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)
340
        branch.get_config().set_user_option('push_location', 'old',
341
            store=config.STORE_LOCATION)
342
        warnings = []
343
        def warning(*args):
344
            warnings.append(args[0] % args[1:])
345
        _warning = trace.warning
346
        trace.warning = warning
347
        try:
348
            branch.set_push_location('new')
349
        finally:
350
            trace.warning = _warning
351
        self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
352
                         'locations.conf')
353
3445.2.1 by John Arbash Meinel
Add tests for Branch.missing_revisions and deprecate it.
354
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
355
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
356
357
    def get_class(self):
358
        return _mod_branch.BzrBranch6
359
360
    def get_format_name(self):
361
        return "dirstate-tags"
362
363
    def get_format_name_subtree(self):
364
        return "dirstate-with-subtree"
365
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
366
    def test_set_stacked_on_url_errors(self):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
367
        branch = self.make_branch('a', format=self.get_format_name())
368
        self.assertRaises(errors.UnstackableBranchFormat,
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
369
            branch.set_stacked_on_url, None)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
370
371
    def test_default_stacked_location(self):
372
        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
373
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
374
375
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
376
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
3221.11.2 by Robert Collins
Create basic stackable branch facility.
377
378
    def get_class(self):
379
        return _mod_branch.BzrBranch7
380
381
    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)
382
        return "1.9"
3221.11.2 by Robert Collins
Create basic stackable branch facility.
383
384
    def get_format_name_subtree(self):
385
        return "development-subtree"
386
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
387
    def test_set_stacked_on_url_unstackable_repo(self):
3221.11.6 by Robert Collins
Stackable branch fixes.
388
        repo = self.make_repository('a', format='dirstate-tags')
389
        control = repo.bzrdir
390
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
391
        target = self.make_branch('b')
392
        self.assertRaises(errors.UnstackableRepositoryFormat,
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
393
            branch.set_stacked_on_url, target.base)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
394
3242.3.21 by Jonathan Lange
Preserve stacking in clone
395
    def test_clone_stacked_on_unstackable_repo(self):
396
        repo = self.make_repository('a', format='dirstate-tags')
397
        control = repo.bzrdir
398
        branch = _mod_branch.BzrBranchFormat7().initialize(control)
399
        # Calling clone should not raise UnstackableRepositoryFormat.
400
        cloned_bzrdir = control.clone('cloned')
401
3221.11.2 by Robert Collins
Create basic stackable branch facility.
402
    def _test_default_stacked_location(self):
403
        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
404
        self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
3221.11.2 by Robert Collins
Create basic stackable branch facility.
405
3221.11.8 by Robert Collins
Minimally test stacking and unstacking a repository.
406
    def test_stack_and_unstack(self):
407
        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.
408
        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
409
        branch.set_stacked_on_url(target.branch.base)
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
410
        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.
411
        revid = target.commit('foo')
412
        self.assertTrue(branch.repository.has_revision(revid))
3537.3.3 by Martin Pool
Rename Branch.set_stacked_on to set_stacked_on_url
413
        branch.set_stacked_on_url(None)
3537.3.1 by Martin Pool
Rename branch.get_stacked_on to get_stacked_on_url
414
        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.
415
        self.assertFalse(branch.repository.has_revision(revid))
3221.11.8 by Robert Collins
Minimally test stacking and unstacking a repository.
416
3221.11.11 by Robert Collins
Ensure opening a stacked branch gives a ready to use repository.
417
    def test_open_opens_stacked_reference(self):
418
        branch = self.make_branch('a', format=self.get_format_name())
419
        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
420
        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.
421
        branch = branch.bzrdir.open_branch()
422
        revid = target.commit('foo')
423
        self.assertTrue(branch.repository.has_revision(revid))
424
3221.11.2 by Robert Collins
Create basic stackable branch facility.
425
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
426
class BzrBranch8(tests.TestCaseWithTransport):
4273.1.15 by Aaron Bentley
Add reference_info caching.
427
428
    def make_branch(self, location, format=None):
429
        if format is None:
430
            format = bzrdir.format_registry.make_bzrdir('1.9')
431
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
432
        return tests.TestCaseWithTransport.make_branch(
433
            self, location, format=format)
4273.1.15 by Aaron Bentley
Add reference_info caching.
434
435
    def create_branch_with_reference(self):
436
        branch = self.make_branch('branch')
437
        branch._set_all_reference_info({'file-id': ('path', 'location')})
438
        return branch
439
440
    @staticmethod
441
    def instrument_branch(branch, gets):
442
        old_get = branch._transport.get
443
        def get(*args, **kwargs):
444
            gets.append((args, kwargs))
445
            return old_get(*args, **kwargs)
446
        branch._transport.get = get
447
448
    def test_reference_info_caching_read_locked(self):
449
        gets = []
450
        branch = self.create_branch_with_reference()
451
        branch.lock_read()
452
        self.addCleanup(branch.unlock)
453
        self.instrument_branch(branch, gets)
454
        branch.get_reference_info('file-id')
455
        branch.get_reference_info('file-id')
456
        self.assertEqual(1, len(gets))
457
458
    def test_reference_info_caching_read_unlocked(self):
459
        gets = []
460
        branch = self.create_branch_with_reference()
461
        self.instrument_branch(branch, gets)
462
        branch.get_reference_info('file-id')
463
        branch.get_reference_info('file-id')
464
        self.assertEqual(2, len(gets))
465
466
    def test_reference_info_caching_write_locked(self):
467
        gets = []
468
        branch = self.make_branch('branch')
469
        branch.lock_write()
470
        self.instrument_branch(branch, gets)
471
        self.addCleanup(branch.unlock)
472
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
473
        path, location = branch.get_reference_info('file-id')
474
        self.assertEqual(0, len(gets))
475
        self.assertEqual('path2', path)
476
        self.assertEqual('location2', location)
477
478
    def test_reference_info_caches_cleared(self):
479
        branch = self.make_branch('branch')
480
        branch.lock_write()
481
        branch.set_reference_info('file-id', 'path2', 'location2')
482
        branch.unlock()
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
483
        doppelganger = _mod_branch.Branch.open('branch')
4273.1.15 by Aaron Bentley
Add reference_info caching.
484
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
485
        self.assertEqual(('path3', 'location3'),
486
                         branch.get_reference_info('file-id'))
487
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
488
class TestBranchReference(tests.TestCaseWithTransport):
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.
489
    """Tests for the branch reference facility."""
490
491
    def test_create_open_reference(self):
492
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
493
        t = transport.get_transport(self.get_url('.'))
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.
494
        t.mkdir('repo')
495
        dir = bzrdirformat.initialize(self.get_url('repo'))
496
        dir.create_repository()
497
        target_branch = dir.create_branch()
498
        t.mkdir('branch')
499
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
500
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
5051.3.10 by Jelmer Vernooij
Pass colocated branch name around in more places.
501
            branch_dir, target_branch=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.
502
        self.assertEqual(made_branch.base, target_branch.base)
503
        opened_branch = branch_dir.open_branch()
504
        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.
505
506
    def test_get_reference(self):
507
        """For a BranchReference, get_reference should reutrn the location."""
508
        branch = self.make_branch('target')
509
        checkout = branch.create_checkout('checkout', lightweight=True)
510
        reference_url = branch.bzrdir.root_transport.abspath('') + '/'
511
        # if the api for create_checkout changes to return different checkout types
512
        # then this file read will fail.
513
        self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
514
        self.assertEqual(reference_url,
2018.5.97 by Andrew Bennetts
Fix more tests.
515
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
2018.5.45 by Andrew Bennetts
Merge from bzr.dev
516
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
517
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
518
class TestHooks(tests.TestCaseWithTransport):
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
519
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.
520
    def test_constructor(self):
521
        """Check that creating a BranchHooks instance has the right defaults."""
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
522
        hooks = _mod_branch.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.
523
        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
524
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
525
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
2659.3.1 by NamNguyen
``Branch.hooks`` now supports ``pre_commit`` hook.
526
        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
527
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
528
        self.assertTrue("post_uncommit" in hooks,
529
                        "post_uncommit not in %s" % hooks)
3331.1.4 by James Henstridge
Adjust my tests to pass with Ian's API.
530
        self.assertTrue("post_change_branch_tip" in hooks,
531
                        "post_change_branch_tip not in %s" % hooks)
5107.3.2 by Marco Pantaleoni
Renamed 'post_branch' hook to 'post_branch_init', for more consistency,
532
        self.assertTrue("post_branch_init" in hooks,
533
                        "post_branch_init not in %s" % hooks)
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
534
        self.assertTrue("post_switch" in hooks,
535
                        "post_switch not in %s" % hooks)
2245.1.1 by Robert Collins
New Branch hooks facility, with one initial hook 'set_rh' which triggers
536
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.
537
    def test_installed_hooks_are_BranchHooks(self):
538
        """The installed hooks object should be a BranchHooks."""
539
        # the installed hooks are saved in self._preserved_hooks.
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
540
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
541
                              _mod_branch.BranchHooks)
2245.1.3 by Robert Collins
Add install_hook to the BranchHooks class as the official means for installing a hook.
542
5107.3.2 by Marco Pantaleoni
Renamed 'post_branch' hook to 'post_branch_init', for more consistency,
543
    def test_post_branch_init_hook(self):
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
544
        calls = []
5107.3.4 by Marco Pantaleoni
Applied suggestions from merge reviewer (John A Meinel):
545
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
546
            calls.append, None)
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
547
        self.assertLength(0, calls)
548
        branch = self.make_branch('a')
549
        self.assertLength(1, calls)
550
        params = calls[0]
5107.3.2 by Marco Pantaleoni
Renamed 'post_branch' hook to 'post_branch_init', for more consistency,
551
        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
552
        self.assertTrue(hasattr(params, 'bzrdir'))
553
        self.assertTrue(hasattr(params, 'branch'))
554
555
    def test_post_switch_hook(self):
556
        from bzrlib import switch
557
        calls = []
5107.3.4 by Marco Pantaleoni
Applied suggestions from merge reviewer (John A Meinel):
558
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
559
            calls.append, None)
5107.3.1 by Marco Pantaleoni
Added the new hooks 'post_branch', 'post_switch' and 'post_repo_init',
560
        tree = self.make_branch_and_tree('branch-1')
561
        self.build_tree(['branch-1/file-1'])
562
        tree.add('file-1')
563
        tree.commit('rev1')
564
        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
565
        self.build_tree(['branch-1/file-2'])
566
        tree.add('file-2')
567
        tree.remove('file-1')
568
        tree.commit('rev2')
569
        checkout = tree.branch.create_checkout('checkout')
570
        self.assertLength(0, calls)
571
        switch.switch(checkout.bzrdir, to_branch)
572
        self.assertLength(1, calls)
573
        params = calls[0]
574
        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
575
        self.assertTrue(hasattr(params, 'to_branch'))
576
        self.assertTrue(hasattr(params, 'revision_id'))
2297.1.3 by Martin Pool
PullResult can pretend to be an int for api compatibility with old .pull()
577
5176.1.1 by Vincent Ladeuil
Warn if a config variable can't be interpreted as a boolean
578
579
class TestBranchOptions(tests.TestCaseWithTransport):
4989.2.1 by Brian de Alwis
The 'append_revisions_only' option is now case-insensitive,
580
4989.2.5 by Vincent Ladeuil
Clarify tests.
581
    def setUp(self):
582
        super(TestBranchOptions, self).setUp()
583
        self.branch = self.make_branch('.')
584
        self.config = self.branch.get_config()
585
4989.2.15 by Vincent Ladeuil
Fixed as per Andrew's review.
586
    def check_append_revisions_only(self, expected_value, value=None):
587
        """Set append_revisions_only in config and check its interpretation."""
4989.2.5 by Vincent Ladeuil
Clarify tests.
588
        if value is not None:
589
            self.config.set_user_option('append_revisions_only', value)
590
        self.assertEqual(expected_value,
591
                         self.branch._get_append_revisions_only())
592
593
    def test_valid_append_revisions_only(self):
594
        self.assertEquals(None,
595
                          self.config.get_user_option('append_revisions_only'))
4989.2.15 by Vincent Ladeuil
Fixed as per Andrew's review.
596
        self.check_append_revisions_only(None)
597
        self.check_append_revisions_only(False, 'False')
598
        self.check_append_revisions_only(True, 'True')
4989.2.13 by Vincent Ladeuil
append_revisions_only accept all valid booleans, update doc to
599
        # The following values will cause compatibility problems on projects
600
        # using older bzr versions (<2.2) but are accepted
4989.2.15 by Vincent Ladeuil
Fixed as per Andrew's review.
601
        self.check_append_revisions_only(False, 'false')
602
        self.check_append_revisions_only(True, 'true')
4989.2.5 by Vincent Ladeuil
Clarify tests.
603
604
    def test_invalid_append_revisions_only(self):
4989.2.9 by Brian de Alwis
Revert append_revisions_only to only allow 'True' and 'False' to
605
        """Ensure warning is noted on invalid settings"""
4989.2.15 by Vincent Ladeuil
Fixed as per Andrew's review.
606
        self.warnings = []
607
        def warning(*args):
608
            self.warnings.append(args[0] % args[1:])
609
        self.overrideAttr(trace, 'warning', warning)
610
        self.check_append_revisions_only(None, 'not-a-bool')
611
        self.assertLength(1, self.warnings)
612
        self.assertEqual(
613
            'Value "not-a-bool" is not a boolean for "append_revisions_only"',
614
            self.warnings[0])
4989.2.5 by Vincent Ladeuil
Clarify tests.
615
4989.2.1 by Brian de Alwis
The 'append_revisions_only' option is now case-insensitive,
616
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
617
class TestPullResult(tests.TestCase):
2297.1.3 by Martin Pool
PullResult can pretend to be an int for api compatibility with old .pull()
618
619
    def test_pull_result_to_int(self):
620
        # to support old code, the pull result can be used as an int
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
621
        r = _mod_branch.PullResult()
2297.1.3 by Martin Pool
PullResult can pretend to be an int for api compatibility with old .pull()
622
        r.old_revno = 10
623
        r.new_revno = 20
624
        # this usage of results is not recommended for new code (because it
625
        # doesn't describe very well what happened), but for api stability
626
        # it's still supported
627
        a = "%d revisions pulled" % r
628
        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()
629
4672.4.1 by Jelmer Vernooij
Add two more tests for PullResult.
630
    def test_report_changed(self):
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
631
        r = _mod_branch.PullResult()
4672.4.1 by Jelmer Vernooij
Add two more tests for PullResult.
632
        r.old_revid = "old-revid"
633
        r.old_revno = 10
634
        r.new_revid = "new-revid"
635
        r.new_revno = 20
636
        f = StringIO()
637
        r.report(f)
638
        self.assertEqual("Now on revision 20.\n", f.getvalue())
639
640
    def test_report_unchanged(self):
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
641
        r = _mod_branch.PullResult()
4672.4.1 by Jelmer Vernooij
Add two more tests for PullResult.
642
        r.old_revid = "same-revid"
643
        r.new_revid = "same-revid"
644
        f = StringIO()
645
        r.report(f)
646
        self.assertEqual("No revisions to pull.\n", f.getvalue())
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
647
648
649
class _StubLockable(object):
650
    """Helper for TestRunWithWriteLockedTarget."""
651
652
    def __init__(self, calls, unlock_exc=None):
653
        self.calls = calls
654
        self.unlock_exc = unlock_exc
655
656
    def lock_write(self):
657
        self.calls.append('lock_write')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
658
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
659
    def unlock(self):
660
        self.calls.append('unlock')
661
        if self.unlock_exc is not None:
662
            raise self.unlock_exc
663
664
665
class _ErrorFromCallable(Exception):
666
    """Helper for TestRunWithWriteLockedTarget."""
667
668
669
class _ErrorFromUnlock(Exception):
670
    """Helper for TestRunWithWriteLockedTarget."""
671
672
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
673
class TestRunWithWriteLockedTarget(tests.TestCase):
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
674
    """Tests for _run_with_write_locked_target."""
675
676
    def setUp(self):
5010.2.1 by Vincent Ladeuil
Fiux test/test_branch.py imports.
677
        tests.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()
678
        self._calls = []
679
680
    def func_that_returns_ok(self):
681
        self._calls.append('func called')
682
        return 'ok'
683
684
    def func_that_raises(self):
685
        self._calls.append('func called')
686
        raise _ErrorFromCallable()
687
688
    def test_success_unlocks(self):
689
        lockable = _StubLockable(self._calls)
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
690
        result = _mod_branch._run_with_write_locked_target(
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
691
            lockable, self.func_that_returns_ok)
692
        self.assertEqual('ok', result)
693
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
694
695
    def test_exception_unlocks_and_propagates(self):
696
        lockable = _StubLockable(self._calls)
697
        self.assertRaises(_ErrorFromCallable,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
698
                          _mod_branch._run_with_write_locked_target,
699
                          lockable, self.func_that_raises)
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
700
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
701
702
    def test_callable_succeeds_but_error_during_unlock(self):
703
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
704
        self.assertRaises(_ErrorFromUnlock,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
705
                          _mod_branch._run_with_write_locked_target,
706
                          lockable, self.func_that_returns_ok)
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
707
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
708
709
    def test_error_during_unlock_does_not_mask_original_error(self):
710
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
711
        self.assertRaises(_ErrorFromCallable,
5010.2.26 by Vincent Ladeuil
Fix imports in test_branch.py.
712
                          _mod_branch._run_with_write_locked_target,
713
                          lockable, self.func_that_raises)
3758.1.1 by Andrew Bennetts
Fix #230902 by being more careful not to squash a pre-existing exception when calling foo.unlock()
714
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
715
716