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,
33
from bzrlib.branch import (
37
BranchReferenceFormat,
42
from bzrlib.bzrdir import (BzrDirMetaFormat1, BzrDirMeta1,
44
from bzrlib.errors import (NotBranchError,
47
UnsupportedFormatError,
50
from bzrlib.tests import TestCase, TestCaseWithTransport
51
from bzrlib.transport import get_transport
53
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())
55
54
def test_get_set_default_format(self):
56
old_format = BranchFormat.get_default_format()
58
self.assertTrue(isinstance(old_format, BzrBranchFormat5))
59
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())
61
59
# the default branch format is used by the meta dir format
62
60
# which is not the default bzrdir format at this point
63
dir = BzrDirMetaFormat1().initialize('memory:///')
61
dir = bzrdir.BzrDirMetaFormat1().initialize('memory:///')
64
62
result = dir.create_branch()
65
63
self.assertEqual(result, 'A branch')
67
BranchFormat.set_default_format(old_format)
68
self.assertEqual(old_format, BranchFormat.get_default_format())
71
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):
72
71
"""Tests specific to branch format 5"""
74
73
def test_branch_format_5_uses_lockdir(self):
75
74
url = self.get_url()
76
bzrdir = BzrDirMetaFormat1().initialize(url)
77
bzrdir.create_repository()
78
branch = bzrdir.create_branch()
75
bdir = bzrdir.BzrDirMetaFormat1().initialize(url)
76
bdir.create_repository()
77
branch = _mod_branch.BzrBranchFormat5().initialize(bdir)
79
78
t = self.get_transport()
80
79
self.log("branch instance is %r" % branch)
81
self.assert_(isinstance(branch, BzrBranch5))
80
self.assert_(isinstance(branch, _mod_branch.BzrBranch5))
82
81
self.assertIsDirectory('.', t)
83
82
self.assertIsDirectory('.bzr/branch', t)
84
83
self.assertIsDirectory('.bzr/branch/lock', t)
85
84
branch.lock_write()
87
self.assertIsDirectory('.bzr/branch/lock/held', t)
85
self.addCleanup(branch.unlock)
86
self.assertIsDirectory('.bzr/branch/lock/held', t)
91
88
def test_set_push_location(self):
92
from bzrlib.config import (locations_config_filename,
93
ensure_config_dir_exists)
94
ensure_config_dir_exists()
95
fn = locations_config_filename()
89
conf = config.LocationConfig.from_string('# comment\n', '.', save=True)
96
91
branch = self.make_branch('.', format='knit')
97
92
branch.set_push_location('foo')
98
93
local_path = urlutils.local_path_from_url(branch.base[:-1])
99
self.assertFileEqual("[%s]\n"
94
self.assertFileEqual("# comment\n"
100
96
"push_location = foo\n"
101
"push_location:policy = norecurse" % local_path,
97
"push_location:policy = norecurse\n" % local_path,
98
config.locations_config_filename())
104
100
# TODO RBC 20051029 test getting a push location from a branch in a
105
101
# recursive section - that is, it appends the branch name.
108
class SampleBranchFormat(BranchFormat):
104
class SampleBranchFormat(_mod_branch.BranchFormatMetadir):
109
105
"""A sample format
111
this format is initializable, unsupported to aid in testing the
107
this format is initializable, unsupported to aid in testing the
112
108
open and open_downlevel routines.
115
def get_format_string(self):
112
def get_format_string(cls):
116
113
"""See BzrBranchFormat.get_format_string()."""
117
114
return "Sample branch format."
119
def initialize(self, a_bzrdir):
116
def initialize(self, a_bzrdir, name=None, repository=None,
117
append_revisions_only=None):
120
118
"""Format 4 branches cannot be created."""
121
t = a_bzrdir.get_branch_transport(self)
119
t = a_bzrdir.get_branch_transport(self, name=name)
122
120
t.put_bytes('format', self.get_format_string())
123
121
return 'A branch'
125
123
def is_supported(self):
128
def open(self, transport, _found=False):
126
def open(self, transport, name=None, _found=False, ignore_fallbacks=False,
127
possible_transports=None):
129
128
return "opened branch."
132
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):
133
174
"""Tests for the BzrBranchFormat facility."""
135
176
def test_find_format(self):
136
177
# is the right format object found for a branch?
137
178
# create a branch with a few known format objects.
138
# this is not quite the same as
179
# this is not quite the same as
139
180
self.build_tree(["foo/", "bar/"])
140
181
def check_format(format, url):
141
182
dir = format._matchingbzrdir.initialize(url)
142
183
dir.create_repository()
143
184
format.initialize(dir)
144
found_format = BranchFormat.find_format(dir)
145
self.failUnless(isinstance(found_format, format.__class__))
146
check_format(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.")
148
207
def test_find_format_not_branch(self):
149
208
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
150
self.assertRaises(NotBranchError,
151
BranchFormat.find_format,
209
self.assertRaises(errors.NotBranchError,
210
_mod_branch.BranchFormatMetadir.find_format,
154
213
def test_find_format_unknown_format(self):
155
214
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
156
215
SampleBranchFormat().initialize(dir)
157
self.assertRaises(UnknownFormatError,
158
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, {})
161
230
def test_register_unregister_format(self):
231
# Test the deprecated format registration functions
162
232
format = SampleBranchFormat()
163
233
# make a control dir
164
234
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
166
236
format.initialize(dir)
167
237
# register a format for it.
168
BranchFormat.register_format(format)
238
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
239
_mod_branch.BranchFormat.register_format, format)
169
240
# which branch.Open will refuse (not supported)
170
self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
241
self.assertRaises(errors.UnsupportedFormatError,
242
_mod_branch.Branch.open, self.get_url())
171
243
self.make_branch_and_tree('foo')
172
244
# but open_downlevel will work
173
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))
174
248
# unregister the format
175
BranchFormat.unregister_format(format)
249
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
250
_mod_branch.BranchFormat.unregister_format, format)
176
251
self.make_branch_and_tree('bar')
178
def test_checkout_format(self):
179
branch = self.make_repository('repository', shared=True)
180
branch = self.make_branch('repository/branch',
182
tree = branch.create_checkout('checkout')
183
self.assertIs(tree.branch.__class__, _mod_branch.BzrBranch5)
186
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)
188
336
def test_creation(self):
189
format = BzrDirMetaFormat1()
337
format = bzrdir.BzrDirMetaFormat1()
190
338
format.set_branch_format(_mod_branch.BzrBranchFormat6())
191
339
branch = self.make_branch('a', format=format)
192
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
193
branch = self.make_branch('b', format='dirstate-with-subtree')
194
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())
195
343
branch = _mod_branch.Branch.open('a')
196
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
344
self.assertIsInstance(branch, self.get_class())
198
346
def test_layout(self):
199
branch = self.make_branch('a', format='dirstate-with-subtree')
200
self.failUnlessExists('a/.bzr/branch/last-revision')
201
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')
203
352
def test_config(self):
204
353
"""Ensure that all configuration data is stored in the branch"""
205
branch = self.make_branch('a', format='dirstate-with-subtree')
206
branch.set_parent('http://bazaar-vcs.org')
207
self.failIfExists('a/.bzr/branch/parent')
208
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
209
branch.set_push_location('sftp://bazaar-vcs.org')
210
config = branch.get_config()._get_branch_data_config()
211
self.assertEqual('sftp://bazaar-vcs.org',
212
config.get_user_option('push_location'))
213
branch.set_bound_location('ftp://bazaar-vcs.org')
214
self.failIfExists('a/.bzr/branch/bound')
215
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
config = branch.get_config_stack()
360
self.assertEqual('sftp://example.com', config.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())
217
365
def test_set_revision_history(self):
218
tree = self.make_branch_and_memory_tree('.',
219
format='dirstate-with-subtree')
223
tree.commit('foo', rev_id='foo')
224
tree.commit('bar', rev_id='bar')
225
tree.branch.set_revision_history(['foo', 'bar'])
226
tree.branch.set_revision_history(['foo'])
227
self.assertRaises(errors.NotLefthandHistory,
228
tree.branch.set_revision_history, ['bar'])
232
def test_append_revision(self):
233
tree = self.make_branch_and_tree('branch1',
234
format='dirstate-with-subtree')
237
tree.commit('foo', rev_id='foo')
238
tree.commit('bar', rev_id='bar')
239
tree.commit('baz', rev_id='baz')
240
tree.set_last_revision('bar')
241
tree.branch.set_last_revision_info(2, 'bar')
242
tree.commit('qux', rev_id='qux')
243
tree.add_parent_tree_id('baz')
244
tree.commit('qux', rev_id='quxx')
245
tree.branch.set_last_revision_info(0, 'null:')
246
self.assertRaises(errors.NotLeftParentDescendant,
247
tree.branch.append_revision, 'bar')
248
tree.branch.append_revision('foo')
249
self.assertRaises(errors.NotLeftParentDescendant,
250
tree.branch.append_revision, 'baz')
251
tree.branch.append_revision('bar')
252
tree.branch.append_revision('baz')
253
self.assertRaises(errors.NotLeftParentDescendant,
254
tree.branch.append_revision, 'quxx')
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'])
258
382
def do_checkout_test(self, lightweight=False):
259
tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
383
tree = self.make_branch_and_tree('source',
384
format=self.get_format_name_subtree())
260
385
subtree = self.make_branch_and_tree('source/subtree',
261
format='dirstate-with-subtree')
386
format=self.get_format_name_subtree())
262
387
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
263
format='dirstate-with-subtree')
388
format=self.get_format_name_subtree())
264
389
self.build_tree(['source/subtree/file',
265
390
'source/subtree/subsubtree/file'])
266
391
subsubtree.add('file')
271
396
subtree.commit('a subtree file')
272
397
subsubtree.commit('a subsubtree file')
273
398
tree.branch.create_checkout('target', lightweight=lightweight)
274
self.failUnlessExists('target')
275
self.failUnlessExists('target/subtree')
276
self.failUnlessExists('target/subtree/file')
277
self.failUnlessExists('target/subtree/subsubtree/file')
399
self.assertPathExists('target')
400
self.assertPathExists('target/subtree')
401
self.assertPathExists('target/subtree/file')
402
self.assertPathExists('target/subtree/subsubtree/file')
278
403
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
280
405
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
282
407
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
285
409
def test_checkout_with_references(self):
286
410
self.do_checkout_test()
288
412
def test_light_checkout_with_references(self):
289
413
self.do_checkout_test(lightweight=True)
291
class TestBranchReference(TestCaseWithTransport):
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):
292
560
"""Tests for the branch reference facility."""
294
562
def test_create_open_reference(self):
295
563
bzrdirformat = bzrdir.BzrDirMetaFormat1()
296
t = get_transport(self.get_url('.'))
564
t = self.get_transport()
298
566
dir = bzrdirformat.initialize(self.get_url('repo'))
299
567
dir.create_repository()
300
568
target_branch = dir.create_branch()
301
569
t.mkdir('branch')
302
570
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
303
made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
571
made_branch = _mod_branch.BranchReferenceFormat().initialize(
572
branch_dir, target_branch=target_branch)
304
573
self.assertEqual(made_branch.base, target_branch.base)
305
574
opened_branch = branch_dir.open_branch()
306
575
self.assertEqual(opened_branch.base, target_branch.base)
309
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):
311
591
def test_constructor(self):
312
592
"""Check that creating a BranchHooks instance has the right defaults."""
313
hooks = BranchHooks()
593
hooks = _mod_branch.BranchHooks()
314
594
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
315
595
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
316
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)
317
598
self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
318
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)
320
608
def test_installed_hooks_are_BranchHooks(self):
321
609
"""The installed hooks object should be a BranchHooks."""
322
610
# the installed hooks are saved in self._preserved_hooks.
323
self.assertIsInstance(self._preserved_hooks, BranchHooks)
325
def test_install_hook_raises_unknown_hook(self):
326
"""install_hook should raise UnknownHook if a hook is unknown."""
327
hooks = BranchHooks()
328
self.assertRaises(UnknownHook, hooks.install_hook, 'silly', None)
330
def test_install_hook_appends_known_hook(self):
331
"""install_hook should append the callable for known hooks."""
332
hooks = BranchHooks()
333
hooks.install_hook('set_rh', None)
334
self.assertEqual(hooks['set_rh'], [None])
337
class TestPullResult(TestCase):
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):
339
699
def test_pull_result_to_int(self):
340
700
# to support old code, the pull result can be used as an int
701
r = _mod_branch.PullResult()
344
704
# this usage of results is not recommended for new code (because it
345
705
# doesn't describe very well what happened), but for api stability
346
706
# it's still supported
347
a = "%d revisions pulled" % r
348
self.assertEqual(a, "10 revisions pulled")
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())