~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_branch.py

  • Committer: Andrew Bennetts
  • Date: 2008-05-21 02:34:32 UTC
  • mto: (3452.2.9 inter-remote-pack)
  • mto: This revision was merged to the branch mainline in revision 3452.
  • Revision ID: andrew.bennetts@canonical.com-20080521023432-rj4qn81st9sou7np
Buffer encoding of v3 messages to minimise write/send calls.  Doubles the speed of pushing over TCP with 500ms latency loopback.

Show diffs side-by-side

added added

removed removed

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