~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_branch.py

  • Committer: Patch Queue Manager
  • Date: 2015-04-21 05:32:33 UTC
  • mfrom: (6602.1.1 bzr.dev)
  • Revision ID: pqm@pqm.ubuntu.com-20150421053233-x63rhby1q3612v2h
(richard-wilbur) (jelmer)Make bzr build reproducible for Debian. (Jelmer
 Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 by Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
18
"""Black-box tests for bzr branch."""
19
19
 
20
20
import os
21
21
 
22
 
from bzrlib import branch, bzrdir
23
 
from bzrlib.repository import RepositoryFormatKnit1
24
 
from bzrlib.tests.blackbox import ExternalBase
 
22
from bzrlib import (
 
23
    branch,
 
24
    bzrdir,
 
25
    controldir,
 
26
    errors,
 
27
    revision as _mod_revision,
 
28
    tests,
 
29
    )
 
30
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
 
31
from bzrlib.tests import (
 
32
    fixtures,
 
33
    test_server,
 
34
    )
 
35
from bzrlib.tests.features import (
 
36
    HardlinkFeature,
 
37
    )
 
38
from bzrlib.tests.blackbox import test_switch
 
39
from bzrlib.tests.matchers import ContainsNoVfsCalls
 
40
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 
41
from bzrlib.tests.script import run_script
 
42
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
25
43
from bzrlib.workingtree import WorkingTree
26
44
 
27
45
 
28
 
class TestBranch(ExternalBase):
 
46
class TestBranch(tests.TestCaseWithTransport):
29
47
 
30
 
    def example_branch(test):
31
 
        test.runbzr('init')
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')
 
48
    def example_branch(self, path='.', format=None):
 
49
        tree = self.make_branch_and_tree(path, format=format)
 
50
        self.build_tree_contents([(path + '/hello', 'foo')])
 
51
        tree.add('hello')
 
52
        tree.commit(message='setup')
 
53
        self.build_tree_contents([(path + '/goodbye', 'baz')])
 
54
        tree.add('goodbye')
 
55
        tree.commit(message='setup')
 
56
        return tree
38
57
 
39
58
    def test_branch(self):
40
59
        """Branch from one branch to another."""
41
 
        os.mkdir('a')
42
 
        os.chdir('a')
43
 
        self.example_branch()
44
 
        os.chdir('..')
45
 
        self.runbzr('branch a b')
46
 
        b = branch.Branch.open('b')
47
 
        self.assertEqual('b\n', b.control_files.get_utf8('branch-name').read())
48
 
        self.runbzr('branch a c -r 1')
49
 
        os.chdir('b')
50
 
        self.runbzr('commit -m foo --unchanged')
51
 
        os.chdir('..')
52
 
 
53
 
    def test_branch_basis(self):
54
 
        # ensure that basis really does grab from the basis by having incomplete source
55
 
        tree = self.make_branch_and_tree('commit_tree')
56
 
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
57
 
        tree.add('foo')
58
 
        tree.commit('revision 1', rev_id='1')
59
 
        source = self.make_branch_and_tree('source')
60
 
        # this gives us an incomplete repository
61
 
        tree.bzrdir.open_repository().copy_content_into(source.branch.repository)
62
 
        tree.commit('revision 2', rev_id='2', allow_pointless=True)
63
 
        tree.bzrdir.open_branch().copy_content_into(source.branch)
64
 
        tree.copy_content_into(source)
65
 
        self.assertFalse(source.branch.repository.has_revision('2'))
66
 
        dir = source.bzrdir
67
 
        self.runbzr('branch source target --basis commit_tree')
68
 
        target = bzrdir.BzrDir.open('target')
69
 
        self.assertEqual('2', target.open_branch().last_revision())
70
 
        self.assertEqual('2', target.open_workingtree().last_revision())
71
 
        self.assertTrue(target.open_branch().repository.has_revision('2'))
 
60
        self.example_branch('a')
 
61
        self.run_bzr('branch a b')
 
62
        b = branch.Branch.open('b')
 
63
        self.run_bzr('branch a c -r 1')
 
64
        # previously was erroneously created by branching
 
65
        self.assertFalse(b._transport.has('branch-name'))
 
66
        b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
 
67
 
 
68
    def test_branch_no_to_location(self):
 
69
        """The to_location is derived from the source branch name."""
 
70
        os.mkdir("something")
 
71
        a = self.example_branch('something/a').branch
 
72
        self.run_bzr('branch something/a')
 
73
        b = branch.Branch.open('a')
 
74
        self.assertEquals(b.last_revision_info(), a.last_revision_info())
 
75
 
 
76
    def test_into_colocated(self):
 
77
        """Branch from a branch into a colocated branch."""
 
78
        self.example_branch('a')
 
79
        out, err = self.run_bzr(
 
80
            'init --format=development-colo file:b,branch=orig')
 
81
        self.assertEqual(
 
82
            """Created a lightweight checkout (format: development-colo)\n""",
 
83
            out)
 
84
        self.assertEqual('', err)
 
85
        out, err = self.run_bzr(
 
86
            'branch a file:b,branch=thiswasa')
 
87
        self.assertEqual('', out)
 
88
        self.assertEqual('Branched 2 revisions.\n', err)
 
89
        out, err = self.run_bzr('branches b')
 
90
        self.assertEqual("  orig\n  thiswasa\n", out)
 
91
        self.assertEqual('', err)
 
92
        out,err = self.run_bzr('branch a file:b,branch=orig', retcode=3)
 
93
        self.assertEqual('', out)
 
94
        self.assertEqual(
 
95
            'bzr: ERROR: Already a branch: "file:b,branch=orig".\n', err)
 
96
 
 
97
    def test_from_colocated(self):
 
98
        """Branch from a colocated branch into a regular branch."""
 
99
        tree = self.example_branch('a', format='development-colo')
 
100
        tree.bzrdir.create_branch(name='somecolo')
 
101
        out, err = self.run_bzr('branch %s,branch=somecolo' %
 
102
            local_path_to_url('a'))
 
103
        self.assertEqual('', out)
 
104
        self.assertEqual('Branched 0 revisions.\n', err)
 
105
        self.assertPathExists("somecolo")
 
106
 
 
107
    def test_branch_broken_pack(self):
 
108
        """branching with a corrupted pack file."""
 
109
        self.example_branch('a')
 
110
        # add some corruption
 
111
        packs_dir = 'a/.bzr/repository/packs/'
 
112
        fname = packs_dir + os.listdir(packs_dir)[0]
 
113
        with open(fname, 'rb+') as f:
 
114
            # Start from the end of the file to avoid choosing a place bigger
 
115
            # than the file itself.
 
116
            f.seek(-5, os.SEEK_END)
 
117
            c = f.read(1)
 
118
            f.seek(-5, os.SEEK_END)
 
119
            # Make sure we inject a value different than the one we just read
 
120
            if c == '\xFF':
 
121
                corrupt = '\x00'
 
122
            else:
 
123
                corrupt = '\xFF'
 
124
            f.write(corrupt) # make sure we corrupt something
 
125
        self.run_bzr_error(['Corruption while decompressing repository file'],
 
126
                            'branch a b', retcode=3)
 
127
 
 
128
    def test_branch_switch_no_branch(self):
 
129
        # No branch in the current directory:
 
130
        #  => new branch will be created, but switch fails
 
131
        self.example_branch('a')
 
132
        self.make_repository('current')
 
133
        self.run_bzr_error(['No WorkingTree exists for'],
 
134
            'branch --switch ../a ../b', working_dir='current')
 
135
        a = branch.Branch.open('a')
 
136
        b = branch.Branch.open('b')
 
137
        self.assertEqual(a.last_revision(), b.last_revision())
 
138
 
 
139
    def test_branch_switch_no_wt(self):
 
140
        # No working tree in the current directory:
 
141
        #  => new branch will be created, but switch fails and the current
 
142
        #     branch is unmodified
 
143
        self.example_branch('a')
 
144
        self.make_branch('current')
 
145
        self.run_bzr_error(['No WorkingTree exists for'],
 
146
            'branch --switch ../a ../b', working_dir='current')
 
147
        a = branch.Branch.open('a')
 
148
        b = branch.Branch.open('b')
 
149
        self.assertEqual(a.last_revision(), b.last_revision())
 
150
        work = branch.Branch.open('current')
 
151
        self.assertEqual(work.last_revision(), _mod_revision.NULL_REVISION)
 
152
 
 
153
    def test_branch_switch_no_checkout(self):
 
154
        # Standalone branch in the current directory:
 
155
        #  => new branch will be created, but switch fails and the current
 
156
        #     branch is unmodified
 
157
        self.example_branch('a')
 
158
        tree = self.make_branch_and_tree('current')
 
159
        c1 = tree.commit('some diverged change')
 
160
        self.run_bzr_error(['Cannot switch a branch, only a checkout'],
 
161
            'branch --switch ../a ../b', working_dir='current')
 
162
        a = branch.Branch.open('a')
 
163
        b = branch.Branch.open('b')
 
164
        self.assertEqual(a.last_revision(), b.last_revision())
 
165
        work = branch.Branch.open('current')
 
166
        self.assertEqual(work.last_revision(), c1)
 
167
 
 
168
    def test_branch_into_empty_dir(self):
 
169
        t = self.example_branch('source')
 
170
        self.make_bzrdir('target')
 
171
        self.run_bzr("branch source target")
 
172
        self.assertEquals(2, len(t.branch.repository.all_revision_ids()))
 
173
 
 
174
    def test_branch_switch_checkout(self):
 
175
        # Checkout in the current directory:
 
176
        #  => new branch will be created and checkout bound to the new branch
 
177
        self.example_branch('a')
 
178
        self.run_bzr('checkout a current')
 
179
        out, err = self.run_bzr('branch --switch ../a ../b',
 
180
                                working_dir='current')
 
181
        a = branch.Branch.open('a')
 
182
        b = branch.Branch.open('b')
 
183
        self.assertEqual(a.last_revision(), b.last_revision())
 
184
        work = WorkingTree.open('current')
 
185
        self.assertEndsWith(work.branch.get_bound_location(), '/b/')
 
186
        self.assertContainsRe(err, "Switched to branch: .*/b/")
 
187
 
 
188
    def test_branch_switch_lightweight_checkout(self):
 
189
        # Lightweight checkout in the current directory:
 
190
        #  => new branch will be created and lightweight checkout pointed to
 
191
        #     the new branch
 
192
        self.example_branch('a')
 
193
        self.run_bzr('checkout --lightweight a current')
 
194
        out, err = self.run_bzr('branch --switch ../a ../b',
 
195
                                working_dir='current')
 
196
        a = branch.Branch.open('a')
 
197
        b = branch.Branch.open('b')
 
198
        self.assertEqual(a.last_revision(), b.last_revision())
 
199
        work = WorkingTree.open('current')
 
200
        self.assertEndsWith(work.branch.base, '/b/')
 
201
        self.assertContainsRe(err, "Switched to branch: .*/b/")
72
202
 
73
203
    def test_branch_only_copies_history(self):
74
204
        # Knit branches should only push the history for the current revision.
79
209
 
80
210
        def make_shared_tree(path):
81
211
            shared_repo.bzrdir.root_transport.mkdir(path)
82
 
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
 
212
            controldir.ControlDir.create_branch_convenience('repo/' + path)
83
213
            return WorkingTree.open('repo/' + path)
84
214
        tree_a = make_shared_tree('a')
85
215
        self.build_tree(['repo/a/file'])
101
231
 
102
232
        # Now that we have a repository with shared files, make sure
103
233
        # that things aren't copied out by a 'branch'
104
 
        self.run_bzr('branch', 'repo/b', 'branch-b')
 
234
        self.run_bzr('branch repo/b branch-b')
105
235
        pushed_tree = WorkingTree.open('branch-b')
106
236
        pushed_repo = pushed_tree.branch.repository
107
237
        self.assertFalse(pushed_repo.has_revision('a-1'))
108
238
        self.assertFalse(pushed_repo.has_revision('a-2'))
109
239
        self.assertTrue(pushed_repo.has_revision('b-1'))
110
240
 
111
 
 
 
241
    def test_branch_hardlink(self):
 
242
        self.requireFeature(HardlinkFeature)
 
243
        source = self.make_branch_and_tree('source')
 
244
        self.build_tree(['source/file1'])
 
245
        source.add('file1')
 
246
        source.commit('added file')
 
247
        out, err = self.run_bzr(['branch', 'source', 'target', '--hardlink'])
 
248
        source_stat = os.stat('source/file1')
 
249
        target_stat = os.stat('target/file1')
 
250
        self.assertEqual(source_stat, target_stat)
 
251
 
 
252
    def test_branch_files_from(self):
 
253
        source = self.make_branch_and_tree('source')
 
254
        self.build_tree(['source/file1'])
 
255
        source.add('file1')
 
256
        source.commit('added file')
 
257
        out, err = self.run_bzr('branch source target --files-from source')
 
258
        self.assertPathExists('target/file1')
 
259
 
 
260
    def test_branch_files_from_hardlink(self):
 
261
        self.requireFeature(HardlinkFeature)
 
262
        source = self.make_branch_and_tree('source')
 
263
        self.build_tree(['source/file1'])
 
264
        source.add('file1')
 
265
        source.commit('added file')
 
266
        source.bzrdir.sprout('second')
 
267
        out, err = self.run_bzr('branch source target --files-from second'
 
268
                                ' --hardlink')
 
269
        source_stat = os.stat('source/file1')
 
270
        second_stat = os.stat('second/file1')
 
271
        target_stat = os.stat('target/file1')
 
272
        self.assertNotEqual(source_stat, target_stat)
 
273
        self.assertEqual(second_stat, target_stat)
 
274
 
 
275
    def test_branch_standalone(self):
 
276
        shared_repo = self.make_repository('repo', shared=True)
 
277
        self.example_branch('source')
 
278
        self.run_bzr('branch --standalone source repo/target')
 
279
        b = branch.Branch.open('repo/target')
 
280
        expected_repo_path = os.path.abspath('repo/target/.bzr/repository')
 
281
        self.assertEqual(strip_trailing_slash(b.repository.base),
 
282
            strip_trailing_slash(local_path_to_url(expected_repo_path)))
 
283
 
 
284
    def test_branch_no_tree(self):
 
285
        self.example_branch('source')
 
286
        self.run_bzr('branch --no-tree source target')
 
287
        self.assertPathDoesNotExist('target/hello')
 
288
        self.assertPathDoesNotExist('target/goodbye')
 
289
 
 
290
    def test_branch_into_existing_dir(self):
 
291
        self.example_branch('a')
 
292
        # existing dir with similar files but no .bzr dir
 
293
        self.build_tree_contents([('b/',)])
 
294
        self.build_tree_contents([('b/hello', 'bar')])  # different content
 
295
        self.build_tree_contents([('b/goodbye', 'baz')])# same content
 
296
        # fails without --use-existing-dir
 
297
        out,err = self.run_bzr('branch a b', retcode=3)
 
298
        self.assertEqual('', out)
 
299
        self.assertEqual('bzr: ERROR: Target directory "b" already exists.\n',
 
300
            err)
 
301
        # force operation
 
302
        self.run_bzr('branch a b --use-existing-dir')
 
303
        # check conflicts
 
304
        self.assertPathExists('b/hello.moved')
 
305
        self.assertPathDoesNotExist('b/godbye.moved')
 
306
        # we can't branch into branch
 
307
        out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
 
308
        self.assertEqual('', out)
 
309
        self.assertEqual('bzr: ERROR: Already a branch: "b".\n', err)
 
310
 
 
311
    def test_branch_bind(self):
 
312
        self.example_branch('a')
 
313
        out, err = self.run_bzr('branch a b --bind')
 
314
        self.assertEndsWith(err, "New branch bound to a\n")
 
315
        b = branch.Branch.open('b')
 
316
        self.assertEndsWith(b.get_bound_location(), '/a/')
 
317
 
 
318
    def test_branch_with_post_branch_init_hook(self):
 
319
        calls = []
 
320
        branch.Branch.hooks.install_named_hook('post_branch_init',
 
321
            calls.append, None)
 
322
        self.assertLength(0, calls)
 
323
        self.example_branch('a')
 
324
        self.assertLength(1, calls)
 
325
        self.run_bzr('branch a b')
 
326
        self.assertLength(2, calls)
 
327
 
 
328
    def test_checkout_with_post_branch_init_hook(self):
 
329
        calls = []
 
330
        branch.Branch.hooks.install_named_hook('post_branch_init',
 
331
            calls.append, None)
 
332
        self.assertLength(0, calls)
 
333
        self.example_branch('a')
 
334
        self.assertLength(1, calls)
 
335
        self.run_bzr('checkout a b')
 
336
        self.assertLength(2, calls)
 
337
 
 
338
    def test_lightweight_checkout_with_post_branch_init_hook(self):
 
339
        calls = []
 
340
        branch.Branch.hooks.install_named_hook('post_branch_init',
 
341
            calls.append, None)
 
342
        self.assertLength(0, calls)
 
343
        self.example_branch('a')
 
344
        self.assertLength(1, calls)
 
345
        self.run_bzr('checkout --lightweight a b')
 
346
        self.assertLength(2, calls)
 
347
 
 
348
    def test_branch_fetches_all_tags(self):
 
349
        builder = self.make_branch_builder('source')
 
350
        source = fixtures.build_branch_with_non_ancestral_rev(builder)
 
351
        source.tags.set_tag('tag-a', 'rev-2')
 
352
        source.get_config_stack().set('branch.fetch_tags', True)
 
353
        # Now source has a tag not in its ancestry.  Make a branch from it.
 
354
        self.run_bzr('branch source new-branch')
 
355
        new_branch = branch.Branch.open('new-branch')
 
356
        # The tag is present, and so is its revision.
 
357
        self.assertEqual('rev-2', new_branch.tags.lookup_tag('tag-a'))
 
358
        new_branch.repository.get_revision('rev-2')
 
359
 
 
360
 
 
361
class TestBranchStacked(tests.TestCaseWithTransport):
 
362
    """Tests for branch --stacked"""
 
363
 
 
364
    def assertRevisionInRepository(self, repo_path, revid):
 
365
        """Check that a revision is in a repo, disregarding stacking."""
 
366
        repo = controldir.ControlDir.open(repo_path).open_repository()
 
367
        self.assertTrue(repo.has_revision(revid))
 
368
 
 
369
    def assertRevisionNotInRepository(self, repo_path, revid):
 
370
        """Check that a revision is not in a repo, disregarding stacking."""
 
371
        repo = controldir.ControlDir.open(repo_path).open_repository()
 
372
        self.assertFalse(repo.has_revision(revid))
 
373
 
 
374
    def assertRevisionsInBranchRepository(self, revid_list, branch_path):
 
375
        repo = branch.Branch.open(branch_path).repository
 
376
        self.assertEqual(set(revid_list),
 
377
            repo.has_revisions(revid_list))
 
378
 
 
379
    def test_branch_stacked_branch_not_stacked(self):
 
380
        """Branching a stacked branch is not stacked by default"""
 
381
        # We have a mainline
 
382
        trunk_tree = self.make_branch_and_tree('target',
 
383
            format='1.9')
 
384
        trunk_tree.commit('mainline')
 
385
        # and a branch from it which is stacked
 
386
        branch_tree = self.make_branch_and_tree('branch',
 
387
            format='1.9')
 
388
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
389
        # with some work on it
 
390
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
 
391
        work_tree.commit('moar work plz')
 
392
        work_tree.branch.push(branch_tree.branch)
 
393
        # branching our local branch gives us a new stacked branch pointing at
 
394
        # mainline.
 
395
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
 
396
        self.assertEqual('', out)
 
397
        self.assertEqual('Branched 2 revisions.\n',
 
398
            err)
 
399
        # it should have preserved the branch format, and so it should be
 
400
        # capable of supporting stacking, but not actually have a stacked_on
 
401
        # branch configured
 
402
        self.assertRaises(errors.NotStacked,
 
403
            controldir.ControlDir.open('newbranch').open_branch().get_stacked_on_url)
 
404
 
 
405
    def test_branch_stacked_branch_stacked(self):
 
406
        """Asking to stack on a stacked branch does work"""
 
407
        # We have a mainline
 
408
        trunk_tree = self.make_branch_and_tree('target',
 
409
            format='1.9')
 
410
        trunk_revid = trunk_tree.commit('mainline')
 
411
        # and a branch from it which is stacked
 
412
        branch_tree = self.make_branch_and_tree('branch',
 
413
            format='1.9')
 
414
        branch_tree.branch.set_stacked_on_url(trunk_tree.branch.base)
 
415
        # with some work on it
 
416
        work_tree = trunk_tree.branch.bzrdir.sprout('local').open_workingtree()
 
417
        branch_revid = work_tree.commit('moar work plz')
 
418
        work_tree.branch.push(branch_tree.branch)
 
419
        # you can chain branches on from there
 
420
        out, err = self.run_bzr(['branch', 'branch', '--stacked', 'branch2'])
 
421
        self.assertEqual('', out)
 
422
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
423
            branch_tree.branch.base, err)
 
424
        self.assertEqual(branch_tree.branch.base,
 
425
            branch.Branch.open('branch2').get_stacked_on_url())
 
426
        branch2_tree = WorkingTree.open('branch2')
 
427
        branch2_revid = work_tree.commit('work on second stacked branch')
 
428
        work_tree.branch.push(branch2_tree.branch)
 
429
        self.assertRevisionInRepository('branch2', branch2_revid)
 
430
        self.assertRevisionsInBranchRepository(
 
431
            [trunk_revid, branch_revid, branch2_revid],
 
432
            'branch2')
 
433
 
 
434
    def test_branch_stacked(self):
 
435
        # We have a mainline
 
436
        trunk_tree = self.make_branch_and_tree('mainline',
 
437
            format='1.9')
 
438
        original_revid = trunk_tree.commit('mainline')
 
439
        self.assertRevisionInRepository('mainline', original_revid)
 
440
        # and a branch from it which is stacked
 
441
        out, err = self.run_bzr(['branch', '--stacked', 'mainline',
 
442
            'newbranch'])
 
443
        self.assertEqual('', out)
 
444
        self.assertEqual('Created new stacked branch referring to %s.\n' %
 
445
            trunk_tree.branch.base, err)
 
446
        self.assertRevisionNotInRepository('newbranch', original_revid)
 
447
        new_branch = branch.Branch.open('newbranch')
 
448
        self.assertEqual(trunk_tree.branch.base,
 
449
                         new_branch.get_stacked_on_url())
 
450
 
 
451
    def test_branch_stacked_from_smart_server(self):
 
452
        # We can branch stacking on a smart server
 
453
        self.transport_server = test_server.SmartTCPServer_for_testing
 
454
        trunk = self.make_branch('mainline', format='1.9')
 
455
        out, err = self.run_bzr(
 
456
            ['branch', '--stacked', self.get_url('mainline'), 'shallow'])
 
457
 
 
458
    def test_branch_stacked_from_non_stacked_format(self):
 
459
        """The origin format doesn't support stacking"""
 
460
        trunk = self.make_branch('trunk', format='pack-0.92')
 
461
        out, err = self.run_bzr(
 
462
            ['branch', '--stacked', 'trunk', 'shallow'])
 
463
        # We should notify the user that we upgraded their format
 
464
        self.assertEqualDiff(
 
465
            'Source repository format does not support stacking, using format:\n'
 
466
            '  Packs 5 (adds stacking support, requires bzr 1.6)\n'
 
467
            'Source branch format does not support stacking, using format:\n'
 
468
            '  Branch format 7\n'
 
469
            'Doing on-the-fly conversion from RepositoryFormatKnitPack1() to RepositoryFormatKnitPack5().\n'
 
470
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
 
471
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
472
            err)
 
473
 
 
474
    def test_branch_stacked_from_rich_root_non_stackable(self):
 
475
        trunk = self.make_branch('trunk', format='rich-root-pack')
 
476
        out, err = self.run_bzr(
 
477
            ['branch', '--stacked', 'trunk', 'shallow'])
 
478
        # We should notify the user that we upgraded their format
 
479
        self.assertEqualDiff(
 
480
            'Source repository format does not support stacking, using format:\n'
 
481
            '  Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)\n'
 
482
            'Source branch format does not support stacking, using format:\n'
 
483
            '  Branch format 7\n'
 
484
            'Doing on-the-fly conversion from RepositoryFormatKnitPack4() to RepositoryFormatKnitPack5RichRoot().\n'
 
485
            'This may take some time. Upgrade the repositories to the same format for better performance.\n'
 
486
            'Created new stacked branch referring to %s.\n' % (trunk.base,),
 
487
            err)
 
488
 
 
489
 
 
490
class TestSmartServerBranching(tests.TestCaseWithTransport):
 
491
 
 
492
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
 
493
        self.setup_smart_server_with_call_log()
 
494
        t = self.make_branch_and_tree('from')
 
495
        for count in range(9):
 
496
            t.commit(message='commit %d' % count)
 
497
        self.reset_smart_call_log()
 
498
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
499
            self.get_url('target')])
 
500
        # This figure represent the amount of work to perform this use case. It
 
501
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
502
        # being too low. If rpc_count increases, more network roundtrips have
 
503
        # become necessary for this use case. Please do not adjust this number
 
504
        # upwards without agreement from bzr's network support maintainers.
 
505
        self.assertLength(2, self.hpss_connections)
 
506
        self.assertLength(33, self.hpss_calls)
 
507
        self.expectFailure("branching to the same branch requires VFS access",
 
508
            self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
 
509
 
 
510
    def test_branch_from_trivial_branch_streaming_acceptance(self):
 
511
        self.setup_smart_server_with_call_log()
 
512
        t = self.make_branch_and_tree('from')
 
513
        for count in range(9):
 
514
            t.commit(message='commit %d' % count)
 
515
        self.reset_smart_call_log()
 
516
        out, err = self.run_bzr(['branch', self.get_url('from'),
 
517
            'local-target'])
 
518
        # This figure represent the amount of work to perform this use case. It
 
519
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
520
        # being too low. If rpc_count increases, more network roundtrips have
 
521
        # become necessary for this use case. Please do not adjust this number
 
522
        # upwards without agreement from bzr's network support maintainers.
 
523
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
 
524
        self.assertLength(10, self.hpss_calls)
 
525
        self.assertLength(1, self.hpss_connections)
 
526
 
 
527
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
 
528
        self.setup_smart_server_with_call_log()
 
529
        t = self.make_branch_and_tree('trunk')
 
530
        for count in range(8):
 
531
            t.commit(message='commit %d' % count)
 
532
        tree2 = t.branch.bzrdir.sprout('feature', stacked=True
 
533
            ).open_workingtree()
 
534
        local_tree = t.branch.bzrdir.sprout('local-working').open_workingtree()
 
535
        local_tree.commit('feature change')
 
536
        local_tree.branch.push(tree2.branch)
 
537
        self.reset_smart_call_log()
 
538
        out, err = self.run_bzr(['branch', self.get_url('feature'),
 
539
            'local-target'])
 
540
        # This figure represent the amount of work to perform this use case. It
 
541
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
542
        # being too low. If rpc_count increases, more network roundtrips have
 
543
        # become necessary for this use case. Please do not adjust this number
 
544
        # upwards without agreement from bzr's network support maintainers.
 
545
        self.assertLength(15, self.hpss_calls)
 
546
        self.assertLength(1, self.hpss_connections)
 
547
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
 
548
 
 
549
    def test_branch_from_branch_with_tags(self):
 
550
        self.setup_smart_server_with_call_log()
 
551
        builder = self.make_branch_builder('source')
 
552
        source = fixtures.build_branch_with_non_ancestral_rev(builder)
 
553
        source.get_config_stack().set('branch.fetch_tags', True)
 
554
        source.tags.set_tag('tag-a', 'rev-2')
 
555
        source.tags.set_tag('tag-missing', 'missing-rev')
 
556
        # Now source has a tag not in its ancestry.  Make a branch from it.
 
557
        self.reset_smart_call_log()
 
558
        out, err = self.run_bzr(['branch', self.get_url('source'), 'target'])
 
559
        # This figure represent the amount of work to perform this use case. It
 
560
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
561
        # being too low. If rpc_count increases, more network roundtrips have
 
562
        # become necessary for this use case. Please do not adjust this number
 
563
        # upwards without agreement from bzr's network support maintainers.
 
564
        self.assertLength(10, self.hpss_calls)
 
565
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
 
566
        self.assertLength(1, self.hpss_connections)
 
567
 
 
568
    def test_branch_to_stacked_from_trivial_branch_streaming_acceptance(self):
 
569
        self.setup_smart_server_with_call_log()
 
570
        t = self.make_branch_and_tree('from')
 
571
        for count in range(9):
 
572
            t.commit(message='commit %d' % count)
 
573
        self.reset_smart_call_log()
 
574
        out, err = self.run_bzr(['branch', '--stacked', self.get_url('from'),
 
575
            'local-target'])
 
576
        # XXX: the number of hpss calls for this case isn't deterministic yet,
 
577
        # so we can't easily assert about the number of calls.
 
578
        #self.assertLength(XXX, self.hpss_calls)
 
579
        # We can assert that none of the calls were readv requests for rix
 
580
        # files, though (demonstrating that at least get_parent_map calls are
 
581
        # not using VFS RPCs).
 
582
        readvs_of_rix_files = [
 
583
            c for c in self.hpss_calls
 
584
            if c.call.method == 'readv' and c.call.args[-1].endswith('.rix')]
 
585
        self.assertLength(1, self.hpss_connections)
 
586
        self.assertLength(0, readvs_of_rix_files)
 
587
        self.expectFailure("branching to stacked requires VFS access",
 
588
            self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
 
589
 
 
590
 
 
591
class TestRemoteBranch(TestCaseWithSFTPServer):
 
592
 
 
593
    def setUp(self):
 
594
        super(TestRemoteBranch, self).setUp()
 
595
        tree = self.make_branch_and_tree('branch')
 
596
        self.build_tree_contents([('branch/file', 'file content\n')])
 
597
        tree.add('file')
 
598
        tree.commit('file created')
 
599
 
 
600
    def test_branch_local_remote(self):
 
601
        self.run_bzr(['branch', 'branch', self.get_url('remote')])
 
602
        t = self.get_transport()
 
603
        # Ensure that no working tree what created remotely
 
604
        self.assertFalse(t.has('remote/file'))
 
605
 
 
606
    def test_branch_remote_remote(self):
 
607
        # Light cheat: we access the branch remotely
 
608
        self.run_bzr(['branch', self.get_url('branch'),
 
609
                      self.get_url('remote')])
 
610
        t = self.get_transport()
 
611
        # Ensure that no working tree what created remotely
 
612
        self.assertFalse(t.has('remote/file'))
 
613
 
 
614
 
 
615
class TestDeprecatedAliases(tests.TestCaseWithTransport):
 
616
 
 
617
    def test_deprecated_aliases(self):
 
618
        """bzr branch can be called clone or get, but those names are
 
619
        deprecated.
 
620
 
 
621
        See bug 506265.
 
622
        """
 
623
        for command in ['clone', 'get']:
 
624
            run_script(self, """
 
625
            $ bzr %(command)s A B
 
626
            2>The command 'bzr %(command)s' has been deprecated in bzr 2.4. Please use 'bzr branch' instead.
 
627
            2>bzr: ERROR: Not a branch...
 
628
            """ % locals())
 
629
 
 
630
 
 
631
class TestBranchParentLocation(test_switch.TestSwitchParentLocationBase):
 
632
 
 
633
    def _checkout_and_branch(self, option=''):
 
634
        self.script_runner.run_script(self, '''
 
635
                $ bzr checkout %(option)s repo/trunk checkout
 
636
                $ cd checkout
 
637
                $ bzr branch --switch ../repo/trunk ../repo/branched
 
638
                2>Branched 0 revisions.
 
639
                2>Tree is up to date at revision 0.
 
640
                2>Switched to branch:...branched...
 
641
                $ cd ..
 
642
                ''' % locals())
 
643
        bound_branch = branch.Branch.open_containing('checkout')[0]
 
644
        master_branch = branch.Branch.open_containing('repo/branched')[0]
 
645
        return (bound_branch, master_branch)
 
646
 
 
647
    def test_branch_switch_parent_lightweight(self):
 
648
        """Lightweight checkout using bzr branch --switch."""
 
649
        bb, mb = self._checkout_and_branch(option='--lightweight')
 
650
        self.assertParent('repo/trunk', bb)
 
651
        self.assertParent('repo/trunk', mb)
 
652
 
 
653
    def test_branch_switch_parent_heavyweight(self):
 
654
        """Heavyweight checkout using bzr branch --switch."""
 
655
        bb, mb = self._checkout_and_branch()
 
656
        self.assertParent('repo/trunk', bb)
 
657
        self.assertParent('repo/trunk', mb)