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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
"""Black-box tests for bzr branch."""
22
from bzrlib import (branch, bzrdir, errors, repository)
22
from bzrlib import branch, bzrdir
23
23
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
24
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
25
from bzrlib.workingtree import WorkingTree
31
28
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')
30
def example_branch(test):
32
file('hello', 'wt').write('foo')
33
test.runbzr('add hello')
34
test.runbzr('commit -m setup hello')
35
file('goodbye', 'wt').write('baz')
36
test.runbzr('add goodbye')
37
test.runbzr('commit -m setup goodbye')
42
39
def test_branch(self):
43
40
"""Branch from one branch to another."""
44
self.example_branch('a')
45
self.run_bzr('branch a b')
45
self.runbzr('branch a b')
46
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)
47
self.assertEqual('b\n', b.control_files.get_utf8('branch-name').read())
48
self.runbzr('branch a c -r 1')
50
self.runbzr('commit -m foo --unchanged')
52
53
def test_branch_only_copies_history(self):
53
54
# Knit branches should only push the history for the current revision.
81
82
# Now that we have a repository with shared files, make sure
82
83
# that things aren't copied out by a 'branch'
83
self.run_bzr('branch repo/b branch-b')
84
self.run_bzr('branch', 'repo/b', 'branch-b')
84
85
pushed_tree = WorkingTree.open('branch-b')
85
86
pushed_repo = pushed_tree.branch.repository
86
87
self.assertFalse(pushed_repo.has_revision('a-1'))
87
88
self.assertFalse(pushed_repo.has_revision('a-2'))
88
89
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)))
110
def test_branch_no_tree(self):
111
self.example_branch('source')
112
self.run_bzr('branch --no-tree source target')
113
self.failIfExists('target/hello')
114
self.failIfExists('target/goodbye')
117
class TestBranchStacked(ExternalBase):
118
"""Tests for branch --stacked"""
120
def check_shallow_branch(self, branch_revid, stacked_on):
121
"""Assert that the branch 'newbranch' has been published correctly.
123
:param stacked_on: url of a branch this one is stacked upon.
124
:param branch_revid: a revision id that should be the only
125
revision present in the stacked branch, and it should not be in
126
the reference branch.
128
new_branch = branch.Branch.open('newbranch')
129
# The branch refers to the mainline
130
self.assertEqual(stacked_on, new_branch.get_stacked_on_url())
131
# and the branch's work was pushed
132
self.assertTrue(new_branch.repository.has_revision(branch_revid))
133
# The newly committed revision shoud be present in the stacked branch,
134
# but not in the stacked-on branch. Because stacking is set up by the
135
# branch object, if we open the stacked branch's repository directly,
136
# bypassing the branch, we see only what's in the stacked repository.
137
stacked_repo = bzrdir.BzrDir.open('newbranch').open_repository()
138
stacked_repo_revisions = set(stacked_repo.all_revision_ids())
139
if len(stacked_repo_revisions) != 1:
140
self.fail("wrong revisions in stacked repository: %r"
141
% (stacked_repo_revisions,))
143
def assertRevisionInRepository(self, repo_path, revid):
144
"""Check that a revision is in a repository, disregarding stacking."""
145
repo = bzrdir.BzrDir.open(repo_path).open_repository()
146
self.assertTrue(repo.has_revision(revid))
148
def assertRevisionNotInRepository(self, repo_path, revid):
149
"""Check that a revision is not in a repository, disregarding stacking."""
150
repo = bzrdir.BzrDir.open(repo_path).open_repository()
151
self.assertFalse(repo.has_revision(revid))
153
def assertRevisionsInBranchRepository(self, revid_list, branch_path):
154
repo = branch.Branch.open(branch_path).repository
155
self.assertEqual(set(revid_list),
156
repo.has_revisions(revid_list))
158
def test_branch_stacked_branch_not_stacked(self):
159
"""Branching a stacked branch is not stacked by default"""
161
trunk_tree = self.make_branch_and_tree('target',
163
trunk_tree.commit('mainline')
164
# and a branch from it which is stacked
165
branch_tree = self.make_branch_and_tree('branch',
167
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
168
# with some work on it
169
branch_tree.commit('moar work plz')
170
# branching our local branch gives us a new stacked branch pointing at
172
out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
173
self.assertEqual('', out)
174
self.assertEqual('Branched 1 revision(s).\n',
176
# it should have preserved the branch format, and so it should be
177
# capable of supporting stacking, but not actually have a stacked_on
179
self.assertRaises(errors.NotStacked,
180
bzrdir.BzrDir.open('newbranch').open_branch().get_stacked_on_url)
182
def test_branch_stacked_branch_stacked(self):
183
"""Asking to stack on a stacked branch does work"""
185
trunk_tree = self.make_branch_and_tree('target',
187
trunk_revid = trunk_tree.commit('mainline')
188
# and a branch from it which is stacked
189
branch_tree = self.make_branch_and_tree('branch',
191
branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
192
# with some work on it
193
branch_revid = branch_tree.commit('moar work plz')
194
# you can chain branches on from there
195
out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
196
self.assertEqual('', out)
197
self.assertEqual('Created new stacked branch referring to %s.\n' %
198
branch_tree.branch.base, err)
199
self.assertEqual(branch_tree.branch.base,
200
branch.Branch.open('branch2').get_stacked_on_url())
201
branch2_tree = WorkingTree.open('branch2')
202
branch2_revid = branch2_tree.commit('work on second stacked branch')
203
self.assertRevisionInRepository('branch2', branch2_revid)
204
self.assertRevisionsInBranchRepository(
205
[trunk_revid, branch_revid, branch2_revid],
208
def test_branch_stacked(self):
210
trunk_tree = self.make_branch_and_tree('mainline',
212
original_revid = trunk_tree.commit('mainline')
213
self.assertRevisionInRepository('mainline', original_revid)
214
# and a branch from it which is stacked
215
out, err = self.run_bzr(['branch', '--stacked', 'mainline',
217
self.assertEqual('', out)
218
self.assertEqual('Created new stacked branch referring to %s.\n' %
219
trunk_tree.branch.base, err)
220
self.assertRevisionNotInRepository('newbranch', original_revid)
221
new_tree = WorkingTree.open('newbranch')
222
new_revid = new_tree.commit('new work')
223
self.check_shallow_branch(new_revid, trunk_tree.branch.base)
225
def test_branch_stacked_from_smart_server(self):
226
# We can branch stacking on a smart server
227
from bzrlib.smart.server import SmartTCPServer_for_testing
228
self.transport_server = SmartTCPServer_for_testing
229
trunk = self.make_branch('mainline', format='1.9')
230
out, err = self.run_bzr(
231
['branch', '--stacked', self.get_url('mainline'), 'shallow'])
233
def test_branch_stacked_from_non_stacked_format(self):
234
"""The origin format doesn't support stacking"""
235
trunk = self.make_branch('trunk', format='pack-0.92')
236
out, err = self.run_bzr(
237
['branch', '--stacked', 'trunk', 'shallow'])
238
# We should notify the user that we upgraded their format
239
self.assertEqualDiff(
240
'Source format does not support stacking, using format: \'1.6\'\n'
241
' Packs 5 (adds stacking support, requires bzr 1.6)\n'
243
'Created new stacked branch referring to %s.\n' % (trunk.base,),
246
def test_branch_stacked_from_rich_root_non_stackable(self):
247
trunk = self.make_branch('trunk', format='rich-root-pack')
248
out, err = self.run_bzr(
249
['branch', '--stacked', 'trunk', 'shallow'])
250
# We should notify the user that we upgraded their format
251
self.assertEqualDiff(
252
'Source format does not support stacking, using format:'
253
' \'1.6.1-rich-root\'\n'
254
' Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
256
'Created new stacked branch referring to %s.\n' % (trunk.base,),
260
class TestSmartServerBranching(ExternalBase):
262
def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
263
self.setup_smart_server_with_call_log()
264
t = self.make_branch_and_tree('from')
265
for count in range(9):
266
t.commit(message='commit %d' % count)
267
self.reset_smart_call_log()
268
out, err = self.run_bzr(['branch', self.get_url('from'),
269
self.get_url('target')])
270
# This figure represent the amount of work to perform this use case. It
271
# is entirely ok to reduce this number if a test fails due to rpc_count
272
# being too low. If rpc_count increases, more network roundtrips have
273
# become necessary for this use case. Please do not adjust this number
274
# upwards without agreement from bzr's network support maintainers.
275
self.assertLength(39, self.hpss_calls)
277
def test_branch_from_trivial_branch_streaming_acceptance(self):
278
self.setup_smart_server_with_call_log()
279
t = self.make_branch_and_tree('from')
280
for count in range(9):
281
t.commit(message='commit %d' % count)
282
self.reset_smart_call_log()
283
out, err = self.run_bzr(['branch', self.get_url('from'),
285
# This figure represent the amount of work to perform this use case. It
286
# is entirely ok to reduce this number if a test fails due to rpc_count
287
# being too low. If rpc_count increases, more network roundtrips have
288
# become necessary for this use case. Please do not adjust this number
289
# upwards without agreement from bzr's network support maintainers.
290
self.assertLength(10, self.hpss_calls)
292
def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
293
self.setup_smart_server_with_call_log()
294
t = self.make_branch_and_tree('trunk')
295
for count in range(8):
296
t.commit(message='commit %d' % count)
297
tree2 = t.branch.bzrdir.sprout('feature', stacked=True
299
tree2.commit('feature change')
300
self.reset_smart_call_log()
301
out, err = self.run_bzr(['branch', self.get_url('feature'),
303
# This figure represent the amount of work to perform this use case. It
304
# is entirely ok to reduce this number if a test fails due to rpc_count
305
# being too low. If rpc_count increases, more network roundtrips have
306
# become necessary for this use case. Please do not adjust this number
307
# upwards without agreement from bzr's network support maintainers.
308
self.assertLength(15, self.hpss_calls)
311
class TestRemoteBranch(TestCaseWithSFTPServer):
314
super(TestRemoteBranch, self).setUp()
315
tree = self.make_branch_and_tree('branch')
316
self.build_tree_contents([('branch/file', 'file content\n')])
318
tree.commit('file created')
320
def test_branch_local_remote(self):
321
self.run_bzr(['branch', 'branch', self.get_url('remote')])
322
t = self.get_transport()
323
# Ensure that no working tree what created remotely
324
self.assertFalse(t.has('remote/file'))
326
def test_branch_remote_remote(self):
327
# Light cheat: we access the branch remotely
328
self.run_bzr(['branch', self.get_url('branch'),
329
self.get_url('remote')])
330
t = self.get_transport()
331
# Ensure that no working tree what created remotely
332
self.assertFalse(t.has('remote/file'))