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
17
17
"""Tests for the Branch facility that are not interface tests.
19
For interface tests see tests/branch_implementations/*.py.
19
For interface tests see `tests/per_branch/*.py`.
21
21
For concrete class tests see this file, and for meta-branch tests
22
22
also see this file.
25
from StringIO import StringIO
25
from cStringIO import StringIO
27
27
from bzrlib import (
28
28
branch as _mod_branch,
34
from bzrlib.branch import (BzrBranch5,
36
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
38
from bzrlib.errors import (NotBranchError,
41
UnsupportedFormatError,
44
from bzrlib.tests import TestCase, TestCaseWithTransport
45
from bzrlib.transport import get_transport
47
class TestDefaultFormat(TestCase):
39
class TestDefaultFormat(tests.TestCase):
41
def test_default_format(self):
42
# update this if you change the default branch format
43
self.assertIsInstance(_mod_branch.format_registry.get_default(),
44
_mod_branch.BzrBranchFormat7)
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
48
# set, but at the moment that's not true -- mbp 20070814 --
49
# https://bugs.launchpad.net/bzr/+bug/132376
51
_mod_branch.format_registry.get_default(),
52
bzrdir.BzrDirFormat.get_default_format().get_branch_format())
49
54
def test_get_set_default_format(self):
50
old_format = bzrlib.branch.BranchFormat.get_default_format()
52
self.assertTrue(isinstance(old_format, bzrlib.branch.BzrBranchFormat5))
53
bzrlib.branch.BranchFormat.set_default_format(SampleBranchFormat())
55
# set the format and then set it back again
56
old_format = _mod_branch.format_registry.get_default()
57
_mod_branch.format_registry.set_default(SampleBranchFormat())
55
59
# the default branch format is used by the meta dir format
56
60
# which is not the default bzrdir format at this point
57
dir = BzrDirMetaFormat1().initialize('memory:///')
61
dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
58
62
result = dir.create_branch()
59
63
self.assertEqual(result, 'A branch')
61
bzrlib.branch.BranchFormat.set_default_format(old_format)
62
self.assertEqual(old_format, bzrlib.branch.BranchFormat.get_default_format())
65
class TestBranchFormat5(TestCaseWithTransport):
65
_mod_branch.format_registry.set_default(old_format)
66
self.assertEqual(old_format,
67
_mod_branch.format_registry.get_default())
70
class TestBranchFormat5(tests.TestCaseWithTransport):
66
71
"""Tests specific to branch format 5"""
68
73
def test_branch_format_5_uses_lockdir(self):
69
74
url = self.get_url()
70
bzrdir = BzrDirMetaFormat1().initialize(url)
71
bzrdir.create_repository()
72
branch = bzrdir.create_branch()
75
bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
76
bdir.create_repository()
77
branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
73
78
t = self.get_transport()
74
79
self.log("branch instance is %r" % branch)
75
self.assert_(isinstance(branch, BzrBranch5))
80
self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
76
81
self.assertIsDirectory('.', t)
77
82
self.assertIsDirectory('.bzr/branch', t)
78
83
self.assertIsDirectory('.bzr/branch/lock', t)
79
84
branch.lock_write()
81
self.assertIsDirectory('.bzr/branch/lock/held', t)
85
self.addCleanup(branch.unlock)
86
self.assertIsDirectory('.bzr/branch/lock/held', t)
85
88
def test_set_push_location(self):
86
from bzrlib.config import (locations_config_filename,
87
ensure_config_dir_exists)
88
ensure_config_dir_exists()
89
fn = locations_config_filename()
89
conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
90
91
branch = self.make_branch('.', format='knit')
91
92
branch.set_push_location('foo')
92
93
local_path = urlutils.local_path_from_url(branch.base[:-1])
93
self.assertFileEqual("[%s]\n"
94
self.assertFileEqual("# comment\n"
94
96
"push_location = foo\n"
95
"push_location:policy = norecurse" % local_path,
97
"push_location:policy = norecurse\n" % local_path,
98
config.locations_config_filename())
98
100
# TODO RBC 20051029 test getting a push location from a branch in a
99
101
# recursive section - that is, it appends the branch name.
102
class SampleBranchFormat(bzrlib.branch.BranchFormat):
104
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
103
105
"""A sample format
105
this format is initializable, unsupported to aid in testing the
107
this format is initializable, unsupported to aid in testing the
106
108
open and open_downlevel routines.
109
def get_format_string(self):
112
def get_format_string(cls):
110
113
"""See BzrBranchFormat.get_format_string()."""
111
114
return "Sample branch format."
113
def initialize(self, a_bzrdir):
116
def initialize(self, a_bzrdir, name=None, repository=None,
117
append_revisions_only=None):
114
118
"""Format 4 branches cannot be created."""
115
t = a_bzrdir.get_branch_transport(self)
119
t = a_bzrdir.get_branch_transport(self, name=name)
116
120
t.put_bytes('format', self.get_format_string())
117
121
return 'A branch'
119
123
def is_supported(self):
122
def open(self, transport, _found=False):
126
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
127
possible_transports=None):
123
128
return "opened branch."
126
class TestBzrBranchFormat(TestCaseWithTransport):
131
# Demonstrating how lazy loading is often implemented:
132
# A constant string is created.
133
SampleSupportedBranchFormatString = "Sample supported branch format."
135
# And the format class can then reference the constant to avoid skew.
136
class SampleSupportedBranchFormat(_mod_branch.BranchFormatMetadir):
137
"""A sample supported format."""
140
def get_format_string(cls):
141
"""See BzrBranchFormat.get_format_string()."""
142
return SampleSupportedBranchFormatString
144
def initialize(self, a_bzrdir, name=None, append_revisions_only=None):
145
t = a_bzrdir.get_branch_transport(self, name=name)
146
t.put_bytes('format', self.get_format_string())
149
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
150
possible_transports=None):
151
return "opened supported branch."
154
class SampleExtraBranchFormat(_mod_branch.BranchFormat):
155
"""A sample format that is not usable in a metadir."""
157
def get_format_string(self):
158
# This format is not usable in a metadir.
161
def network_name(self):
162
# Network name always has to be provided.
165
def initialize(self, a_bzrdir, name=None):
166
raise NotImplementedError(self.initialize)
168
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
169
possible_transports=None):
170
raise NotImplementedError(self.open)
173
class TestBzrBranchFormat(tests.TestCaseWithTransport):
127
174
"""Tests for the BzrBranchFormat facility."""
129
176
def test_find_format(self):
130
177
# is the right format object found for a branch?
131
178
# create a branch with a few known format objects.
132
# this is not quite the same as
179
# this is not quite the same as
133
180
self.build_tree(["foo/", "bar/"])
134
181
def check_format(format, url):
135
182
dir = format._matchingbzrdir.initialize(url)
136
183
dir.create_repository()
137
184
format.initialize(dir)
138
found_format = bzrlib.branch.BranchFormat.find_format(dir)
139
self.failUnless(isinstance(found_format, format.__class__))
140
check_format(bzrlib.branch.BzrBranchFormat5(), "bar")
185
found_format = _mod_branch.BranchFormatMetadir.find_format(dir)
186
self.assertIsInstance(found_format, format.__class__)
187
check_format(_mod_branch.BzrBranchFormat5(), "bar")
189
def test_find_format_factory(self):
190
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
191
SampleSupportedBranchFormat().initialize(dir)
192
factory = _mod_branch.MetaDirBranchFormatFactory(
193
SampleSupportedBranchFormatString,
194
"bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
195
_mod_branch.format_registry.register(factory)
196
self.addCleanup(_mod_branch.format_registry.remove, factory)
197
b = _mod_branch.Branch.open(self.get_url())
198
self.assertEqual(b, "opened supported branch.")
200
def test_from_string(self):
201
self.assertIsInstance(
202
SampleBranchFormat.from_string("Sample branch format."),
204
self.assertRaises(AssertionError,
205
SampleBranchFormat.from_string, "Different branch format.")
142
207
def test_find_format_not_branch(self):
143
208
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
144
self.assertRaises(NotBranchError,
145
bzrlib.branch.BranchFormat.find_format,
209
self.assertRaises(errors.NotBranchError,
210
_mod_branch.BranchFormatMetadir.find_format,
148
213
def test_find_format_unknown_format(self):
149
214
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
150
215
SampleBranchFormat().initialize(dir)
151
self.assertRaises(UnknownFormatError,
152
bzrlib.branch.BranchFormat.find_format,
216
self.assertRaises(errors.UnknownFormatError,
217
_mod_branch.BranchFormatMetadir.find_format,
220
def test_find_format_with_features(self):
221
tree = self.make_branch_and_tree('.', format='2a')
222
tree.branch.update_feature_flags({"name": "optional"})
223
found_format = _mod_branch.BranchFormatMetadir.find_format(tree.bzrdir)
224
self.assertIsInstance(found_format, _mod_branch.BranchFormatMetadir)
225
self.assertEquals(found_format.features.get("name"), "optional")
226
tree.branch.update_feature_flags({"name": None})
227
branch = _mod_branch.Branch.open('.')
228
self.assertEquals(branch._format.features, {})
155
230
def test_register_unregister_format(self):
231
# Test the deprecated format registration functions
156
232
format = SampleBranchFormat()
157
233
# make a control dir
158
234
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
160
236
format.initialize(dir)
161
237
# register a format for it.
162
bzrlib.branch.BranchFormat.register_format(format)
238
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
239
_mod_branch.BranchFormat.register_format, format)
163
240
# which branch.Open will refuse (not supported)
164
self.assertRaises(UnsupportedFormatError, bzrlib.branch.Branch.open, self.get_url())
241
self.assertRaises(errors.UnsupportedFormatError,
242
_mod_branch.Branch.open, self.get_url())
165
243
self.make_branch_and_tree('foo')
166
244
# but open_downlevel will work
167
self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
247
bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
168
248
# unregister the format
169
bzrlib.branch.BranchFormat.unregister_format(format)
249
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
250
_mod_branch.BranchFormat.unregister_format, format)
170
251
self.make_branch_and_tree('bar')
172
def test_checkout_format(self):
173
branch = self.make_repository('repository', shared=True)
174
branch = self.make_branch('repository/branch',
176
tree = branch.create_checkout('checkout')
177
self.assertIs(tree.branch.__class__, _mod_branch.BzrBranch5)
180
class TestBranch6(TestCaseWithTransport):
254
class TestBranchFormatRegistry(tests.TestCase):
257
super(TestBranchFormatRegistry, self).setUp()
258
self.registry = _mod_branch.BranchFormatRegistry()
260
def test_default(self):
261
self.assertIs(None, self.registry.get_default())
262
format = SampleBranchFormat()
263
self.registry.set_default(format)
264
self.assertEquals(format, self.registry.get_default())
266
def test_register_unregister_format(self):
267
format = SampleBranchFormat()
268
self.registry.register(format)
269
self.assertEquals(format,
270
self.registry.get("Sample branch format."))
271
self.registry.remove(format)
272
self.assertRaises(KeyError, self.registry.get,
273
"Sample branch format.")
275
def test_get_all(self):
276
format = SampleBranchFormat()
277
self.assertEquals([], self.registry._get_all())
278
self.registry.register(format)
279
self.assertEquals([format], self.registry._get_all())
281
def test_register_extra(self):
282
format = SampleExtraBranchFormat()
283
self.assertEquals([], self.registry._get_all())
284
self.registry.register_extra(format)
285
self.assertEquals([format], self.registry._get_all())
287
def test_register_extra_lazy(self):
288
self.assertEquals([], self.registry._get_all())
289
self.registry.register_extra_lazy("bzrlib.tests.test_branch",
290
"SampleExtraBranchFormat")
291
formats = self.registry._get_all()
292
self.assertEquals(1, len(formats))
293
self.assertIsInstance(formats[0], SampleExtraBranchFormat)
296
#Used by TestMetaDirBranchFormatFactory
297
FakeLazyFormat = None
300
class TestMetaDirBranchFormatFactory(tests.TestCase):
302
def test_get_format_string_does_not_load(self):
303
"""Formats have a static format string."""
304
factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
305
self.assertEqual("yo", factory.get_format_string())
307
def test_call_loads(self):
308
# __call__ is used by the network_format_registry interface to get a
310
global FakeLazyFormat
312
factory = _mod_branch.MetaDirBranchFormatFactory(None,
313
"bzrlib.tests.test_branch", "FakeLazyFormat")
314
self.assertRaises(AttributeError, factory)
316
def test_call_returns_call_of_referenced_object(self):
317
global FakeLazyFormat
318
FakeLazyFormat = lambda:'called'
319
factory = _mod_branch.MetaDirBranchFormatFactory(None,
320
"bzrlib.tests.test_branch", "FakeLazyFormat")
321
self.assertEqual('called', factory())
324
class TestBranch67(object):
325
"""Common tests for both branch 6 and 7 which are mostly the same."""
327
def get_format_name(self):
328
raise NotImplementedError(self.get_format_name)
330
def get_format_name_subtree(self):
331
raise NotImplementedError(self.get_format_name)
334
raise NotImplementedError(self.get_class)
182
336
def test_creation(self):
183
format = BzrDirMetaFormat1()
337
format = bzrdir.BzrDirMetaFormat1()
184
338
format.set_branch_format(_mod_branch.BzrBranchFormat6())
185
339
branch = self.make_branch('a', format=format)
186
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
187
branch = self.make_branch('b', format='experimental-branch6')
188
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
340
self.assertIsInstance(branch, self.get_class())
341
branch = self.make_branch('b', format=self.get_format_name())
342
self.assertIsInstance(branch, self.get_class())
189
343
branch = _mod_branch.Branch.open('a')
190
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
344
self.assertIsInstance(branch, self.get_class())
192
346
def test_layout(self):
193
branch = self.make_branch('a', format='experimental-branch6')
194
self.failUnlessExists('a/.bzr/branch/last-revision')
195
self.failIfExists('a/.bzr/branch/revision-history')
347
branch = self.make_branch('a', format=self.get_format_name())
348
self.assertPathExists('a/.bzr/branch/last-revision')
349
self.assertPathDoesNotExist('a/.bzr/branch/revision-history')
350
self.assertPathDoesNotExist('a/.bzr/branch/references')
197
352
def test_config(self):
198
353
"""Ensure that all configuration data is stored in the branch"""
199
branch = self.make_branch('a', format='experimental-branch6')
200
branch.set_parent('http://bazaar-vcs.org')
201
self.failIfExists('a/.bzr/branch/parent')
202
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
203
branch.set_push_location('sftp://bazaar-vcs.org')
204
config = branch.get_config()._get_branch_data_config()
205
self.assertEqual('sftp://bazaar-vcs.org',
206
config.get_user_option('push_location'))
207
branch.set_bound_location('ftp://bazaar-vcs.org')
208
self.failIfExists('a/.bzr/branch/bound')
209
self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
354
branch = self.make_branch('a', format=self.get_format_name())
355
branch.set_parent('http://example.com')
356
self.assertPathDoesNotExist('a/.bzr/branch/parent')
357
self.assertEqual('http://example.com', branch.get_parent())
358
branch.set_push_location('sftp://example.com')
359
conf = branch.get_config_stack()
360
self.assertEqual('sftp://example.com', conf.get('push_location'))
361
branch.set_bound_location('ftp://example.com')
362
self.assertPathDoesNotExist('a/.bzr/branch/bound')
363
self.assertEqual('ftp://example.com', branch.get_bound_location())
211
365
def test_set_revision_history(self):
212
tree = self.make_branch_and_memory_tree('.',
213
format='experimental-branch6')
217
tree.commit('foo', rev_id='foo')
218
tree.commit('bar', rev_id='bar')
219
tree.branch.set_revision_history(['foo', 'bar'])
220
tree.branch.set_revision_history(['foo'])
221
self.assertRaises(errors.NotLefthandHistory,
222
tree.branch.set_revision_history, ['bar'])
226
def test_append_revision(self):
227
tree = self.make_branch_and_tree('branch1',
228
format='experimental-branch6')
232
tree.commit('foo', rev_id='foo')
233
tree.commit('bar', rev_id='bar')
234
tree.commit('baz', rev_id='baz')
235
tree.set_last_revision('bar')
236
tree.branch.set_last_revision_info(2, 'bar')
237
tree.commit('qux', rev_id='qux')
238
tree.add_parent_tree_id('baz')
239
tree.commit('qux', rev_id='quxx')
240
tree.branch.set_last_revision_info(0, 'null:')
241
self.assertRaises(errors.NotLeftParentDescendant,
242
tree.branch.append_revision, 'bar')
243
tree.branch.append_revision('foo')
244
self.assertRaises(errors.NotLeftParentDescendant,
245
tree.branch.append_revision, 'baz')
246
tree.branch.append_revision('bar')
247
tree.branch.append_revision('baz')
248
self.assertRaises(errors.NotLeftParentDescendant,
249
tree.branch.append_revision, 'quxx')
254
class TestBranchReference(TestCaseWithTransport):
366
builder = self.make_branch_builder('.', format=self.get_format_name())
367
builder.build_snapshot('foo', None,
368
[('add', ('', None, 'directory', None))],
370
builder.build_snapshot('bar', None, [], message='bar')
371
branch = builder.get_branch()
373
self.addCleanup(branch.unlock)
374
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
375
branch.set_revision_history, ['foo', 'bar'])
376
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
377
branch.set_revision_history, ['foo'])
378
self.assertRaises(errors.NotLefthandHistory,
379
self.applyDeprecated, symbol_versioning.deprecated_in((2, 4, 0)),
380
branch.set_revision_history, ['bar'])
382
def do_checkout_test(self, lightweight=False):
383
tree = self.make_branch_and_tree('source',
384
format=self.get_format_name_subtree())
385
subtree = self.make_branch_and_tree('source/subtree',
386
format=self.get_format_name_subtree())
387
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
388
format=self.get_format_name_subtree())
389
self.build_tree(['source/subtree/file',
390
'source/subtree/subsubtree/file'])
391
subsubtree.add('file')
393
subtree.add_reference(subsubtree)
394
tree.add_reference(subtree)
395
tree.commit('a revision')
396
subtree.commit('a subtree file')
397
subsubtree.commit('a subsubtree file')
398
tree.branch.create_checkout('target', lightweight=lightweight)
399
self.assertPathExists('target')
400
self.assertPathExists('target/subtree')
401
self.assertPathExists('target/subtree/file')
402
self.assertPathExists('target/subtree/subsubtree/file')
403
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
405
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
407
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
409
def test_checkout_with_references(self):
410
self.do_checkout_test()
412
def test_light_checkout_with_references(self):
413
self.do_checkout_test(lightweight=True)
416
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
419
return _mod_branch.BzrBranch6
421
def get_format_name(self):
422
return "dirstate-tags"
424
def get_format_name_subtree(self):
425
return "dirstate-with-subtree"
427
def test_set_stacked_on_url_errors(self):
428
branch = self.make_branch('a', format=self.get_format_name())
429
self.assertRaises(errors.UnstackableBranchFormat,
430
branch.set_stacked_on_url, None)
432
def test_default_stacked_location(self):
433
branch = self.make_branch('a', format=self.get_format_name())
434
self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
437
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
440
return _mod_branch.BzrBranch7
442
def get_format_name(self):
445
def get_format_name_subtree(self):
446
return "development-subtree"
448
def test_set_stacked_on_url_unstackable_repo(self):
449
repo = self.make_repository('a', format='dirstate-tags')
450
control = repo.bzrdir
451
branch = _mod_branch.BzrBranchFormat7().initialize(control)
452
target = self.make_branch('b')
453
self.assertRaises(errors.UnstackableRepositoryFormat,
454
branch.set_stacked_on_url, target.base)
456
def test_clone_stacked_on_unstackable_repo(self):
457
repo = self.make_repository('a', format='dirstate-tags')
458
control = repo.bzrdir
459
branch = _mod_branch.BzrBranchFormat7().initialize(control)
460
# Calling clone should not raise UnstackableRepositoryFormat.
461
cloned_bzrdir = control.clone('cloned')
463
def _test_default_stacked_location(self):
464
branch = self.make_branch('a', format=self.get_format_name())
465
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
467
def test_stack_and_unstack(self):
468
branch = self.make_branch('a', format=self.get_format_name())
469
target = self.make_branch_and_tree('b', format=self.get_format_name())
470
branch.set_stacked_on_url(target.branch.base)
471
self.assertEqual(target.branch.base, branch.get_stacked_on_url())
472
revid = target.commit('foo')
473
self.assertTrue(branch.repository.has_revision(revid))
474
branch.set_stacked_on_url(None)
475
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
476
self.assertFalse(branch.repository.has_revision(revid))
478
def test_open_opens_stacked_reference(self):
479
branch = self.make_branch('a', format=self.get_format_name())
480
target = self.make_branch_and_tree('b', format=self.get_format_name())
481
branch.set_stacked_on_url(target.branch.base)
482
branch = branch.bzrdir.open_branch()
483
revid = target.commit('foo')
484
self.assertTrue(branch.repository.has_revision(revid))
487
class BzrBranch8(tests.TestCaseWithTransport):
489
def make_branch(self, location, format=None):
491
format = bzrdir.format_registry.make_bzrdir('1.9')
492
format.set_branch_format(_mod_branch.BzrBranchFormat8())
493
return tests.TestCaseWithTransport.make_branch(
494
self, location, format=format)
496
def create_branch_with_reference(self):
497
branch = self.make_branch('branch')
498
branch._set_all_reference_info({'file-id': ('path', 'location')})
502
def instrument_branch(branch, gets):
503
old_get = branch._transport.get
504
def get(*args, **kwargs):
505
gets.append((args, kwargs))
506
return old_get(*args, **kwargs)
507
branch._transport.get = get
509
def test_reference_info_caching_read_locked(self):
511
branch = self.create_branch_with_reference()
513
self.addCleanup(branch.unlock)
514
self.instrument_branch(branch, gets)
515
branch.get_reference_info('file-id')
516
branch.get_reference_info('file-id')
517
self.assertEqual(1, len(gets))
519
def test_reference_info_caching_read_unlocked(self):
521
branch = self.create_branch_with_reference()
522
self.instrument_branch(branch, gets)
523
branch.get_reference_info('file-id')
524
branch.get_reference_info('file-id')
525
self.assertEqual(2, len(gets))
527
def test_reference_info_caching_write_locked(self):
529
branch = self.make_branch('branch')
531
self.instrument_branch(branch, gets)
532
self.addCleanup(branch.unlock)
533
branch._set_all_reference_info({'file-id': ('path2', 'location2')})
534
path, location = branch.get_reference_info('file-id')
535
self.assertEqual(0, len(gets))
536
self.assertEqual('path2', path)
537
self.assertEqual('location2', location)
539
def test_reference_info_caches_cleared(self):
540
branch = self.make_branch('branch')
542
branch.set_reference_info('file-id', 'path2', 'location2')
544
doppelganger = _mod_branch.Branch.open('branch')
545
doppelganger.set_reference_info('file-id', 'path3', 'location3')
546
self.assertEqual(('path3', 'location3'),
547
branch.get_reference_info('file-id'))
549
def _recordParentMapCalls(self, repo):
550
self._parent_map_calls = []
551
orig_get_parent_map = repo.revisions.get_parent_map
552
def get_parent_map(q):
554
self._parent_map_calls.extend([e[0] for e in q])
555
return orig_get_parent_map(q)
556
repo.revisions.get_parent_map = get_parent_map
559
class TestBranchReference(tests.TestCaseWithTransport):
255
560
"""Tests for the branch reference facility."""
257
562
def test_create_open_reference(self):
258
563
bzrdirformat = bzrdir.BzrDirMetaFormat1()
259
t = get_transport(self.get_url('.'))
564
t = self.get_transport()
261
566
dir = bzrdirformat.initialize(self.get_url('repo'))
262
567
dir.create_repository()
263
568
target_branch = dir.create_branch()
264
569
t.mkdir('branch')
265
570
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
266
made_branch = bzrlib.branch.BranchReferenceFormat().initialize(branch_dir, target_branch)
571
made_branch = _mod_branch.BranchReferenceFormat().initialize(
572
branch_dir, target_branch=target_branch)
267
573
self.assertEqual(made_branch.base, target_branch.base)
268
574
opened_branch = branch_dir.open_branch()
269
575
self.assertEqual(opened_branch.base, target_branch.base)
272
class TestHooks(TestCase):
577
def test_get_reference(self):
578
"""For a BranchReference, get_reference should return the location."""
579
branch = self.make_branch('target')
580
checkout = branch.create_checkout('checkout', lightweight=True)
581
reference_url = branch.bzrdir.root_transport.abspath('') + '/'
582
# if the api for create_checkout changes to return different checkout types
583
# then this file read will fail.
584
self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
585
self.assertEqual(reference_url,
586
_mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
589
class TestHooks(tests.TestCaseWithTransport):
274
591
def test_constructor(self):
275
592
"""Check that creating a BranchHooks instance has the right defaults."""
276
hooks = bzrlib.branch.BranchHooks()
593
hooks = _mod_branch.BranchHooks()
277
594
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
278
595
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
279
596
self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
597
self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
280
598
self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
281
self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
599
self.assertTrue("post_uncommit" in hooks,
600
"post_uncommit not in %s" % hooks)
601
self.assertTrue("post_change_branch_tip" in hooks,
602
"post_change_branch_tip not in %s" % hooks)
603
self.assertTrue("post_branch_init" in hooks,
604
"post_branch_init not in %s" % hooks)
605
self.assertTrue("post_switch" in hooks,
606
"post_switch not in %s" % hooks)
283
608
def test_installed_hooks_are_BranchHooks(self):
284
609
"""The installed hooks object should be a BranchHooks."""
285
610
# the installed hooks are saved in self._preserved_hooks.
286
self.assertIsInstance(self._preserved_hooks, bzrlib.branch.BranchHooks)
288
def test_install_hook_raises_unknown_hook(self):
289
"""install_hook should raise UnknownHook if a hook is unknown."""
290
hooks = bzrlib.branch.BranchHooks()
291
self.assertRaises(UnknownHook, hooks.install_hook, 'silly', None)
293
def test_install_hook_appends_known_hook(self):
294
"""install_hook should append the callable for known hooks."""
295
hooks = bzrlib.branch.BranchHooks()
296
hooks.install_hook('set_rh', None)
297
self.assertEqual(hooks['set_rh'], [None])
611
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
612
_mod_branch.BranchHooks)
614
def test_post_branch_init_hook(self):
616
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
618
self.assertLength(0, calls)
619
branch = self.make_branch('a')
620
self.assertLength(1, calls)
622
self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
623
self.assertTrue(hasattr(params, 'bzrdir'))
624
self.assertTrue(hasattr(params, 'branch'))
626
def test_post_branch_init_hook_repr(self):
628
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
629
lambda params: param_reprs.append(repr(params)), None)
630
branch = self.make_branch('a')
631
self.assertLength(1, param_reprs)
632
param_repr = param_reprs[0]
633
self.assertStartsWith(param_repr, '<BranchInitHookParams of ')
635
def test_post_switch_hook(self):
636
from bzrlib import switch
638
_mod_branch.Branch.hooks.install_named_hook('post_switch',
640
tree = self.make_branch_and_tree('branch-1')
641
self.build_tree(['branch-1/file-1'])
644
to_branch = tree.bzrdir.sprout('branch-2').open_branch()
645
self.build_tree(['branch-1/file-2'])
647
tree.remove('file-1')
649
checkout = tree.branch.create_checkout('checkout')
650
self.assertLength(0, calls)
651
switch.switch(checkout.bzrdir, to_branch)
652
self.assertLength(1, calls)
654
self.assertIsInstance(params, _mod_branch.SwitchHookParams)
655
self.assertTrue(hasattr(params, 'to_branch'))
656
self.assertTrue(hasattr(params, 'revision_id'))
659
class TestBranchOptions(tests.TestCaseWithTransport):
662
super(TestBranchOptions, self).setUp()
663
self.branch = self.make_branch('.')
664
self.config_stack = self.branch.get_config_stack()
666
def check_append_revisions_only(self, expected_value, value=None):
667
"""Set append_revisions_only in config and check its interpretation."""
668
if value is not None:
669
self.config_stack.set('append_revisions_only', value)
670
self.assertEqual(expected_value,
671
self.branch.get_append_revisions_only())
673
def test_valid_append_revisions_only(self):
674
self.assertEquals(None,
675
self.config_stack.get('append_revisions_only'))
676
self.check_append_revisions_only(None)
677
self.check_append_revisions_only(False, 'False')
678
self.check_append_revisions_only(True, 'True')
679
# The following values will cause compatibility problems on projects
680
# using older bzr versions (<2.2) but are accepted
681
self.check_append_revisions_only(False, 'false')
682
self.check_append_revisions_only(True, 'true')
684
def test_invalid_append_revisions_only(self):
685
"""Ensure warning is noted on invalid settings"""
688
self.warnings.append(args[0] % args[1:])
689
self.overrideAttr(trace, 'warning', warning)
690
self.check_append_revisions_only(None, 'not-a-bool')
691
self.assertLength(1, self.warnings)
693
'Value "not-a-bool" is not valid for "append_revisions_only"',
697
class TestPullResult(tests.TestCase):
699
def test_pull_result_to_int(self):
700
# to support old code, the pull result can be used as an int
701
r = _mod_branch.PullResult()
704
# this usage of results is not recommended for new code (because it
705
# doesn't describe very well what happened), but for api stability
706
# it's still supported
707
self.assertEqual(self.applyDeprecated(
708
symbol_versioning.deprecated_in((2, 3, 0)),
712
def test_report_changed(self):
713
r = _mod_branch.PullResult()
714
r.old_revid = "old-revid"
716
r.new_revid = "new-revid"
720
self.assertEqual("Now on revision 20.\n", f.getvalue())
721
self.assertEqual("Now on revision 20.\n", f.getvalue())
723
def test_report_unchanged(self):
724
r = _mod_branch.PullResult()
725
r.old_revid = "same-revid"
726
r.new_revid = "same-revid"
729
self.assertEqual("No revisions or tags to pull.\n", f.getvalue())