~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

(jameinel) Allow 'bzr serve' to interpret SIGHUP as a graceful shutdown.
 (bug #795025) (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests for the Branch facility that are not interface  tests.
18
18
 
19
 
For interface tests see tests/branch_implementations/*.py.
 
19
For interface tests see `tests/per_branch/*.py`.
20
20
 
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
23
23
"""
24
24
 
25
 
from StringIO import StringIO
 
25
from cStringIO import StringIO
26
26
 
27
27
from bzrlib import (
28
28
    branch as _mod_branch,
29
29
    bzrdir,
30
30
    config,
31
31
    errors,
 
32
    symbol_versioning,
 
33
    tests,
32
34
    trace,
33
35
    urlutils,
34
36
    )
35
 
from bzrlib.branch import (
36
 
    Branch,
37
 
    BranchHooks,
38
 
    BranchFormat,
39
 
    BranchReferenceFormat,
40
 
    BzrBranch5,
41
 
    BzrBranchFormat5,
42
 
    BzrBranchFormat6,
43
 
    PullResult,
44
 
    _run_with_write_locked_target,
45
 
    )
46
 
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1, 
47
 
                           BzrDir, BzrDirFormat)
48
 
from bzrlib.errors import (NotBranchError,
49
 
                           UnknownFormatError,
50
 
                           UnknownHook,
51
 
                           UnsupportedFormatError,
52
 
                           )
53
 
 
54
 
from bzrlib.tests import TestCase, TestCaseWithTransport
55
 
from bzrlib.transport import get_transport
56
 
 
57
 
 
58
 
class TestDefaultFormat(TestCase):
 
37
 
 
38
 
 
39
class TestDefaultFormat(tests.TestCase):
59
40
 
60
41
    def test_default_format(self):
61
42
        # update this if you change the default branch format
62
 
        self.assertIsInstance(BranchFormat.get_default_format(),
63
 
                BzrBranchFormat6)
 
43
        self.assertIsInstance(_mod_branch.format_registry.get_default(),
 
44
                _mod_branch.BzrBranchFormat7)
64
45
 
65
46
    def test_default_format_is_same_as_bzrdir_default(self):
66
47
        # XXX: it might be nice if there was only one place the default was
67
 
        # set, but at the moment that's not true -- mbp 20070814 -- 
 
48
        # set, but at the moment that's not true -- mbp 20070814 --
68
49
        # https://bugs.launchpad.net/bzr/+bug/132376
69
 
        self.assertEqual(BranchFormat.get_default_format(),
70
 
                BzrDirFormat.get_default_format().get_branch_format())
 
50
        self.assertEqual(
 
51
            _mod_branch.format_registry.get_default(),
 
52
            bzrdir.BzrDirFormat.get_default_format().get_branch_format())
71
53
 
72
54
    def test_get_set_default_format(self):
73
55
        # set the format and then set it back again
74
 
        old_format = BranchFormat.get_default_format()
75
 
        BranchFormat.set_default_format(SampleBranchFormat())
 
56
        old_format = _mod_branch.format_registry.get_default()
 
57
        _mod_branch.format_registry.set_default(SampleBranchFormat())
76
58
        try:
77
59
            # the default branch format is used by the meta dir format
78
60
            # which is not the default bzrdir format at this point
79
 
            dir = BzrDirMetaFormat1().initialize('memory:///')
 
61
            dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
80
62
            result = dir.create_branch()
81
63
            self.assertEqual(result, 'A branch')
82
64
        finally:
83
 
            BranchFormat.set_default_format(old_format)
84
 
        self.assertEqual(old_format, BranchFormat.get_default_format())
85
 
 
86
 
 
87
 
class TestBranchFormat5(TestCaseWithTransport):
 
65
            _mod_branch.format_registry.set_default(old_format)
 
66
        self.assertEqual(old_format,
 
67
                         _mod_branch.format_registry.get_default())
 
68
 
 
69
 
 
70
class TestBranchFormat5(tests.TestCaseWithTransport):
88
71
    """Tests specific to branch format 5"""
89
72
 
90
73
    def test_branch_format_5_uses_lockdir(self):
91
74
        url = self.get_url()
92
 
        bzrdir = BzrDirMetaFormat1().initialize(url)
93
 
        bzrdir.create_repository()
94
 
        branch = bzrdir.create_branch()
 
75
        bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
 
76
        bdir.create_repository()
 
77
        branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
95
78
        t = self.get_transport()
96
79
        self.log("branch instance is %r" % branch)
97
 
        self.assert_(isinstance(branch, BzrBranch5))
 
80
        self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
98
81
        self.assertIsDirectory('.', t)
99
82
        self.assertIsDirectory('.bzr/branch', t)
100
83
        self.assertIsDirectory('.bzr/branch/lock', t)
101
84
        branch.lock_write()
102
 
        try:
103
 
            self.assertIsDirectory('.bzr/branch/lock/held', t)
104
 
        finally:
105
 
            branch.unlock()
 
85
        self.addCleanup(branch.unlock)
 
86
        self.assertIsDirectory('.bzr/branch/lock/held', t)
106
87
 
107
88
    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()
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()
 
89
        conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
120
90
 
121
91
        branch = self.make_branch('.', format='knit')
122
92
        branch.set_push_location('foo')
125
95
                             "[%s]\n"
126
96
                             "push_location = foo\n"
127
97
                             "push_location:policy = norecurse\n" % local_path,
128
 
                             fn)
 
98
                             config.locations_config_filename())
129
99
 
130
100
    # TODO RBC 20051029 test getting a push location from a branch in a
131
101
    # recursive section - that is, it appends the branch name.
132
102
 
133
103
 
134
 
class SampleBranchFormat(BranchFormat):
 
104
class SampleBranchFormat(_mod_branch.BranchFormat):
135
105
    """A sample format
136
106
 
137
 
    this format is initializable, unsupported to aid in testing the 
 
107
    this format is initializable, unsupported to aid in testing the
138
108
    open and open_downlevel routines.
139
109
    """
140
110
 
142
112
        """See BzrBranchFormat.get_format_string()."""
143
113
        return "Sample branch format."
144
114
 
145
 
    def initialize(self, a_bzrdir):
 
115
    def initialize(self, a_bzrdir, name=None, repository=None,
 
116
                   append_revisions_only=None):
146
117
        """Format 4 branches cannot be created."""
147
 
        t = a_bzrdir.get_branch_transport(self)
 
118
        t = a_bzrdir.get_branch_transport(self, name=name)
148
119
        t.put_bytes('format', self.get_format_string())
149
120
        return 'A branch'
150
121
 
151
122
    def is_supported(self):
152
123
        return False
153
124
 
154
 
    def open(self, transport, _found=False):
 
125
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
155
126
        return "opened branch."
156
127
 
157
128
 
158
 
class TestBzrBranchFormat(TestCaseWithTransport):
 
129
# Demonstrating how lazy loading is often implemented:
 
130
# A constant string is created.
 
131
SampleSupportedBranchFormatString = "Sample supported branch format."
 
132
 
 
133
# And the format class can then reference the constant to avoid skew.
 
134
class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
 
135
    """A sample supported format."""
 
136
 
 
137
    def get_format_string(self):
 
138
        """See BzrBranchFormat.get_format_string()."""
 
139
        return SampleSupportedBranchFormatString
 
140
 
 
141
    def initialize(self, a_bzrdir, name=None, append_revisions_only=None):
 
142
        t = a_bzrdir.get_branch_transport(self, name=name)
 
143
        t.put_bytes('format', self.get_format_string())
 
144
        return 'A branch'
 
145
 
 
146
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
 
147
        return "opened supported branch."
 
148
 
 
149
 
 
150
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
 
151
    """A sample format that is not usable in a metadir."""
 
152
 
 
153
    def get_format_string(self):
 
154
        # This format is not usable in a metadir.
 
155
        return None
 
156
 
 
157
    def network_name(self):
 
158
        # Network name always has to be provided.
 
159
        return "extra"
 
160
 
 
161
    def initialize(self, a_bzrdir, name=None):
 
162
        raise NotImplementedError(self.initialize)
 
163
 
 
164
    def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
 
165
        raise NotImplementedError(self.open)
 
166
 
 
167
 
 
168
class TestBzrBranchFormat(tests.TestCaseWithTransport):
159
169
    """Tests for the BzrBranchFormat facility."""
160
170
 
161
171
    def test_find_format(self):
162
172
        # is the right format object found for a branch?
163
173
        # create a branch with a few known format objects.
164
 
        # this is not quite the same as 
 
174
        # this is not quite the same as
165
175
        self.build_tree(["foo/", "bar/"])
166
176
        def check_format(format, url):
167
177
            dir = format._matchingbzrdir.initialize(url)
168
178
            dir.create_repository()
169
179
            format.initialize(dir)
170
 
            found_format = BranchFormat.find_format(dir)
171
 
            self.failUnless(isinstance(found_format, format.__class__))
172
 
        check_format(BzrBranchFormat5(), "bar")
173
 
        
 
180
            found_format = _mod_branch.BranchFormat.find_format(dir)
 
181
            self.assertIsInstance(found_format, format.__class__)
 
182
        check_format(_mod_branch.BzrBranchFormat5(), "bar")
 
183
 
 
184
    def test_find_format_factory(self):
 
185
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
186
        SampleSupportedBranchFormat().initialize(dir)
 
187
        factory = _mod_branch.MetaDirBranchFormatFactory(
 
188
            SampleSupportedBranchFormatString,
 
189
            "bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
 
190
        _mod_branch.format_registry.register(factory)
 
191
        self.addCleanup(_mod_branch.format_registry.remove, factory)
 
192
        b = _mod_branch.Branch.open(self.get_url())
 
193
        self.assertEqual(b, "opened supported branch.")
 
194
 
174
195
    def test_find_format_not_branch(self):
175
196
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
176
 
        self.assertRaises(NotBranchError,
177
 
                          BranchFormat.find_format,
 
197
        self.assertRaises(errors.NotBranchError,
 
198
                          _mod_branch.BranchFormat.find_format,
178
199
                          dir)
179
200
 
180
201
    def test_find_format_unknown_format(self):
181
202
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
182
203
        SampleBranchFormat().initialize(dir)
183
 
        self.assertRaises(UnknownFormatError,
184
 
                          BranchFormat.find_format,
 
204
        self.assertRaises(errors.UnknownFormatError,
 
205
                          _mod_branch.BranchFormat.find_format,
185
206
                          dir)
186
207
 
187
208
    def test_register_unregister_format(self):
 
209
        # Test the deprecated format registration functions
188
210
        format = SampleBranchFormat()
189
211
        # make a control dir
190
212
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
191
213
        # make a branch
192
214
        format.initialize(dir)
193
215
        # register a format for it.
194
 
        BranchFormat.register_format(format)
 
216
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
217
            _mod_branch.BranchFormat.register_format, format)
195
218
        # which branch.Open will refuse (not supported)
196
 
        self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
 
219
        self.assertRaises(errors.UnsupportedFormatError,
 
220
                          _mod_branch.Branch.open, self.get_url())
197
221
        self.make_branch_and_tree('foo')
198
222
        # but open_downlevel will work
199
 
        self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
 
223
        self.assertEqual(
 
224
            format.open(dir),
 
225
            bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
200
226
        # unregister the format
201
 
        BranchFormat.unregister_format(format)
 
227
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
228
            _mod_branch.BranchFormat.unregister_format, format)
202
229
        self.make_branch_and_tree('bar')
203
230
 
204
231
 
 
232
class TestBranchFormatRegistry(tests.TestCase):
 
233
 
 
234
    def setUp(self):
 
235
        super(TestBranchFormatRegistry, self).setUp()
 
236
        self.registry = _mod_branch.BranchFormatRegistry()
 
237
 
 
238
    def test_default(self):
 
239
        self.assertIs(None, self.registry.get_default())
 
240
        format = SampleBranchFormat()
 
241
        self.registry.set_default(format)
 
242
        self.assertEquals(format, self.registry.get_default())
 
243
 
 
244
    def test_register_unregister_format(self):
 
245
        format = SampleBranchFormat()
 
246
        self.registry.register(format)
 
247
        self.assertEquals(format,
 
248
            self.registry.get("Sample branch format."))
 
249
        self.registry.remove(format)
 
250
        self.assertRaises(KeyError, self.registry.get,
 
251
            "Sample branch format.")
 
252
 
 
253
    def test_get_all(self):
 
254
        format = SampleBranchFormat()
 
255
        self.assertEquals([], self.registry._get_all())
 
256
        self.registry.register(format)
 
257
        self.assertEquals([format], self.registry._get_all())
 
258
 
 
259
    def test_register_extra(self):
 
260
        format = SampleExtraBranchFormat()
 
261
        self.assertEquals([], self.registry._get_all())
 
262
        self.registry.register_extra(format)
 
263
        self.assertEquals([format], self.registry._get_all())
 
264
 
 
265
    def test_register_extra_lazy(self):
 
266
        self.assertEquals([], self.registry._get_all())
 
267
        self.registry.register_extra_lazy("bzrlib.tests.test_branch",
 
268
            "SampleExtraBranchFormat")
 
269
        formats = self.registry._get_all()
 
270
        self.assertEquals(1, len(formats))
 
271
        self.assertIsInstance(formats[0], SampleExtraBranchFormat)
 
272
 
 
273
 
 
274
#Used by TestMetaDirBranchFormatFactory 
 
275
FakeLazyFormat = None
 
276
 
 
277
 
 
278
class TestMetaDirBranchFormatFactory(tests.TestCase):
 
279
 
 
280
    def test_get_format_string_does_not_load(self):
 
281
        """Formats have a static format string."""
 
282
        factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
 
283
        self.assertEqual("yo", factory.get_format_string())
 
284
 
 
285
    def test_call_loads(self):
 
286
        # __call__ is used by the network_format_registry interface to get a
 
287
        # Format.
 
288
        global FakeLazyFormat
 
289
        del FakeLazyFormat
 
290
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
 
291
            "bzrlib.tests.test_branch", "FakeLazyFormat")
 
292
        self.assertRaises(AttributeError, factory)
 
293
 
 
294
    def test_call_returns_call_of_referenced_object(self):
 
295
        global FakeLazyFormat
 
296
        FakeLazyFormat = lambda:'called'
 
297
        factory = _mod_branch.MetaDirBranchFormatFactory(None,
 
298
            "bzrlib.tests.test_branch", "FakeLazyFormat")
 
299
        self.assertEqual('called', factory())
 
300
 
 
301
 
205
302
class TestBranch67(object):
206
303
    """Common tests for both branch 6 and 7 which are mostly the same."""
207
304
 
215
312
        raise NotImplementedError(self.get_class)
216
313
 
217
314
    def test_creation(self):
218
 
        format = BzrDirMetaFormat1()
 
315
        format = bzrdir.BzrDirMetaFormat1()
219
316
        format.set_branch_format(_mod_branch.BzrBranchFormat6())
220
317
        branch = self.make_branch('a', format=format)
221
318
        self.assertIsInstance(branch, self.get_class())
226
323
 
227
324
    def test_layout(self):
228
325
        branch = self.make_branch('a', format=self.get_format_name())
229
 
        self.failUnlessExists('a/.bzr/branch/last-revision')
230
 
        self.failIfExists('a/.bzr/branch/revision-history')
 
326
        self.assertPathExists('a/.bzr/branch/last-revision')
 
327
        self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
 
328
        self.assertPathDoesNotExist('a/.bzr/branch/references')
231
329
 
232
330
    def test_config(self):
233
331
        """Ensure that all configuration data is stored in the branch"""
234
332
        branch = self.make_branch('a', format=self.get_format_name())
235
 
        branch.set_parent('http://bazaar-vcs.org')
236
 
        self.failIfExists('a/.bzr/branch/parent')
237
 
        self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
238
 
        branch.set_push_location('sftp://bazaar-vcs.org')
 
333
        branch.set_parent('http://example.com')
 
334
        self.assertPathDoesNotExist('a/.bzr/branch/parent')
 
335
        self.assertEqual('http://example.com', branch.get_parent())
 
336
        branch.set_push_location('sftp://example.com')
239
337
        config = branch.get_config()._get_branch_data_config()
240
 
        self.assertEqual('sftp://bazaar-vcs.org',
 
338
        self.assertEqual('sftp://example.com',
241
339
                         config.get_user_option('push_location'))
242
 
        branch.set_bound_location('ftp://bazaar-vcs.org')
243
 
        self.failIfExists('a/.bzr/branch/bound')
244
 
        self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
 
340
        branch.set_bound_location('ftp://example.com')
 
341
        self.assertPathDoesNotExist('a/.bzr/branch/bound')
 
342
        self.assertEqual('ftp://example.com', branch.get_bound_location())
245
343
 
246
344
    def test_set_revision_history(self):
247
345
        builder = self.make_branch_builder('.', format=self.get_format_name())
252
350
        branch = builder.get_branch()
253
351
        branch.lock_write()
254
352
        self.addCleanup(branch.unlock)
255
 
        branch.set_revision_history(['foo', 'bar'])
256
 
        branch.set_revision_history(['foo'])
 
353
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
354
            branch.set_revision_history, ['foo', 'bar'])
 
355
        self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
356
                branch.set_revision_history, ['foo'])
257
357
        self.assertRaises(errors.NotLefthandHistory,
258
 
                          branch.set_revision_history, ['bar'])
 
358
            self.applyDeprecated, symbol_versioning.deprecated_in((2, 4, 0)),
 
359
            branch.set_revision_history, ['bar'])
259
360
 
260
361
    def do_checkout_test(self, lightweight=False):
261
362
        tree = self.make_branch_and_tree('source',
274
375
        subtree.commit('a subtree file')
275
376
        subsubtree.commit('a subsubtree file')
276
377
        tree.branch.create_checkout('target', lightweight=lightweight)
277
 
        self.failUnlessExists('target')
278
 
        self.failUnlessExists('target/subtree')
279
 
        self.failUnlessExists('target/subtree/file')
280
 
        self.failUnlessExists('target/subtree/subsubtree/file')
 
378
        self.assertPathExists('target')
 
379
        self.assertPathExists('target/subtree')
 
380
        self.assertPathExists('target/subtree/file')
 
381
        self.assertPathExists('target/subtree/subsubtree/file')
281
382
        subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
282
383
        if lightweight:
283
384
            self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
307
408
                         'locations.conf')
308
409
 
309
410
 
310
 
class TestBranch6(TestBranch67, TestCaseWithTransport):
 
411
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
311
412
 
312
413
    def get_class(self):
313
414
        return _mod_branch.BzrBranch6
328
429
        self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
329
430
 
330
431
 
331
 
class TestBranch7(TestBranch67, TestCaseWithTransport):
 
432
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
332
433
 
333
434
    def get_class(self):
334
435
        return _mod_branch.BzrBranch7
335
436
 
336
437
    def get_format_name(self):
337
 
        return "development"
 
438
        return "1.9"
338
439
 
339
440
    def get_format_name_subtree(self):
340
441
        return "development-subtree"
378
479
        self.assertTrue(branch.repository.has_revision(revid))
379
480
 
380
481
 
381
 
class TestBranchReference(TestCaseWithTransport):
 
482
class BzrBranch8(tests.TestCaseWithTransport):
 
483
 
 
484
    def make_branch(self, location, format=None):
 
485
        if format is None:
 
486
            format = bzrdir.format_registry.make_bzrdir('1.9')
 
487
            format.set_branch_format(_mod_branch.BzrBranchFormat8())
 
488
        return tests.TestCaseWithTransport.make_branch(
 
489
            self, location, format=format)
 
490
 
 
491
    def create_branch_with_reference(self):
 
492
        branch = self.make_branch('branch')
 
493
        branch._set_all_reference_info({'file-id': ('path', 'location')})
 
494
        return branch
 
495
 
 
496
    @staticmethod
 
497
    def instrument_branch(branch, gets):
 
498
        old_get = branch._transport.get
 
499
        def get(*args, **kwargs):
 
500
            gets.append((args, kwargs))
 
501
            return old_get(*args, **kwargs)
 
502
        branch._transport.get = get
 
503
 
 
504
    def test_reference_info_caching_read_locked(self):
 
505
        gets = []
 
506
        branch = self.create_branch_with_reference()
 
507
        branch.lock_read()
 
508
        self.addCleanup(branch.unlock)
 
509
        self.instrument_branch(branch, gets)
 
510
        branch.get_reference_info('file-id')
 
511
        branch.get_reference_info('file-id')
 
512
        self.assertEqual(1, len(gets))
 
513
 
 
514
    def test_reference_info_caching_read_unlocked(self):
 
515
        gets = []
 
516
        branch = self.create_branch_with_reference()
 
517
        self.instrument_branch(branch, gets)
 
518
        branch.get_reference_info('file-id')
 
519
        branch.get_reference_info('file-id')
 
520
        self.assertEqual(2, len(gets))
 
521
 
 
522
    def test_reference_info_caching_write_locked(self):
 
523
        gets = []
 
524
        branch = self.make_branch('branch')
 
525
        branch.lock_write()
 
526
        self.instrument_branch(branch, gets)
 
527
        self.addCleanup(branch.unlock)
 
528
        branch._set_all_reference_info({'file-id': ('path2', 'location2')})
 
529
        path, location = branch.get_reference_info('file-id')
 
530
        self.assertEqual(0, len(gets))
 
531
        self.assertEqual('path2', path)
 
532
        self.assertEqual('location2', location)
 
533
 
 
534
    def test_reference_info_caches_cleared(self):
 
535
        branch = self.make_branch('branch')
 
536
        branch.lock_write()
 
537
        branch.set_reference_info('file-id', 'path2', 'location2')
 
538
        branch.unlock()
 
539
        doppelganger = _mod_branch.Branch.open('branch')
 
540
        doppelganger.set_reference_info('file-id', 'path3', 'location3')
 
541
        self.assertEqual(('path3', 'location3'),
 
542
                         branch.get_reference_info('file-id'))
 
543
 
 
544
class TestBranchReference(tests.TestCaseWithTransport):
382
545
    """Tests for the branch reference facility."""
383
546
 
384
547
    def test_create_open_reference(self):
385
548
        bzrdirformat = bzrdir.BzrDirMetaFormat1()
386
 
        t = get_transport(self.get_url('.'))
 
549
        t = self.get_transport()
387
550
        t.mkdir('repo')
388
551
        dir = bzrdirformat.initialize(self.get_url('repo'))
389
552
        dir.create_repository()
390
553
        target_branch = dir.create_branch()
391
554
        t.mkdir('branch')
392
555
        branch_dir = bzrdirformat.initialize(self.get_url('branch'))
393
 
        made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
 
556
        made_branch = _mod_branch.BranchReferenceFormat().initialize(
 
557
            branch_dir, target_branch=target_branch)
394
558
        self.assertEqual(made_branch.base, target_branch.base)
395
559
        opened_branch = branch_dir.open_branch()
396
560
        self.assertEqual(opened_branch.base, target_branch.base)
407
571
            _mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
408
572
 
409
573
 
410
 
class TestHooks(TestCase):
 
574
class TestHooks(tests.TestCaseWithTransport):
411
575
 
412
576
    def test_constructor(self):
413
577
        """Check that creating a BranchHooks instance has the right defaults."""
414
 
        hooks = BranchHooks()
 
578
        hooks = _mod_branch.BranchHooks()
415
579
        self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
416
580
        self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
417
581
        self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
418
582
        self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
419
583
        self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
420
 
        self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
 
584
        self.assertTrue("post_uncommit" in hooks,
 
585
                        "post_uncommit not in %s" % hooks)
421
586
        self.assertTrue("post_change_branch_tip" in hooks,
422
587
                        "post_change_branch_tip not in %s" % hooks)
 
588
        self.assertTrue("post_branch_init" in hooks,
 
589
                        "post_branch_init not in %s" % hooks)
 
590
        self.assertTrue("post_switch" in hooks,
 
591
                        "post_switch not in %s" % hooks)
423
592
 
424
593
    def test_installed_hooks_are_BranchHooks(self):
425
594
        """The installed hooks object should be a BranchHooks."""
426
595
        # the installed hooks are saved in self._preserved_hooks.
427
 
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
428
 
 
429
 
 
430
 
class TestPullResult(TestCase):
 
596
        self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
 
597
                              _mod_branch.BranchHooks)
 
598
 
 
599
    def test_post_branch_init_hook(self):
 
600
        calls = []
 
601
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
 
602
            calls.append, None)
 
603
        self.assertLength(0, calls)
 
604
        branch = self.make_branch('a')
 
605
        self.assertLength(1, calls)
 
606
        params = calls[0]
 
607
        self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
 
608
        self.assertTrue(hasattr(params, 'bzrdir'))
 
609
        self.assertTrue(hasattr(params, 'branch'))
 
610
 
 
611
    def test_post_branch_init_hook_repr(self):
 
612
        param_reprs = []
 
613
        _mod_branch.Branch.hooks.install_named_hook('post_branch_init',
 
614
            lambda params: param_reprs.append(repr(params)), None)
 
615
        branch = self.make_branch('a')
 
616
        self.assertLength(1, param_reprs)
 
617
        param_repr = param_reprs[0]
 
618
        self.assertStartsWith(param_repr, '<BranchInitHookParams of ')
 
619
 
 
620
    def test_post_switch_hook(self):
 
621
        from bzrlib import switch
 
622
        calls = []
 
623
        _mod_branch.Branch.hooks.install_named_hook('post_switch',
 
624
            calls.append, None)
 
625
        tree = self.make_branch_and_tree('branch-1')
 
626
        self.build_tree(['branch-1/file-1'])
 
627
        tree.add('file-1')
 
628
        tree.commit('rev1')
 
629
        to_branch = tree.bzrdir.sprout('branch-2').open_branch()
 
630
        self.build_tree(['branch-1/file-2'])
 
631
        tree.add('file-2')
 
632
        tree.remove('file-1')
 
633
        tree.commit('rev2')
 
634
        checkout = tree.branch.create_checkout('checkout')
 
635
        self.assertLength(0, calls)
 
636
        switch.switch(checkout.bzrdir, to_branch)
 
637
        self.assertLength(1, calls)
 
638
        params = calls[0]
 
639
        self.assertIsInstance(params, _mod_branch.SwitchHookParams)
 
640
        self.assertTrue(hasattr(params, 'to_branch'))
 
641
        self.assertTrue(hasattr(params, 'revision_id'))
 
642
 
 
643
 
 
644
class TestBranchOptions(tests.TestCaseWithTransport):
 
645
 
 
646
    def setUp(self):
 
647
        super(TestBranchOptions, self).setUp()
 
648
        self.branch = self.make_branch('.')
 
649
        self.config = self.branch.get_config()
 
650
 
 
651
    def check_append_revisions_only(self, expected_value, value=None):
 
652
        """Set append_revisions_only in config and check its interpretation."""
 
653
        if value is not None:
 
654
            self.config.set_user_option('append_revisions_only', value)
 
655
        self.assertEqual(expected_value,
 
656
                         self.branch.get_append_revisions_only())
 
657
 
 
658
    def test_valid_append_revisions_only(self):
 
659
        self.assertEquals(None,
 
660
                          self.config.get_user_option('append_revisions_only'))
 
661
        self.check_append_revisions_only(None)
 
662
        self.check_append_revisions_only(False, 'False')
 
663
        self.check_append_revisions_only(True, 'True')
 
664
        # The following values will cause compatibility problems on projects
 
665
        # using older bzr versions (<2.2) but are accepted
 
666
        self.check_append_revisions_only(False, 'false')
 
667
        self.check_append_revisions_only(True, 'true')
 
668
 
 
669
    def test_invalid_append_revisions_only(self):
 
670
        """Ensure warning is noted on invalid settings"""
 
671
        self.warnings = []
 
672
        def warning(*args):
 
673
            self.warnings.append(args[0] % args[1:])
 
674
        self.overrideAttr(trace, 'warning', warning)
 
675
        self.check_append_revisions_only(None, 'not-a-bool')
 
676
        self.assertLength(1, self.warnings)
 
677
        self.assertEqual(
 
678
            'Value "not-a-bool" is not a boolean for "append_revisions_only"',
 
679
            self.warnings[0])
 
680
 
 
681
 
 
682
class TestPullResult(tests.TestCase):
431
683
 
432
684
    def test_pull_result_to_int(self):
433
685
        # to support old code, the pull result can be used as an int
434
 
        r = PullResult()
 
686
        r = _mod_branch.PullResult()
435
687
        r.old_revno = 10
436
688
        r.new_revno = 20
437
689
        # this usage of results is not recommended for new code (because it
438
690
        # doesn't describe very well what happened), but for api stability
439
691
        # it's still supported
440
 
        a = "%d revisions pulled" % r
441
 
        self.assertEqual(a, "10 revisions pulled")
442
 
 
443
 
 
444
 
 
445
 
class _StubLockable(object):
446
 
    """Helper for TestRunWithWriteLockedTarget."""
447
 
 
448
 
    def __init__(self, calls, unlock_exc=None):
449
 
        self.calls = calls
450
 
        self.unlock_exc = unlock_exc
451
 
 
452
 
    def lock_write(self):
453
 
        self.calls.append('lock_write')
454
 
    
455
 
    def unlock(self):
456
 
        self.calls.append('unlock')
457
 
        if self.unlock_exc is not None:
458
 
            raise self.unlock_exc
459
 
 
460
 
 
461
 
class _ErrorFromCallable(Exception):
462
 
    """Helper for TestRunWithWriteLockedTarget."""
463
 
 
464
 
 
465
 
class _ErrorFromUnlock(Exception):
466
 
    """Helper for TestRunWithWriteLockedTarget."""
467
 
 
468
 
 
469
 
class TestRunWithWriteLockedTarget(TestCase):
470
 
    """Tests for _run_with_write_locked_target."""
471
 
 
472
 
    def setUp(self):
473
 
        self._calls = []
474
 
 
475
 
    def func_that_returns_ok(self):
476
 
        self._calls.append('func called')
477
 
        return 'ok'
478
 
 
479
 
    def func_that_raises(self):
480
 
        self._calls.append('func called')
481
 
        raise _ErrorFromCallable()
482
 
 
483
 
    def test_success_unlocks(self):
484
 
        lockable = _StubLockable(self._calls)
485
 
        result = _run_with_write_locked_target(
486
 
            lockable, self.func_that_returns_ok)
487
 
        self.assertEqual('ok', result)
488
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
489
 
 
490
 
    def test_exception_unlocks_and_propagates(self):
491
 
        lockable = _StubLockable(self._calls)
492
 
        self.assertRaises(_ErrorFromCallable,
493
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
494
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
495
 
 
496
 
    def test_callable_succeeds_but_error_during_unlock(self):
497
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
498
 
        self.assertRaises(_ErrorFromUnlock,
499
 
            _run_with_write_locked_target, lockable, self.func_that_returns_ok)
500
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
501
 
 
502
 
    def test_error_during_unlock_does_not_mask_original_error(self):
503
 
        lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
504
 
        self.assertRaises(_ErrorFromCallable,
505
 
            _run_with_write_locked_target, lockable, self.func_that_raises)
506
 
        self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
507
 
 
 
692
        self.assertEqual(self.applyDeprecated(
 
693
            symbol_versioning.deprecated_in((2, 3, 0)),
 
694
            r.__int__),
 
695
            10)
 
696
 
 
697
    def test_report_changed(self):
 
698
        r = _mod_branch.PullResult()
 
699
        r.old_revid = "old-revid"
 
700
        r.old_revno = 10
 
701
        r.new_revid = "new-revid"
 
702
        r.new_revno = 20
 
703
        f = StringIO()
 
704
        r.report(f)
 
705
        self.assertEqual("Now on revision 20.\n", f.getvalue())
 
706
 
 
707
    def test_report_unchanged(self):
 
708
        r = _mod_branch.PullResult()
 
709
        r.old_revid = "same-revid"
 
710
        r.new_revid = "same-revid"
 
711
        f = StringIO()
 
712
        r.report(f)
 
713
        self.assertEqual("No revisions or tags to pull.\n", f.getvalue())
508
714