50
54
from bzrlib.tests import TestCase, TestCaseWithTransport
51
55
from bzrlib.transport import get_transport
53
58
class TestDefaultFormat(TestCase):
60
def test_default_format(self):
61
# update this if you change the default branch format
62
self.assertIsInstance(BranchFormat.get_default_format(),
65
def test_default_format_is_same_as_bzrdir_default(self):
66
# XXX: it might be nice if there was only one place the default was
67
# set, but at the moment that's not true -- mbp 20070814 --
68
# https://bugs.launchpad.net/bzr/+bug/132376
69
self.assertEqual(BranchFormat.get_default_format(),
70
BzrDirFormat.get_default_format().get_branch_format())
55
72
def test_get_set_default_format(self):
73
# set the format and then set it back again
56
74
old_format = BranchFormat.get_default_format()
58
self.assertTrue(isinstance(old_format, BzrBranchFormat5))
59
75
BranchFormat.set_default_format(SampleBranchFormat())
61
77
# the default branch format is used by the meta dir format
93
109
ensure_config_dir_exists)
94
110
ensure_config_dir_exists()
95
111
fn = locations_config_filename()
112
# write correct newlines to locations.conf
113
# by default ConfigObj uses native line-endings for new files
114
# but uses already existing line-endings if file is not empty
117
f.write('# comment\n')
96
121
branch = self.make_branch('.', format='knit')
97
122
branch.set_push_location('foo')
98
123
local_path = urlutils.local_path_from_url(branch.base[:-1])
99
self.assertFileEqual("[%s]\n"
124
self.assertFileEqual("# comment\n"
100
126
"push_location = foo\n"
101
"push_location:policy = norecurse" % local_path,
127
"push_location:policy = norecurse\n" % local_path,
104
130
# TODO RBC 20051029 test getting a push location from a branch in a
176
202
self.make_branch_and_tree('bar')
179
class TestBranch6(TestCaseWithTransport):
205
class TestBranch67(object):
206
"""Common tests for both branch 6 and 7 which are mostly the same."""
208
def get_format_name(self):
209
raise NotImplementedError(self.get_format_name)
211
def get_format_name_subtree(self):
212
raise NotImplementedError(self.get_format_name)
215
raise NotImplementedError(self.get_class)
181
217
def test_creation(self):
182
218
format = BzrDirMetaFormat1()
183
219
format.set_branch_format(_mod_branch.BzrBranchFormat6())
184
220
branch = self.make_branch('a', format=format)
185
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
186
branch = self.make_branch('b', format='dirstate-tags')
187
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
221
self.assertIsInstance(branch, self.get_class())
222
branch = self.make_branch('b', format=self.get_format_name())
223
self.assertIsInstance(branch, self.get_class())
188
224
branch = _mod_branch.Branch.open('a')
189
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
225
self.assertIsInstance(branch, self.get_class())
191
227
def test_layout(self):
192
branch = self.make_branch('a', format='dirstate-tags')
228
branch = self.make_branch('a', format=self.get_format_name())
193
229
self.failUnlessExists('a/.bzr/branch/last-revision')
194
230
self.failIfExists('a/.bzr/branch/revision-history')
196
232
def test_config(self):
197
233
"""Ensure that all configuration data is stored in the branch"""
198
branch = self.make_branch('a', format='dirstate-tags')
234
branch = self.make_branch('a', format=self.get_format_name())
199
235
branch.set_parent('http://bazaar-vcs.org')
200
236
self.failIfExists('a/.bzr/branch/parent')
201
237
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
208
244
self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
210
246
def test_set_revision_history(self):
211
tree = self.make_branch_and_memory_tree('.',
212
format='dirstate-tags')
216
tree.commit('foo', rev_id='foo')
217
tree.commit('bar', rev_id='bar')
218
tree.branch.set_revision_history(['foo', 'bar'])
219
tree.branch.set_revision_history(['foo'])
220
self.assertRaises(errors.NotLefthandHistory,
221
tree.branch.set_revision_history, ['bar'])
225
def test_append_revision(self):
226
tree = self.make_branch_and_tree('branch1',
227
format='dirstate-tags')
230
tree.commit('foo', rev_id='foo')
231
tree.commit('bar', rev_id='bar')
232
tree.commit('baz', rev_id='baz')
233
tree.set_last_revision('bar')
234
tree.branch.set_last_revision_info(2, 'bar')
235
tree.commit('qux', rev_id='qux')
236
tree.add_parent_tree_id('baz')
237
tree.commit('qux', rev_id='quxx')
238
tree.branch.set_last_revision_info(0, 'null:')
239
self.assertRaises(errors.NotLeftParentDescendant,
240
tree.branch.append_revision, 'bar')
241
tree.branch.append_revision('foo')
242
self.assertRaises(errors.NotLeftParentDescendant,
243
tree.branch.append_revision, 'baz')
244
tree.branch.append_revision('bar')
245
tree.branch.append_revision('baz')
246
self.assertRaises(errors.NotLeftParentDescendant,
247
tree.branch.append_revision, 'quxx')
247
builder = self.make_branch_builder('.', format=self.get_format_name())
248
builder.build_snapshot('foo', None,
249
[('add', ('', None, 'directory', None))],
251
builder.build_snapshot('bar', None, [], message='bar')
252
branch = builder.get_branch()
254
self.addCleanup(branch.unlock)
255
branch.set_revision_history(['foo', 'bar'])
256
branch.set_revision_history(['foo'])
257
self.assertRaises(errors.NotLefthandHistory,
258
branch.set_revision_history, ['bar'])
251
260
def do_checkout_test(self, lightweight=False):
252
tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
261
tree = self.make_branch_and_tree('source',
262
format=self.get_format_name_subtree())
253
263
subtree = self.make_branch_and_tree('source/subtree',
254
format='dirstate-with-subtree')
264
format=self.get_format_name_subtree())
255
265
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
256
format='dirstate-with-subtree')
266
format=self.get_format_name_subtree())
257
267
self.build_tree(['source/subtree/file',
258
268
'source/subtree/subsubtree/file'])
259
269
subsubtree.add('file')
275
285
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
278
287
def test_checkout_with_references(self):
279
288
self.do_checkout_test()
281
290
def test_light_checkout_with_references(self):
282
291
self.do_checkout_test(lightweight=True)
293
def test_set_push(self):
294
branch = self.make_branch('source', format=self.get_format_name())
295
branch.get_config().set_user_option('push_location', 'old',
296
store=config.STORE_LOCATION)
299
warnings.append(args[0] % args[1:])
300
_warning = trace.warning
301
trace.warning = warning
303
branch.set_push_location('new')
305
trace.warning = _warning
306
self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
310
class TestBranch6(TestBranch67, TestCaseWithTransport):
313
return _mod_branch.BzrBranch6
315
def get_format_name(self):
316
return "dirstate-tags"
318
def get_format_name_subtree(self):
319
return "dirstate-with-subtree"
321
def test_set_stacked_on_url_errors(self):
322
branch = self.make_branch('a', format=self.get_format_name())
323
self.assertRaises(errors.UnstackableBranchFormat,
324
branch.set_stacked_on_url, None)
326
def test_default_stacked_location(self):
327
branch = self.make_branch('a', format=self.get_format_name())
328
self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
331
class TestBranch7(TestBranch67, TestCaseWithTransport):
334
return _mod_branch.BzrBranch7
336
def get_format_name(self):
339
def get_format_name_subtree(self):
340
return "development-subtree"
342
def test_set_stacked_on_url_unstackable_repo(self):
343
repo = self.make_repository('a', format='dirstate-tags')
344
control = repo.bzrdir
345
branch = _mod_branch.BzrBranchFormat7().initialize(control)
346
target = self.make_branch('b')
347
self.assertRaises(errors.UnstackableRepositoryFormat,
348
branch.set_stacked_on_url, target.base)
350
def test_clone_stacked_on_unstackable_repo(self):
351
repo = self.make_repository('a', format='dirstate-tags')
352
control = repo.bzrdir
353
branch = _mod_branch.BzrBranchFormat7().initialize(control)
354
# Calling clone should not raise UnstackableRepositoryFormat.
355
cloned_bzrdir = control.clone('cloned')
357
def _test_default_stacked_location(self):
358
branch = self.make_branch('a', format=self.get_format_name())
359
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
361
def test_stack_and_unstack(self):
362
branch = self.make_branch('a', format=self.get_format_name())
363
target = self.make_branch_and_tree('b', format=self.get_format_name())
364
branch.set_stacked_on_url(target.branch.base)
365
self.assertEqual(target.branch.base, branch.get_stacked_on_url())
366
revid = target.commit('foo')
367
self.assertTrue(branch.repository.has_revision(revid))
368
branch.set_stacked_on_url(None)
369
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
370
self.assertFalse(branch.repository.has_revision(revid))
372
def test_open_opens_stacked_reference(self):
373
branch = self.make_branch('a', format=self.get_format_name())
374
target = self.make_branch_and_tree('b', format=self.get_format_name())
375
branch.set_stacked_on_url(target.branch.base)
376
branch = branch.bzrdir.open_branch()
377
revid = target.commit('foo')
378
self.assertTrue(branch.repository.has_revision(revid))
284
381
class TestBranchReference(TestCaseWithTransport):
285
382
"""Tests for the branch reference facility."""
298
395
opened_branch = branch_dir.open_branch()
299
396
self.assertEqual(opened_branch.base, target_branch.base)
398
def test_get_reference(self):
399
"""For a BranchReference, get_reference should reutrn the location."""
400
branch = self.make_branch('target')
401
checkout = branch.create_checkout('checkout', lightweight=True)
402
reference_url = branch.bzrdir.root_transport.abspath('') + '/'
403
# if the api for create_checkout changes to return different checkout types
404
# then this file read will fail.
405
self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
406
self.assertEqual(reference_url,
407
_mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
302
410
class TestHooks(TestCase):
307
415
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
308
416
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
309
417
self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
418
self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
310
419
self.assertTrue("post_pull" in hooks, "post_pull not in %s" % hooks)
311
420
self.assertTrue("post_uncommit" in hooks, "post_uncommit not in %s" % hooks)
421
self.assertTrue("post_change_branch_tip" in hooks,
422
"post_change_branch_tip not in %s" % hooks)
313
424
def test_installed_hooks_are_BranchHooks(self):
314
425
"""The installed hooks object should be a BranchHooks."""
315
426
# the installed hooks are saved in self._preserved_hooks.
316
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch], BranchHooks)
318
def test_install_hook_raises_unknown_hook(self):
319
"""install_hook should raise UnknownHook if a hook is unknown."""
320
hooks = BranchHooks()
321
self.assertRaises(UnknownHook, hooks.install_hook, 'silly', None)
323
def test_install_hook_appends_known_hook(self):
324
"""install_hook should append the callable for known hooks."""
325
hooks = BranchHooks()
326
hooks.install_hook('set_rh', None)
327
self.assertEqual(hooks['set_rh'], [None])
427
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
330
431
class TestPullResult(TestCase):
339
440
# it's still supported
340
441
a = "%d revisions pulled" % r
341
442
self.assertEqual(a, "10 revisions pulled")
446
class _StubLockable(object):
447
"""Helper for TestRunWithWriteLockedTarget."""
449
def __init__(self, calls, unlock_exc=None):
451
self.unlock_exc = unlock_exc
453
def lock_write(self):
454
self.calls.append('lock_write')
457
self.calls.append('unlock')
458
if self.unlock_exc is not None:
459
raise self.unlock_exc
462
class _ErrorFromCallable(Exception):
463
"""Helper for TestRunWithWriteLockedTarget."""
466
class _ErrorFromUnlock(Exception):
467
"""Helper for TestRunWithWriteLockedTarget."""
470
class TestRunWithWriteLockedTarget(TestCase):
471
"""Tests for _run_with_write_locked_target."""
477
def func_that_returns_ok(self):
478
self._calls.append('func called')
481
def func_that_raises(self):
482
self._calls.append('func called')
483
raise _ErrorFromCallable()
485
def test_success_unlocks(self):
486
lockable = _StubLockable(self._calls)
487
result = _run_with_write_locked_target(
488
lockable, self.func_that_returns_ok)
489
self.assertEqual('ok', result)
490
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
492
def test_exception_unlocks_and_propagates(self):
493
lockable = _StubLockable(self._calls)
494
self.assertRaises(_ErrorFromCallable,
495
_run_with_write_locked_target, lockable, self.func_that_raises)
496
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
498
def test_callable_succeeds_but_error_during_unlock(self):
499
lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
500
self.assertRaises(_ErrorFromUnlock,
501
_run_with_write_locked_target, lockable, self.func_that_returns_ok)
502
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
504
def test_error_during_unlock_does_not_mask_original_error(self):
505
lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
506
self.assertRaises(_ErrorFromCallable,
507
_run_with_write_locked_target, lockable, self.func_that_raises)
508
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)