1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
17
"""Tests for the Branch facility that are not interface tests.
19
For interface tests see tests/branch_implementations/*.py.
21
For concrete class tests see this file, and for meta-branch tests
25
from StringIO import StringIO
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):
55
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())
61
# the default branch format is used by the meta dir format
62
# which is not the default bzrdir format at this point
63
dir = BzrDirMetaFormat1().initialize('memory:///')
64
result = dir.create_branch()
65
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):
72
"""Tests specific to branch format 5"""
74
def test_branch_format_5_uses_lockdir(self):
76
bzrdir = BzrDirMetaFormat1().initialize(url)
77
bzrdir.create_repository()
78
branch = bzrdir.create_branch()
79
t = self.get_transport()
80
self.log("branch instance is %r" % branch)
81
self.assert_(isinstance(branch, BzrBranch5))
82
self.assertIsDirectory('.', t)
83
self.assertIsDirectory('.bzr/branch', t)
84
self.assertIsDirectory('.bzr/branch/lock', t)
87
self.assertIsDirectory('.bzr/branch/lock/held', t)
91
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()
96
branch = self.make_branch('.', format='knit')
97
branch.set_push_location('foo')
98
local_path = urlutils.local_path_from_url(branch.base[:-1])
99
self.assertFileEqual("[%s]\n"
100
"push_location = foo\n"
101
"push_location:policy = norecurse" % local_path,
104
# TODO RBC 20051029 test getting a push location from a branch in a
105
# recursive section - that is, it appends the branch name.
108
class SampleBranchFormat(BranchFormat):
111
this format is initializable, unsupported to aid in testing the
112
open and open_downlevel routines.
115
def get_format_string(self):
116
"""See BzrBranchFormat.get_format_string()."""
117
return "Sample branch format."
119
def initialize(self, a_bzrdir):
120
"""Format 4 branches cannot be created."""
121
t = a_bzrdir.get_branch_transport(self)
122
t.put_bytes('format', self.get_format_string())
125
def is_supported(self):
128
def open(self, transport, _found=False):
129
return "opened branch."
132
class TestBzrBranchFormat(TestCaseWithTransport):
133
"""Tests for the BzrBranchFormat facility."""
135
def test_find_format(self):
136
# is the right format object found for a branch?
137
# create a branch with a few known format objects.
138
# this is not quite the same as
139
self.build_tree(["foo/", "bar/"])
140
def check_format(format, url):
141
dir = format._matchingbzrdir.initialize(url)
142
dir.create_repository()
143
format.initialize(dir)
144
found_format = BranchFormat.find_format(dir)
145
self.failUnless(isinstance(found_format, format.__class__))
146
check_format(BzrBranchFormat5(), "bar")
148
def test_find_format_not_branch(self):
149
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
150
self.assertRaises(NotBranchError,
151
BranchFormat.find_format,
154
def test_find_format_unknown_format(self):
155
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
156
SampleBranchFormat().initialize(dir)
157
self.assertRaises(UnknownFormatError,
158
BranchFormat.find_format,
161
def test_register_unregister_format(self):
162
format = SampleBranchFormat()
164
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
166
format.initialize(dir)
167
# register a format for it.
168
BranchFormat.register_format(format)
169
# which branch.Open will refuse (not supported)
170
self.assertRaises(UnsupportedFormatError, Branch.open, self.get_url())
171
self.make_branch_and_tree('foo')
172
# but open_downlevel will work
173
self.assertEqual(format.open(dir), bzrdir.BzrDir.open(self.get_url()).open_branch(unsupported=True))
174
# unregister the format
175
BranchFormat.unregister_format(format)
176
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):
188
def test_creation(self):
189
format = BzrDirMetaFormat1()
190
format.set_branch_format(_mod_branch.BzrBranchFormat6())
191
branch = self.make_branch('a', format=format)
192
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
193
branch = self.make_branch('b', format='dirstate-tags')
194
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
195
branch = _mod_branch.Branch.open('a')
196
self.assertIsInstance(branch, _mod_branch.BzrBranch6)
198
def test_layout(self):
199
branch = self.make_branch('a', format='dirstate-tags')
200
self.failUnlessExists('a/.bzr/branch/last-revision')
201
self.failIfExists('a/.bzr/branch/revision-history')
203
def test_config(self):
204
"""Ensure that all configuration data is stored in the branch"""
205
branch = self.make_branch('a', format='dirstate-tags')
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())
217
def test_set_revision_history(self):
218
tree = self.make_branch_and_memory_tree('.',
219
format='dirstate-tags')
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-tags')
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')
258
def do_checkout_test(self, lightweight=False):
259
tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
260
subtree = self.make_branch_and_tree('source/subtree',
261
format='dirstate-with-subtree')
262
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
263
format='dirstate-with-subtree')
264
self.build_tree(['source/subtree/file',
265
'source/subtree/subsubtree/file'])
266
subsubtree.add('file')
268
subtree.add_reference(subsubtree)
269
tree.add_reference(subtree)
270
tree.commit('a revision')
271
subtree.commit('a subtree file')
272
subsubtree.commit('a subsubtree file')
273
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')
278
subbranch = _mod_branch.Branch.open('target/subtree/subsubtree')
280
self.assertEndsWith(subbranch.base, 'source/subtree/subsubtree/')
282
self.assertEndsWith(subbranch.base, 'target/subtree/subsubtree/')
285
def test_checkout_with_references(self):
286
self.do_checkout_test()
288
def test_light_checkout_with_references(self):
289
self.do_checkout_test(lightweight=True)
291
class TestBranchReference(TestCaseWithTransport):
292
"""Tests for the branch reference facility."""
294
def test_create_open_reference(self):
295
bzrdirformat = bzrdir.BzrDirMetaFormat1()
296
t = get_transport(self.get_url('.'))
298
dir = bzrdirformat.initialize(self.get_url('repo'))
299
dir.create_repository()
300
target_branch = dir.create_branch()
302
branch_dir = bzrdirformat.initialize(self.get_url('branch'))
303
made_branch = BranchReferenceFormat().initialize(branch_dir, target_branch)
304
self.assertEqual(made_branch.base, target_branch.base)
305
opened_branch = branch_dir.open_branch()
306
self.assertEqual(opened_branch.base, target_branch.base)
309
class TestHooks(TestCase):
311
def test_constructor(self):
312
"""Check that creating a BranchHooks instance has the right defaults."""
313
hooks = BranchHooks()
314
self.assertTrue("set_rh" in hooks, "set_rh not in %s" % hooks)
315
self.assertTrue("post_push" in hooks, "post_push not in %s" % hooks)
316
self.assertTrue("post_commit" in hooks, "post_commit not in %s" % hooks)
317
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)
320
def test_installed_hooks_are_BranchHooks(self):
321
"""The installed hooks object should be a BranchHooks."""
322
# 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):
339
def test_pull_result_to_int(self):
340
# to support old code, the pull result can be used as an int
344
# this usage of results is not recommended for new code (because it
345
# doesn't describe very well what happened), but for api stability
346
# it's still supported
347
a = "%d revisions pulled" % r
348
self.assertEqual(a, "10 revisions pulled")