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.workingtree import WorkingTree
30
class TestBranch(ExternalBase):
32
def example_branch(self, path='.'):
33
tree = self.make_branch_and_tree(path)
34
self.build_tree_contents([(path + '/hello', 'foo')])
36
tree.commit(message='setup')
37
self.build_tree_contents([(path + '/goodbye', 'baz')])
39
tree.commit(message='setup')
41
def test_branch(self):
42
"""Branch from one branch to another."""
43
self.example_branch('a')
44
self.run_bzr('branch a b')
45
b = branch.Branch.open('b')
46
self.run_bzr('branch a c -r 1')
47
# previously was erroneously created by branching
48
self.assertFalse(b._transport.has('branch-name'))
49
b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
51
def test_branch_only_copies_history(self):
52
# Knit branches should only push the history for the current revision.
53
format = bzrdir.BzrDirMetaFormat1()
54
format.repository_format = RepositoryFormatKnit1()
55
shared_repo = self.make_repository('repo', format=format, shared=True)
56
shared_repo.set_make_working_trees(True)
58
def make_shared_tree(path):
59
shared_repo.bzrdir.root_transport.mkdir(path)
60
shared_repo.bzrdir.create_branch_convenience('repo/' + path)
61
return WorkingTree.open('repo/' + path)
62
tree_a = make_shared_tree('a')
63
self.build_tree(['repo/a/file'])
65
tree_a.commit('commit a-1', rev_id='a-1')
66
f = open('repo/a/file', 'ab')
67
f.write('more stuff\n')
69
tree_a.commit('commit a-2', rev_id='a-2')
71
tree_b = make_shared_tree('b')
72
self.build_tree(['repo/b/file'])
74
tree_b.commit('commit b-1', rev_id='b-1')
76
self.assertTrue(shared_repo.has_revision('a-1'))
77
self.assertTrue(shared_repo.has_revision('a-2'))
78
self.assertTrue(shared_repo.has_revision('b-1'))
80
# Now that we have a repository with shared files, make sure
81
# that things aren't copied out by a 'branch'
82
self.run_bzr('branch repo/b branch-b')
83
pushed_tree = WorkingTree.open('branch-b')
84
pushed_repo = pushed_tree.branch.repository
85
self.assertFalse(pushed_repo.has_revision('a-1'))
86
self.assertFalse(pushed_repo.has_revision('a-2'))
87
self.assertTrue(pushed_repo.has_revision('b-1'))
89
def test_branch_hardlink(self):
90
self.requireFeature(HardlinkFeature)
91
source = self.make_branch_and_tree('source')
92
self.build_tree(['source/file1'])
94
source.commit('added file')
95
self.run_bzr(['branch', 'source', 'target', '--hardlink'])
96
source_stat = os.stat('source/file1')
97
target_stat = os.stat('target/file1')
98
self.assertEqual(source_stat, target_stat)
101
class TestBranchStacked(ExternalBase):
102
"""Tests for branch --stacked"""
104
def check_shallow_branch(self, branch_revid, stacked_on):
105
"""Assert that the branch 'newbranch' has been published correctly.
107
:param stacked_on: url of a branch this one is stacked upon.
108
:param branch_revid: a revision id that should be the only
109
revision present in the stacked branch, and it should not be in
110
the reference branch.
112
new_branch = branch.Branch.open('newbranch')
113
# The branch refers to the mainline
114
self.assertEqual(stacked_on, new_branch.get_stacked_on_url())
115
# and the branch's work was pushed
116
self.assertTrue(new_branch.repository.has_revision(branch_revid))
117
# The newly committed revision shoud be present in the stacked branch,
118
# but not in the stacked-on branch. Because stacking is set up by the
119
# branch object, if we open the stacked branch's repository directly,
120
# bypassing the branch, we see only what's in the stacked repository.
121
stacked_repo = bzrdir.BzrDir.open('newbranch').open_repository()
122
stacked_repo_revisions = set(stacked_repo.all_revision_ids())
123
if len(stacked_repo_revisions) != 1:
124
self.fail("wrong revisions in stacked repository: %r"
125
% (stacked_repo_revisions,))
127
def assertRevisionInRepository(self, repo_path, revid):
128
"""Check that a revision is in a repository, disregarding stacking."""
129
repo = bzrdir.BzrDir.open(repo_path).open_repository()
130
self.assertTrue(repo.has_revision(revid))
132
def assertRevisionNotInRepository(self, repo_path, revid):
133
"""Check that a revision is not in a repository, disregarding stacking."""
134
repo = bzrdir.BzrDir.open(repo_path).open_repository()
135
self.assertFalse(repo.has_revision(revid))
137
def assertRevisionsInBranchRepository(self, revid_list, branch_path):
138
repo = branch.Branch.open(branch_path).repository
139
self.assertEqual(set(revid_list),
140
repo.has_revisions(revid_list))
142
def test_branch_stacked_branch_not_stacked(self):
143
"""Branching a stacked branch is not stacked by default"""
145
trunk_tree = self.make_branch_and_tree('target',
146
format='development')
147
trunk_tree.commit('mainline')
148
# and a branch from it which is stacked
149
branch_tree = self.make_branch_and_tree('branch',
150
format='development')
151
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
152
# with some work on it
153
branch_tree.commit('moar work plz')
154
# branching our local branch gives us a new stacked branch pointing at
156
out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
157
self.assertEqual('', out)
158
self.assertEqual('Branched 1 revision(s).\n',
160
# it should have preserved the branch format, and so it should be
161
# capable of supporting stacking, but not actually have a stacked_on
163
self.assertRaises(errors.NotStacked,
164
bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
166
def test_branch_stacked_branch_stacked(self):
167
"""Asking to stack on a stacked branch does work"""
169
trunk_tree = self.make_branch_and_tree('target',
170
format='development')
171
trunk_revid = trunk_tree.commit('mainline')
172
# and a branch from it which is stacked
173
branch_tree = self.make_branch_and_tree('branch',
174
format='development')
175
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
176
# with some work on it
177
branch_revid = branch_tree.commit('moar work plz')
178
# you can chain branches on from there
179
out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
180
self.assertEqual('', out)
181
self.assertEqual('Created new stacked branch referring to %s.\n' %
182
branch_tree.branch.base, err)
183
self.assertEqual(branch_tree.branch.base,
184
branch.Branch.open('branch2').get_stacked_on_url())
185
branch2_tree = WorkingTree.open('branch2')
186
branch2_revid = branch2_tree.commit('work on second stacked branch')
187
self.assertRevisionInRepository('branch2', branch2_revid)
188
self.assertRevisionsInBranchRepository(
189
[trunk_revid, branch_revid, branch2_revid],
192
def test_branch_stacked(self):
194
trunk_tree = self.make_branch_and_tree('mainline',
195
format='development')
196
original_revid = trunk_tree.commit('mainline')
197
self.assertRevisionInRepository('mainline', original_revid)
198
# and a branch from it which is stacked
199
out, err = self.run_bzr(['branch', '--stacked', 'mainline',
201
self.assertEqual('', out)
202
self.assertEqual('Created new stacked branch referring to %s.\n' %
203
trunk_tree.branch.base, err)
204
self.assertRevisionNotInRepository('newbranch', original_revid)
205
new_tree = WorkingTree.open('newbranch')
206
new_revid = new_tree.commit('new work')
207
self.check_shallow_branch(new_revid, trunk_tree.branch.base)
209
def test_branch_stacked_from_smart_server(self):
210
# We can branch stacking on a smart server
211
from bzrlib.smart.server import SmartTCPServer_for_testing
212
self.transport_server = SmartTCPServer_for_testing
213
trunk = self.make_branch('mainline', format='development')
214
out, err = self.run_bzr(
215
['branch', '--stacked', self.get_url('mainline'), 'shallow'])
217
def test_branch_stacked_from_non_stacked_format(self):
218
"""The origin format doesn't support stacking"""
219
trunk = self.make_branch('trunk', format='pack-0.92')
220
out, err = self.run_bzr(
221
['branch', '--stacked', 'trunk', 'shallow'])
222
# We should notify the user that we upgraded their format
223
self.assertEqualDiff(
224
'Source format does not support stacking, using format: \'1.6\'\n'
225
' Packs 5 (adds stacking support, requires bzr 1.6)\n'
227
'Created new stacked branch referring to %s.\n' % (trunk.base,),
230
def test_branch_stacked_from_rich_root_non_stackable(self):
231
trunk = self.make_branch('trunk', format='rich-root-pack')
232
out, err = self.run_bzr(
233
['branch', '--stacked', 'trunk', 'shallow'])
234
# We should notify the user that we upgraded their format
235
self.assertEqualDiff(
236
'Source format does not support stacking, using format:'
237
' \'1.6.1-rich-root\'\n'
238
' Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
240
'Created new stacked branch referring to %s.\n' % (trunk.base,),
245
class TestRemoteBranch(TestCaseWithSFTPServer):
248
super(TestRemoteBranch, self).setUp()
249
tree = self.make_branch_and_tree('branch')
250
self.build_tree_contents([('branch/file', 'file content\n')])
252
tree.commit('file created')
254
def test_branch_local_remote(self):
255
self.run_bzr(['branch', 'branch', self.get_url('remote')])
256
t = self.get_transport()
257
# Ensure that no working tree what created remotely
258
self.assertFalse(t.has('remote/file'))
260
def test_branch_remote_remote(self):
261
# Light cheat: we access the branch remotely
262
self.run_bzr(['branch', self.get_url('branch'),
263
self.get_url('remote')])
264
t = self.get_transport()
265
# Ensure that no working tree what created remotely
266
self.assertFalse(t.has('remote/file'))