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.BranchFormat.get_default_format(),
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.BranchFormat.get_default_format(),
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.BranchFormat.get_default_format()
57
_mod_branch.BranchFormat.set_default_format(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.BranchFormat.set_default_format(old_format)
66
self.assertEqual(old_format,
67
_mod_branch.BranchFormat.get_default_format())
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 = bdir.create_branch()
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
89
from bzrlib.config import (locations_config_filename,
87
90
ensure_config_dir_exists)
88
91
ensure_config_dir_exists()
89
92
fn = locations_config_filename()
93
# write correct newlines to locations.conf
94
# by default ConfigObj uses native line-endings for new files
95
# but uses already existing line-endings if file is not empty
98
f.write('# comment\n')
90
102
branch = self.make_branch('.', format='knit')
91
103
branch.set_push_location('foo')
92
104
local_path = urlutils.local_path_from_url(branch.base[:-1])
93
self.assertFileEqual("[%s]\n"
105
self.assertFileEqual("# comment\n"
94
107
"push_location = foo\n"
95
"push_location:policy = norecurse" % local_path,
108
"push_location:policy = norecurse\n" % local_path,
98
111
# TODO RBC 20051029 test getting a push location from a branch in a
99
112
# recursive section - that is, it appends the branch name.
102
class SampleBranchFormat(bzrlib.branch.BranchFormat):
115
class SampleBranchFormat(_mod_branch.BranchFormat):
103
116
"""A sample format
105
this format is initializable, unsupported to aid in testing the
118
this format is initializable, unsupported to aid in testing the
106
119
open and open_downlevel routines.
110
123
"""See BzrBranchFormat.get_format_string()."""
111
124
return "Sample branch format."
113
def initialize(self, a_bzrdir):
126
def initialize(self, a_bzrdir, name=None):
114
127
"""Format 4 branches cannot be created."""
115
t = a_bzrdir.get_branch_transport(self)
128
t = a_bzrdir.get_branch_transport(self, name=name)
116
129
t.put_bytes('format', self.get_format_string())
117
130
return 'A branch'
119
132
def is_supported(self):
122
def open(self, transport, _found=False):
135
def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
123
136
return "opened branch."
126
class TestBzrBranchFormat(TestCaseWithTransport):
139
# Demonstrating how lazy loading is often implemented:
140
# A constant string is created.
141
SampleSupportedBranchFormatString = "Sample supported branch format."
143
# And the format class can then reference the constant to avoid skew.
144
class SampleSupportedBranchFormat(_mod_branch.BranchFormat):
145
"""A sample supported format."""
147
def get_format_string(self):
148
"""See BzrBranchFormat.get_format_string()."""
149
return SampleSupportedBranchFormatString
151
def initialize(self, a_bzrdir, name=None):
152
t = a_bzrdir.get_branch_transport(self, name=name)
153
t.put_bytes('format', self.get_format_string())
156
def open(self, transport, name=None, _found=False, ignore_fallbacks=False):
157
return "opened supported branch."
160
class TestBzrBranchFormat(tests.TestCaseWithTransport):
127
161
"""Tests for the BzrBranchFormat facility."""
129
163
def test_find_format(self):
130
164
# is the right format object found for a branch?
131
165
# create a branch with a few known format objects.
132
# this is not quite the same as
166
# this is not quite the same as
133
167
self.build_tree(["foo/", "bar/"])
134
168
def check_format(format, url):
135
169
dir = format._matchingbzrdir.initialize(url)
136
170
dir.create_repository()
137
171
format.initialize(dir)
138
found_format = bzrlib.branch.BranchFormat.find_format(dir)
172
found_format = _mod_branch.BranchFormat.find_format(dir)
139
173
self.failUnless(isinstance(found_format, format.__class__))
140
check_format(bzrlib.branch.BzrBranchFormat5(), "bar")
174
check_format(_mod_branch.BzrBranchFormat5(), "bar")
176
def test_find_format_factory(self):
177
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
178
SampleSupportedBranchFormat().initialize(dir)
179
factory = _mod_branch.MetaDirBranchFormatFactory(
180
SampleSupportedBranchFormatString,
181
"bzrlib.tests.test_branch", "SampleSupportedBranchFormat")
182
_mod_branch.BranchFormat.register_format(factory)
183
self.addCleanup(_mod_branch.BranchFormat.unregister_format, factory)
184
b = _mod_branch.Branch.open(self.get_url())
185
self.assertEqual(b, "opened supported branch.")
142
187
def test_find_format_not_branch(self):
143
188
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
144
self.assertRaises(NotBranchError,
145
bzrlib.branch.BranchFormat.find_format,
189
self.assertRaises(errors.NotBranchError,
190
_mod_branch.BranchFormat.find_format,
148
193
def test_find_format_unknown_format(self):
149
194
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
150
195
SampleBranchFormat().initialize(dir)
151
self.assertRaises(UnknownFormatError,
152
bzrlib.branch.BranchFormat.find_format,
196
self.assertRaises(errors.UnknownFormatError,
197
_mod_branch.BranchFormat.find_format,
155
200
def test_register_unregister_format(self):
160
205
format.initialize(dir)
161
206
# register a format for it.
162
bzrlib.branch.BranchFormat.register_format(format)
207
_mod_branch.BranchFormat.register_format(format)
163
208
# which branch.Open will refuse (not supported)
164
self.assertRaises(UnsupportedFormatError, bzrlib.branch.Branch.open, self.get_url())
209
self.assertRaises(errors.UnsupportedFormatError,
210
_mod_branch.Branch.open, self.get_url())
165
211
self.make_branch_and_tree('foo')
166
212
# but open_downlevel will work
167
self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
215
bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
168
216
# unregister the format
169
bzrlib.branch.BranchFormat.unregister_format(format)
217
_mod_branch.BranchFormat.unregister_format(format)
170
218
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):
221
#Used by TestMetaDirBranchFormatFactory
222
FakeLazyFormat = None
225
class TestMetaDirBranchFormatFactory(tests.TestCase):
227
def test_get_format_string_does_not_load(self):
228
"""Formats have a static format string."""
229
factory = _mod_branch.MetaDirBranchFormatFactory("yo", None, None)
230
self.assertEqual("yo", factory.get_format_string())
232
def test_call_loads(self):
233
# __call__ is used by the network_format_registry interface to get a
235
global FakeLazyFormat
237
factory = _mod_branch.MetaDirBranchFormatFactory(None,
238
"bzrlib.tests.test_branch", "FakeLazyFormat")
239
self.assertRaises(AttributeError, factory)
241
def test_call_returns_call_of_referenced_object(self):
242
global FakeLazyFormat
243
FakeLazyFormat = lambda:'called'
244
factory = _mod_branch.MetaDirBranchFormatFactory(None,
245
"bzrlib.tests.test_branch", "FakeLazyFormat")
246
self.assertEqual('called', factory())
249
class TestBranch67(object):
250
"""Common tests for both branch 6 and 7 which are mostly the same."""
252
def get_format_name(self):
253
raise NotImplementedError(self.get_format_name)
255
def get_format_name_subtree(self):
256
raise NotImplementedError(self.get_format_name)
259
raise NotImplementedError(self.get_class)
182
261
def test_creation(self):
183
format = BzrDirMetaFormat1()
262
format = bzrdir.BzrDirMetaFormat1()
184
263
format.set_branch_format(_mod_branch.BzrBranchFormat6())
185
264
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)
265
self.assertIsInstance(branch, self.get_class())
266
branch = self.make_branch('b', format=self.get_format_name())
267
self.assertIsInstance(branch, self.get_class())
189
268
branch = _mod_branch.Branch.open('a')
190
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
269
self.assertIsInstance(branch, self.get_class())
192
271
def test_layout(self):
193
branch = self.make_branch('a', format='experimental-branch6')
272
branch = self.make_branch('a', format=self.get_format_name())
194
273
self.failUnlessExists('a/.bzr/branch/last-revision')
195
274
self.failIfExists('a/.bzr/branch/revision-history')
275
self.failIfExists('a/.bzr/branch/references')
197
277
def test_config(self):
198
278
"""Ensure that all configuration data is stored in the branch"""
199
branch = self.make_branch('a', format='experimental-branch6')
279
branch = self.make_branch('a', format=self.get_format_name())
200
280
branch.set_parent('http://bazaar-vcs.org')
201
281
self.failIfExists('a/.bzr/branch/parent')
202
282
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
209
289
self.assertEqual('ftp://bazaar-vcs.org', branch.get_bound_location())
211
291
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):
292
builder = self.make_branch_builder('.', format=self.get_format_name())
293
builder.build_snapshot('foo', None,
294
[('add', ('', None, 'directory', None))],
296
builder.build_snapshot('bar', None, [], message='bar')
297
branch = builder.get_branch()
299
self.addCleanup(branch.unlock)
300
branch.set_revision_history(['foo', 'bar'])
301
branch.set_revision_history(['foo'])
302
self.assertRaises(errors.NotLefthandHistory,
303
branch.set_revision_history, ['bar'])
305
def do_checkout_test(self, lightweight=False):
306
tree = self.make_branch_and_tree('source',
307
format=self.get_format_name_subtree())
308
subtree = self.make_branch_and_tree('source/subtree',
309
format=self.get_format_name_subtree())
310
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
311
format=self.get_format_name_subtree())
312
self.build_tree(['source/subtree/file',
313
'source/subtree/subsubtree/file'])
314
subsubtree.add('file')
316
subtree.add_reference(subsubtree)
317
tree.add_reference(subtree)
318
tree.commit('a revision')
319
subtree.commit('a subtree file')
320
subsubtree.commit('a subsubtree file')
321
tree.branch.create_checkout('target', lightweight=lightweight)
322
self.failUnlessExists('target')
323
self.failUnlessExists('target/subtree')
324
self.failUnlessExists('target/subtree/file')
325
self.failUnlessExists('target/subtree/subsubtree/file')
326
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
328
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
330
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
332
def test_checkout_with_references(self):
333
self.do_checkout_test()
335
def test_light_checkout_with_references(self):
336
self.do_checkout_test(lightweight=True)
338
def test_set_push(self):
339
branch = self.make_branch('source', format=self.get_format_name())
340
branch.get_config().set_user_option('push_location', 'old',
341
store=config.STORE_LOCATION)
344
warnings.append(args[0] % args[1:])
345
_warning = trace.warning
346
trace.warning = warning
348
branch.set_push_location('new')
350
trace.warning = _warning
351
self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
355
class TestBranch6(TestBranch67, tests.TestCaseWithTransport):
358
return _mod_branch.BzrBranch6
360
def get_format_name(self):
361
return "dirstate-tags"
363
def get_format_name_subtree(self):
364
return "dirstate-with-subtree"
366
def test_set_stacked_on_url_errors(self):
367
branch = self.make_branch('a', format=self.get_format_name())
368
self.assertRaises(errors.UnstackableBranchFormat,
369
branch.set_stacked_on_url, None)
371
def test_default_stacked_location(self):
372
branch = self.make_branch('a', format=self.get_format_name())
373
self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on_url)
376
class TestBranch7(TestBranch67, tests.TestCaseWithTransport):
379
return _mod_branch.BzrBranch7
381
def get_format_name(self):
384
def get_format_name_subtree(self):
385
return "development-subtree"
387
def test_set_stacked_on_url_unstackable_repo(self):
388
repo = self.make_repository('a', format='dirstate-tags')
389
control = repo.bzrdir
390
branch = _mod_branch.BzrBranchFormat7().initialize(control)
391
target = self.make_branch('b')
392
self.assertRaises(errors.UnstackableRepositoryFormat,
393
branch.set_stacked_on_url, target.base)
395
def test_clone_stacked_on_unstackable_repo(self):
396
repo = self.make_repository('a', format='dirstate-tags')
397
control = repo.bzrdir
398
branch = _mod_branch.BzrBranchFormat7().initialize(control)
399
# Calling clone should not raise UnstackableRepositoryFormat.
400
cloned_bzrdir = control.clone('cloned')
402
def _test_default_stacked_location(self):
403
branch = self.make_branch('a', format=self.get_format_name())
404
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
406
def test_stack_and_unstack(self):
407
branch = self.make_branch('a', format=self.get_format_name())
408
target = self.make_branch_and_tree('b', format=self.get_format_name())
409
branch.set_stacked_on_url(target.branch.base)
410
self.assertEqual(target.branch.base, branch.get_stacked_on_url())
411
revid = target.commit('foo')
412
self.assertTrue(branch.repository.has_revision(revid))
413
branch.set_stacked_on_url(None)
414
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
415
self.assertFalse(branch.repository.has_revision(revid))
417
def test_open_opens_stacked_reference(self):
418
branch = self.make_branch('a', format=self.get_format_name())
419
target = self.make_branch_and_tree('b', format=self.get_format_name())
420
branch.set_stacked_on_url(target.branch.base)
421
branch = branch.bzrdir.open_branch()
422
revid = target.commit('foo')
423
self.assertTrue(branch.repository.has_revision(revid))
426
class BzrBranch8(tests.TestCaseWithTransport):
428
def make_branch(self, location, format=None):
430
format = bzrdir.format_registry.make_bzrdir('1.9')
431
format.set_branch_format(_mod_branch.BzrBranchFormat8())
432
return tests.TestCaseWithTransport.make_branch(
433
self, location, format=format)
435
def create_branch_with_reference(self):
436
branch = self.make_branch('branch')
437
branch._set_all_reference_info({'file-id': ('path', 'location')})
441
def instrument_branch(branch, gets):
442
old_get = branch._transport.get
443
def get(*args, **kwargs):
444
gets.append((args, kwargs))
445
return old_get(*args, **kwargs)
446
branch._transport.get = get
448
def test_reference_info_caching_read_locked(self):
450
branch = self.create_branch_with_reference()
452
self.addCleanup(branch.unlock)
453
self.instrument_branch(branch, gets)
454
branch.get_reference_info('file-id')
455
branch.get_reference_info('file-id')
456
self.assertEqual(1, len(gets))
458
def test_reference_info_caching_read_unlocked(self):
460
branch = self.create_branch_with_reference()
461
self.instrument_branch(branch, gets)
462
branch.get_reference_info('file-id')
463
branch.get_reference_info('file-id')
464
self.assertEqual(2, len(gets))
466
def test_reference_info_caching_write_locked(self):
468
branch = self.make_branch('branch')
470
self.instrument_branch(branch, gets)
471
self.addCleanup(branch.unlock)
472
branch._set_all_reference_info({'file-id': ('path2', 'location2')})
473
path, location = branch.get_reference_info('file-id')
474
self.assertEqual(0, len(gets))
475
self.assertEqual('path2', path)
476
self.assertEqual('location2', location)
478
def test_reference_info_caches_cleared(self):
479
branch = self.make_branch('branch')
481
branch.set_reference_info('file-id', 'path2', 'location2')
483
doppelganger = _mod_branch.Branch.open('branch')
484
doppelganger.set_reference_info('file-id', 'path3', 'location3')
485
self.assertEqual(('path3', 'location3'),
486
branch.get_reference_info('file-id'))
488
class TestBranchReference(tests.TestCaseWithTransport):
255
489
"""Tests for the branch reference facility."""
257
491
def test_create_open_reference(self):
258
492
bzrdirformat = bzrdir.BzrDirMetaFormat1()
259
t = get_transport(self.get_url('.'))
493
t = transport.get_transport(self.get_url('.'))
261
495
dir = bzrdirformat.initialize(self.get_url('repo'))
262
496
dir.create_repository()
263
497
target_branch = dir.create_branch()
264
498
t.mkdir('branch')
265
499
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
266
made_branch = bzrlib.branch.BranchReferenceFormat().initialize(branch_dir, target_branch)
500
made_branch = _mod_branch.BranchReferenceFormat().initialize(
501
branch_dir, target_branch=target_branch)
267
502
self.assertEqual(made_branch.base, target_branch.base)
268
503
opened_branch = branch_dir.open_branch()
269
504
self.assertEqual(opened_branch.base, target_branch.base)
272
class TestHooks(TestCase):
506
def test_get_reference(self):
507
"""For a BranchReference, get_reference should reutrn the location."""
508
branch = self.make_branch('target')
509
checkout = branch.create_checkout('checkout', lightweight=True)
510
reference_url = branch.bzrdir.root_transport.abspath('') + '/'
511
# if the api for create_checkout changes to return different checkout types
512
# then this file read will fail.
513
self.assertFileEqual(reference_url, 'checkout/.bzr/branch/location')
514
self.assertEqual(reference_url,
515
_mod_branch.BranchReferenceFormat().get_reference(checkout.bzrdir))
518
class TestHooks(tests.TestCaseWithTransport):
274
520
def test_constructor(self):
275
521
"""Check that creating a BranchHooks instance has the right defaults."""
276
hooks = bzrlib.branch.BranchHooks()
522
hooks = _mod_branch.BranchHooks()
277
523
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
278
524
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
279
525
self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
526
self.assertTrue("pre_commit" in hooks, "pre_commit not in %s" % hooks)
280
527
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)
528
self.assertTrue("post_uncommit" in hooks,
529
"post_uncommit not in %s" % hooks)
530
self.assertTrue("post_change_branch_tip" in hooks,
531
"post_change_branch_tip not in %s" % hooks)
532
self.assertTrue("post_branch_init" in hooks,
533
"post_branch_init not in %s" % hooks)
534
self.assertTrue("post_switch" in hooks,
535
"post_switch not in %s" % hooks)
283
537
def test_installed_hooks_are_BranchHooks(self):
284
538
"""The installed hooks object should be a BranchHooks."""
285
539
# 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])
540
self.assertIsInstance(self._preserved_hooks[_mod_branch.Branch][1],
541
_mod_branch.BranchHooks)
543
def test_post_branch_init_hook(self):
545
_mod_branch.Branch.hooks.install_named_hook('post_branch_init',
547
self.assertLength(0, calls)
548
branch = self.make_branch('a')
549
self.assertLength(1, calls)
551
self.assertIsInstance(params, _mod_branch.BranchInitHookParams)
552
self.assertTrue(hasattr(params, 'bzrdir'))
553
self.assertTrue(hasattr(params, 'branch'))
555
def test_post_switch_hook(self):
556
from bzrlib import switch
558
_mod_branch.Branch.hooks.install_named_hook('post_switch',
560
tree = self.make_branch_and_tree('branch-1')
561
self.build_tree(['branch-1/file-1'])
564
to_branch = tree.bzrdir.sprout('branch-2').open_branch()
565
self.build_tree(['branch-1/file-2'])
567
tree.remove('file-1')
569
checkout = tree.branch.create_checkout('checkout')
570
self.assertLength(0, calls)
571
switch.switch(checkout.bzrdir, to_branch)
572
self.assertLength(1, calls)
574
self.assertIsInstance(params, _mod_branch.SwitchHookParams)
575
self.assertTrue(hasattr(params, 'to_branch'))
576
self.assertTrue(hasattr(params, 'revision_id'))
579
class TestBranchOptions(tests.TestCaseWithTransport):
582
super(TestBranchOptions, self).setUp()
583
self.branch = self.make_branch('.')
584
self.config = self.branch.get_config()
586
def check_append_revisions_only(self, expected_value, value=None):
587
"""Set append_revisions_only in config and check its interpretation."""
588
if value is not None:
589
self.config.set_user_option('append_revisions_only', value)
590
self.assertEqual(expected_value,
591
self.branch._get_append_revisions_only())
593
def test_valid_append_revisions_only(self):
594
self.assertEquals(None,
595
self.config.get_user_option('append_revisions_only'))
596
self.check_append_revisions_only(None)
597
self.check_append_revisions_only(False, 'False')
598
self.check_append_revisions_only(True, 'True')
599
# The following values will cause compatibility problems on projects
600
# using older bzr versions (<2.2) but are accepted
601
self.check_append_revisions_only(False, 'false')
602
self.check_append_revisions_only(True, 'true')
604
def test_invalid_append_revisions_only(self):
605
"""Ensure warning is noted on invalid settings"""
608
self.warnings.append(args[0] % args[1:])
609
self.overrideAttr(trace, 'warning', warning)
610
self.check_append_revisions_only(None, 'not-a-bool')
611
self.assertLength(1, self.warnings)
613
'Value "not-a-bool" is not a boolean for "append_revisions_only"',
617
class TestPullResult(tests.TestCase):
619
def test_pull_result_to_int(self):
620
# to support old code, the pull result can be used as an int
621
r = _mod_branch.PullResult()
624
# this usage of results is not recommended for new code (because it
625
# doesn't describe very well what happened), but for api stability
626
# it's still supported
627
a = "%d revisions pulled" % r
628
self.assertEqual(a, "10 revisions pulled")
630
def test_report_changed(self):
631
r = _mod_branch.PullResult()
632
r.old_revid = "old-revid"
634
r.new_revid = "new-revid"
638
self.assertEqual("Now on revision 20.\n", f.getvalue())
640
def test_report_unchanged(self):
641
r = _mod_branch.PullResult()
642
r.old_revid = "same-revid"
643
r.new_revid = "same-revid"
646
self.assertEqual("No revisions to pull.\n", f.getvalue())
649
class _StubLockable(object):
650
"""Helper for TestRunWithWriteLockedTarget."""
652
def __init__(self, calls, unlock_exc=None):
654
self.unlock_exc = unlock_exc
656
def lock_write(self):
657
self.calls.append('lock_write')
660
self.calls.append('unlock')
661
if self.unlock_exc is not None:
662
raise self.unlock_exc
665
class _ErrorFromCallable(Exception):
666
"""Helper for TestRunWithWriteLockedTarget."""
669
class _ErrorFromUnlock(Exception):
670
"""Helper for TestRunWithWriteLockedTarget."""
673
class TestRunWithWriteLockedTarget(tests.TestCase):
674
"""Tests for _run_with_write_locked_target."""
677
tests.TestCase.setUp(self)
680
def func_that_returns_ok(self):
681
self._calls.append('func called')
684
def func_that_raises(self):
685
self._calls.append('func called')
686
raise _ErrorFromCallable()
688
def test_success_unlocks(self):
689
lockable = _StubLockable(self._calls)
690
result = _mod_branch._run_with_write_locked_target(
691
lockable, self.func_that_returns_ok)
692
self.assertEqual('ok', result)
693
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
695
def test_exception_unlocks_and_propagates(self):
696
lockable = _StubLockable(self._calls)
697
self.assertRaises(_ErrorFromCallable,
698
_mod_branch._run_with_write_locked_target,
699
lockable, self.func_that_raises)
700
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
702
def test_callable_succeeds_but_error_during_unlock(self):
703
lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
704
self.assertRaises(_ErrorFromUnlock,
705
_mod_branch._run_with_write_locked_target,
706
lockable, self.func_that_returns_ok)
707
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)
709
def test_error_during_unlock_does_not_mask_original_error(self):
710
lockable = _StubLockable(self._calls, unlock_exc=_ErrorFromUnlock())
711
self.assertRaises(_ErrorFromCallable,
712
_mod_branch._run_with_write_locked_target,
713
lockable, self.func_that_raises)
714
self.assertEqual(['lock_write', 'func called', 'unlock'], self._calls)