1
# Copyright (C) 2005, 2006, 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
18
"""Black-box tests for bzr branch."""
22
from bzrlib import (branch, bzrdir, errors, repository)
23
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
24
from bzrlib.tests.blackbox import ExternalBase
25
from bzrlib.tests import HardlinkFeature
26
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
27
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
28
from bzrlib.workingtree import WorkingTree
31
class TestBranch(ExternalBase):
33
def example_branch(self, path='.'):
34
tree = self.make_branch_and_tree(path)
35
self.build_tree_contents([(path + '/hello', 'foo')])
37
tree.commit(message='setup')
38
self.build_tree_contents([(path + '/goodbye', 'baz')])
40
tree.commit(message='setup')
42
def test_branch(self):
43
"""Branch from one branch to another."""
44
self.example_branch('a')
45
self.run_bzr('branch a b')
46
b = branch.Branch.open('b')
47
self.run_bzr('branch a c -r 1')
48
# previously was erroneously created by branching
49
self.assertFalse(b._transport.has('branch-name'))
50
b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
52
def test_branch_only_copies_history(self):
53
# Knit branches should only push the history for the current revision.
54
format = bzrdir.BzrDirMetaFormat1()
55
format.repository_format = RepositoryFormatKnit1()
56
shared_repo = self.make_repository('repo', format=format, shared=True)
57
shared_repo.set_make_working_trees(True)
59
def make_shared_tree(path):
60
shared_repo.bzrdir.root_transport.mkdir(path)
61
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
62
return WorkingTree.open('repo/' + path)
63
tree_a = make_shared_tree('a')
64
self.build_tree(['repo/a/file'])
66
tree_a.commit('commit a-1', rev_id='a-1')
67
f = open('repo/a/file', 'ab')
68
f.write('more stuff\n')
70
tree_a.commit('commit a-2', rev_id='a-2')
72
tree_b = make_shared_tree('b')
73
self.build_tree(['repo/b/file'])
75
tree_b.commit('commit b-1', rev_id='b-1')
77
self.assertTrue(shared_repo.has_revision('a-1'))
78
self.assertTrue(shared_repo.has_revision('a-2'))
79
self.assertTrue(shared_repo.has_revision('b-1'))
81
# Now that we have a repository with shared files, make sure
82
# that things aren't copied out by a 'branch'
83
self.run_bzr('branch repo/b branch-b')
84
pushed_tree = WorkingTree.open('branch-b')
85
pushed_repo = pushed_tree.branch.repository
86
self.assertFalse(pushed_repo.has_revision('a-1'))
87
self.assertFalse(pushed_repo.has_revision('a-2'))
88
self.assertTrue(pushed_repo.has_revision('b-1'))
90
def test_branch_hardlink(self):
91
self.requireFeature(HardlinkFeature)
92
source = self.make_branch_and_tree('source')
93
self.build_tree(['source/file1'])
95
source.commit('added file')
96
self.run_bzr(['branch', 'source', 'target', '--hardlink'])
97
source_stat = os.stat('source/file1')
98
target_stat = os.stat('target/file1')
99
self.assertEqual(source_stat, target_stat)
101
def test_branch_standalone(self):
102
shared_repo = self.make_repository('repo', shared=True)
103
self.example_branch('source')
104
self.run_bzr('branch --standalone source repo/target')
105
b = branch.Branch.open('repo/target')
106
expected_repo_path = os.path.abspath('repo/target/.bzr/repository')
107
self.assertEqual(strip_trailing_slash(b.repository.base),
108
strip_trailing_slash(local_path_to_url(expected_repo_path)))
111
class TestBranchStacked(ExternalBase):
112
"""Tests for branch --stacked"""
114
def check_shallow_branch(self, branch_revid, stacked_on):
115
"""Assert that the branch 'newbranch' has been published correctly.
117
:param stacked_on: url of a branch this one is stacked upon.
118
:param branch_revid: a revision id that should be the only
119
revision present in the stacked branch, and it should not be in
120
the reference branch.
122
new_branch = branch.Branch.open('newbranch')
123
# The branch refers to the mainline
124
self.assertEqual(stacked_on, new_branch.get_stacked_on_url())
125
# and the branch's work was pushed
126
self.assertTrue(new_branch.repository.has_revision(branch_revid))
127
# The newly committed revision shoud be present in the stacked branch,
128
# but not in the stacked-on branch. Because stacking is set up by the
129
# branch object, if we open the stacked branch's repository directly,
130
# bypassing the branch, we see only what's in the stacked repository.
131
stacked_repo = bzrdir.BzrDir.open('newbranch').open_repository()
132
stacked_repo_revisions = set(stacked_repo.all_revision_ids())
133
if len(stacked_repo_revisions) != 1:
134
self.fail("wrong revisions in stacked repository: %r"
135
% (stacked_repo_revisions,))
137
def assertRevisionInRepository(self, repo_path, revid):
138
"""Check that a revision is in a repository, disregarding stacking."""
139
repo = bzrdir.BzrDir.open(repo_path).open_repository()
140
self.assertTrue(repo.has_revision(revid))
142
def assertRevisionNotInRepository(self, repo_path, revid):
143
"""Check that a revision is not in a repository, disregarding stacking."""
144
repo = bzrdir.BzrDir.open(repo_path).open_repository()
145
self.assertFalse(repo.has_revision(revid))
147
def assertRevisionsInBranchRepository(self, revid_list, branch_path):
148
repo = branch.Branch.open(branch_path).repository
149
self.assertEqual(set(revid_list),
150
repo.has_revisions(revid_list))
152
def test_branch_stacked_branch_not_stacked(self):
153
"""Branching a stacked branch is not stacked by default"""
155
trunk_tree = self.make_branch_and_tree('target',
156
format='development')
157
trunk_tree.commit('mainline')
158
# and a branch from it which is stacked
159
branch_tree = self.make_branch_and_tree('branch',
160
format='development')
161
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
162
# with some work on it
163
branch_tree.commit('moar work plz')
164
# branching our local branch gives us a new stacked branch pointing at
166
out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
167
self.assertEqual('', out)
168
self.assertEqual('Branched 1 revision(s).\n',
170
# it should have preserved the branch format, and so it should be
171
# capable of supporting stacking, but not actually have a stacked_on
173
self.assertRaises(errors.NotStacked,
174
bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
176
def test_branch_stacked_branch_stacked(self):
177
"""Asking to stack on a stacked branch does work"""
179
trunk_tree = self.make_branch_and_tree('target',
180
format='development')
181
trunk_revid = trunk_tree.commit('mainline')
182
# and a branch from it which is stacked
183
branch_tree = self.make_branch_and_tree('branch',
184
format='development')
185
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
186
# with some work on it
187
branch_revid = branch_tree.commit('moar work plz')
188
# you can chain branches on from there
189
out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
190
self.assertEqual('', out)
191
self.assertEqual('Created new stacked branch referring to %s.\n' %
192
branch_tree.branch.base, err)
193
self.assertEqual(branch_tree.branch.base,
194
branch.Branch.open('branch2').get_stacked_on_url())
195
branch2_tree = WorkingTree.open('branch2')
196
branch2_revid = branch2_tree.commit('work on second stacked branch')
197
self.assertRevisionInRepository('branch2', branch2_revid)
198
self.assertRevisionsInBranchRepository(
199
[trunk_revid, branch_revid, branch2_revid],
202
def test_branch_stacked(self):
204
trunk_tree = self.make_branch_and_tree('mainline',
205
format='development')
206
original_revid = trunk_tree.commit('mainline')
207
self.assertRevisionInRepository('mainline', original_revid)
208
# and a branch from it which is stacked
209
out, err = self.run_bzr(['branch', '--stacked', 'mainline',
211
self.assertEqual('', out)
212
self.assertEqual('Created new stacked branch referring to %s.\n' %
213
trunk_tree.branch.base, err)
214
self.assertRevisionNotInRepository('newbranch', original_revid)
215
new_tree = WorkingTree.open('newbranch')
216
new_revid = new_tree.commit('new work')
217
self.check_shallow_branch(new_revid, trunk_tree.branch.base)
219
def test_branch_stacked_from_smart_server(self):
220
# We can branch stacking on a smart server
221
from bzrlib.smart.server import SmartTCPServer_for_testing
222
self.transport_server = SmartTCPServer_for_testing
223
trunk = self.make_branch('mainline', format='development')
224
out, err = self.run_bzr(
225
['branch', '--stacked', self.get_url('mainline'), 'shallow'])
227
def test_branch_stacked_from_non_stacked_format(self):
228
"""The origin format doesn't support stacking"""
229
trunk = self.make_branch('trunk', format='pack-0.92')
230
out, err = self.run_bzr(
231
['branch', '--stacked', 'trunk', 'shallow'])
232
# We should notify the user that we upgraded their format
233
self.assertEqualDiff(
234
'Source format does not support stacking, using format: \'1.6\'\n'
235
' Packs 5 (adds stacking support, requires bzr 1.6)\n'
237
'Created new stacked branch referring to %s.\n' % (trunk.base,),
240
def test_branch_stacked_from_rich_root_non_stackable(self):
241
trunk = self.make_branch('trunk', format='rich-root-pack')
242
out, err = self.run_bzr(
243
['branch', '--stacked', 'trunk', 'shallow'])
244
# We should notify the user that we upgraded their format
245
self.assertEqualDiff(
246
'Source format does not support stacking, using format:'
247
' \'1.6.1-rich-root\'\n'
248
' Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
250
'Created new stacked branch referring to %s.\n' % (trunk.base,),
255
class TestRemoteBranch(TestCaseWithSFTPServer):
258
super(TestRemoteBranch, self).setUp()
259
tree = self.make_branch_and_tree('branch')
260
self.build_tree_contents([('branch/file', 'file content\n')])
262
tree.commit('file created')
264
def test_branch_local_remote(self):
265
self.run_bzr(['branch', 'branch', self.get_url('remote')])
266
t = self.get_transport()
267
# Ensure that no working tree what created remotely
268
self.assertFalse(t.has('remote/file'))
270
def test_branch_remote_remote(self):
271
# Light cheat: we access the branch remotely
272
self.run_bzr(['branch', self.get_url('branch'),
273
self.get_url('remote')])
274
t = self.get_transport()
275
# Ensure that no working tree what created remotely
276
self.assertFalse(t.has('remote/file'))