1
# Copyright (C) 2008 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 Branch.get_stacked_on_url and set_stacked_on_url."""
23
from bzrlib.revision import NULL_REVISION
24
from bzrlib.tests import TestNotApplicable, KnownFailure
25
from bzrlib.tests.branch_implementations import TestCaseWithBranch
28
class TestStacking(TestCaseWithBranch):
30
def test_get_set_stacked_on_url(self):
31
# branches must either:
32
# raise UnstackableBranchFormat or
33
# raise UnstackableRepositoryFormat or
34
# permit stacking to be done and then return the stacked location.
35
branch = self.make_branch('branch')
36
target = self.make_branch('target')
38
errors.UnstackableBranchFormat,
39
errors.UnstackableRepositoryFormat,
42
branch.set_stacked_on_url(target.base)
43
except old_format_errors:
44
# if the set failed, so must the get
45
self.assertRaises(old_format_errors, branch.get_stacked_on_url)
47
# now we have a stacked branch:
48
self.assertEqual(target.base, branch.get_stacked_on_url())
49
branch.set_stacked_on_url(None)
50
self.assertRaises(errors.NotStacked, branch.get_stacked_on_url)
52
def test_get_set_stacked_on_relative(self):
53
# Branches can be stacked on other branches using relative paths.
54
branch = self.make_branch('branch')
55
target = self.make_branch('target')
57
errors.UnstackableBranchFormat,
58
errors.UnstackableRepositoryFormat,
61
branch.set_stacked_on_url('../target')
62
except old_format_errors:
63
# if the set failed, so must the get
64
self.assertRaises(old_format_errors, branch.get_stacked_on_url)
66
self.assertEqual('../target', branch.get_stacked_on_url())
68
def assertRevisionInRepository(self, repo_path, revid):
69
"""Check that a revision is in a repository, disregarding stacking."""
70
repo = bzrdir.BzrDir.open(repo_path).open_repository()
71
self.assertTrue(repo.has_revision(revid))
73
def assertRevisionNotInRepository(self, repo_path, revid):
74
"""Check that a revision is not in a repository, disregarding stacking."""
75
repo = bzrdir.BzrDir.open(repo_path).open_repository()
76
self.assertFalse(repo.has_revision(revid))
78
def test_get_graph_stacked(self):
79
"""A stacked repository shows the graph of its parent."""
80
trunk_tree = self.make_branch_and_tree('mainline')
81
trunk_revid = trunk_tree.commit('mainline')
82
# make a new branch, and stack on the existing one. we don't use
83
# sprout(stacked=True) here because if that is buggy and copies data
84
# it would cause a false pass of this test.
85
new_branch = self.make_branch('new_branch')
87
new_branch.set_stacked_on_url(trunk_tree.branch.base)
88
except (errors.UnstackableBranchFormat,
89
errors.UnstackableRepositoryFormat), e:
90
raise TestNotApplicable(e)
91
# reading the graph from the stacked branch's repository should see
92
# data from the stacked-on branch
93
new_repo = new_branch.repository
96
self.assertEqual(new_repo.get_parent_map([trunk_revid]),
97
{trunk_revid: (NULL_REVISION, )})
101
def test_sprout_stacked(self):
103
trunk_tree = self.make_branch_and_tree('mainline')
104
trunk_revid = trunk_tree.commit('mainline')
105
# and make branch from it which is stacked
107
new_dir = trunk_tree.bzrdir.sprout('newbranch', stacked=True)
108
except (errors.UnstackableBranchFormat,
109
errors.UnstackableRepositoryFormat), e:
110
raise TestNotApplicable(e)
112
self.assertRevisionNotInRepository('newbranch', trunk_revid)
113
new_tree = new_dir.open_workingtree()
114
new_branch_revid = new_tree.commit('something local')
115
self.assertRevisionNotInRepository('mainline', new_branch_revid)
116
self.assertRevisionInRepository('newbranch', new_branch_revid)
118
def test_unstack_fetches(self):
119
"""Removing the stacked-on branch pulls across all data"""
121
trunk_tree = self.make_branch_and_tree('mainline')
122
trunk_revid = trunk_tree.commit('revision on mainline')
123
# and make branch from it which is stacked
125
new_dir = trunk_tree.bzrdir.sprout('newbranch', stacked=True)
126
except (errors.UnstackableBranchFormat,
127
errors.UnstackableRepositoryFormat), e:
128
raise TestNotApplicable(e)
130
self.assertRevisionNotInRepository('newbranch', trunk_revid)
131
# now when we unstack that should implicitly fetch, to make sure that
132
# the branch will still work
133
new_branch = new_dir.open_branch()
134
new_branch.set_stacked_on_url(None)
135
self.assertRevisionInRepository('newbranch', trunk_revid)
136
# of course it's still in the mainline
137
self.assertRevisionInRepository('mainline', trunk_revid)
138
# and now we're no longer stacked
139
self.assertRaises(errors.NotStacked,
140
new_branch.get_stacked_on_url)
142
def make_stacked_bzrdir(self, in_directory=None):
143
"""Create a stacked branch and return its bzrdir.
145
:param in_directory: If not None, create a directory of this
146
name and create the stacking and stacked-on bzrdirs in
149
if in_directory is not None:
150
self.get_transport().mkdir(in_directory)
151
prefix = in_directory + '/'
154
tree = self.make_branch_and_tree(prefix + 'stacked-on')
155
tree.commit('Added foo')
156
stacked_bzrdir = tree.branch.bzrdir.sprout(
157
prefix + 'stacked', tree.branch.last_revision(), stacked=True)
158
return stacked_bzrdir
160
def test_clone_from_stacked_branch_preserve_stacking(self):
161
# We can clone from the bzrdir of a stacked branch. If
162
# preserve_stacking is True, the cloned branch is stacked on the
163
# same branch as the original.
165
stacked_bzrdir = self.make_stacked_bzrdir()
166
except (errors.UnstackableBranchFormat,
167
errors.UnstackableRepositoryFormat), e:
168
# not a testable combination.
169
raise TestNotApplicable(e)
170
cloned_bzrdir = stacked_bzrdir.clone('cloned', preserve_stacking=True)
173
stacked_bzrdir.open_branch().get_stacked_on_url(),
174
cloned_bzrdir.open_branch().get_stacked_on_url())
175
except (errors.UnstackableBranchFormat,
176
errors.UnstackableRepositoryFormat):
179
def test_clone_from_branch_stacked_on_relative_url_preserve_stacking(self):
180
# If a branch's stacked-on url is relative, we can still clone
181
# from it with preserve_stacking True and get a branch stacked
182
# on an appropriately adjusted relative url.
184
stacked_bzrdir = self.make_stacked_bzrdir(in_directory='dir')
185
except (errors.UnstackableBranchFormat,
186
errors.UnstackableRepositoryFormat), e:
187
# not a testable combination.
188
raise TestNotApplicable(e)
189
stacked_bzrdir.open_branch().set_stacked_on_url('../stacked-on')
190
cloned_bzrdir = stacked_bzrdir.clone('cloned', preserve_stacking=True)
193
cloned_bzrdir.open_branch().get_stacked_on_url())
195
def test_clone_from_stacked_branch_no_preserve_stacking(self):
197
stacked_bzrdir = self.make_stacked_bzrdir()
198
except (errors.UnstackableBranchFormat,
199
errors.UnstackableRepositoryFormat), e:
200
# not a testable combination.
201
raise TestNotApplicable(e)
202
cloned_unstacked_bzrdir = stacked_bzrdir.clone('cloned-unstacked',
203
preserve_stacking=False)
204
unstacked_branch = cloned_unstacked_bzrdir.open_branch()
205
self.assertRaises((errors.NotStacked, errors.UnstackableBranchFormat),
206
unstacked_branch.get_stacked_on_url)
208
def test_no_op_preserve_stacking(self):
209
"""With no stacking, preserve_stacking should be a no-op."""
210
branch = self.make_branch('source')
211
cloned_bzrdir = branch.bzrdir.clone('cloned', preserve_stacking=True)
212
self.assertRaises((errors.NotStacked, errors.UnstackableBranchFormat),
213
cloned_bzrdir.open_branch().get_stacked_on_url)
215
def test_sprout_stacking_policy_handling(self):
216
"""Obey policy where possible, ignore otherwise."""
217
stack_on = self.make_branch('stack-on')
218
parent_bzrdir = self.make_bzrdir('.', format='default')
219
parent_bzrdir.get_config().set_default_stack_on('stack-on')
220
source = self.make_branch('source')
221
target = source.bzrdir.sprout('target').open_branch()
223
self.assertEqual('../stack-on', target.get_stacked_on_url())
224
except errors.UnstackableBranchFormat:
227
def test_clone_stacking_policy_handling(self):
228
"""Obey policy where possible, ignore otherwise."""
229
stack_on = self.make_branch('stack-on')
230
parent_bzrdir = self.make_bzrdir('.', format='default')
231
parent_bzrdir.get_config().set_default_stack_on('stack-on')
232
source = self.make_branch('source')
233
target = source.bzrdir.clone('target').open_branch()
235
self.assertEqual('../stack-on', target.get_stacked_on_url())
236
except errors.UnstackableBranchFormat:
239
def prepare_stacked_on_fetch(self):
240
stack_on = self.make_branch_and_tree('stack-on')
241
stack_on.commit('first commit', rev_id='rev1')
243
stacked_dir = stack_on.bzrdir.sprout('stacked', stacked=True)
244
except (errors.UnstackableRepositoryFormat,
245
errors.UnstackableBranchFormat):
246
raise TestNotApplicable('Format does not support stacking.')
247
unstacked = self.make_repository('unstacked')
248
return stacked_dir.open_workingtree(), unstacked
250
def test_fetch_copies_from_stacked_on(self):
251
stacked, unstacked = self.prepare_stacked_on_fetch()
252
unstacked.fetch(stacked.branch.repository, 'rev1')
253
unstacked.get_revision('rev1')
255
def test_fetch_copies_from_stacked_on_and_stacked(self):
256
stacked, unstacked = self.prepare_stacked_on_fetch()
257
stacked.commit('second commit', rev_id='rev2')
258
unstacked.fetch(stacked.branch.repository, 'rev2')
259
unstacked.get_revision('rev1')
260
unstacked.get_revision('rev2')