/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

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