~bzr-pqm/bzr/bzr.dev

« 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-2010 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
22
22
from bzrlib import (
23
23
    branch,
24
24
    bzrdir,
 
25
    controldir,
25
26
    errors,
26
 
    repository,
27
27
    revision as _mod_revision,
 
28
    tests,
28
29
    )
29
30
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit1
30
 
from bzrlib.tests.blackbox import ExternalBase
31
31
from bzrlib.tests import (
32
 
    KnownFailure,
 
32
    fixtures,
 
33
    test_server,
 
34
    )
 
35
from bzrlib.tests.features import (
33
36
    HardlinkFeature,
34
 
    test_server,
35
37
    )
 
38
from bzrlib.tests.blackbox import test_switch
 
39
from bzrlib.tests.matchers import ContainsNoVfsCalls
36
40
from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 
41
from bzrlib.tests.script import run_script
37
42
from bzrlib.urlutils import local_path_to_url, strip_trailing_slash
38
43
from bzrlib.workingtree import WorkingTree
39
44
 
40
45
 
41
 
class TestBranch(ExternalBase):
 
46
class TestBranch(tests.TestCaseWithTransport):
42
47
 
43
 
    def example_branch(self, path='.'):
44
 
        tree = self.make_branch_and_tree(path)
 
48
    def example_branch(self, path='.', format=None):
 
49
        tree = self.make_branch_and_tree(path, format=format)
45
50
        self.build_tree_contents([(path + '/hello', 'foo')])
46
51
        tree.add('hello')
47
52
        tree.commit(message='setup')
48
53
        self.build_tree_contents([(path + '/goodbye', 'baz')])
49
54
        tree.add('goodbye')
50
55
        tree.commit(message='setup')
 
56
        return tree
51
57
 
52
58
    def test_branch(self):
53
59
        """Branch from one branch to another."""
59
65
        self.assertFalse(b._transport.has('branch-name'))
60
66
        b.bzrdir.open_workingtree().commit(message='foo', allow_pointless=True)
61
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
 
62
120
    def test_branch_switch_no_branch(self):
63
121
        # No branch in the current directory:
64
122
        #  => new branch will be created, but switch fails
103
161
        #  => new branch will be created and checkout bound to the new branch
104
162
        self.example_branch('a')
105
163
        self.run_bzr('checkout a current')
106
 
        out, err = self.run_bzr('branch --switch ../a ../b', working_dir='current')
 
164
        out, err = self.run_bzr('branch --switch ../a ../b',
 
165
                                working_dir='current')
107
166
        a = branch.Branch.open('a')
108
167
        b = branch.Branch.open('b')
109
168
        self.assertEqual(a.last_revision(), b.last_revision())
117
176
        #     the new branch
118
177
        self.example_branch('a')
119
178
        self.run_bzr('checkout --lightweight a current')
120
 
        out, err = self.run_bzr('branch --switch ../a ../b', working_dir='current')
 
179
        out, err = self.run_bzr('branch --switch ../a ../b',
 
180
                                working_dir='current')
121
181
        a = branch.Branch.open('a')
122
182
        b = branch.Branch.open('b')
123
183
        self.assertEqual(a.last_revision(), b.last_revision())
134
194
 
135
195
        def make_shared_tree(path):
136
196
            shared_repo.bzrdir.root_transport.mkdir(path)
137
 
            shared_repo.bzrdir.create_branch_convenience('repo/' + path)
 
197
            controldir.ControlDir.create_branch_convenience('repo/' + path)
138
198
            return WorkingTree.open('repo/' + path)
139
199
        tree_a = make_shared_tree('a')
140
200
        self.build_tree(['repo/a/file'])
174
234
        target_stat = os.stat('target/file1')
175
235
        self.assertEqual(source_stat, target_stat)
176
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
 
177
260
    def test_branch_standalone(self):
178
261
        shared_repo = self.make_repository('repo', shared=True)
179
262
        self.example_branch('source')
186
269
    def test_branch_no_tree(self):
187
270
        self.example_branch('source')
188
271
        self.run_bzr('branch --no-tree source target')
189
 
        self.failIfExists('target/hello')
190
 
        self.failIfExists('target/goodbye')
 
272
        self.assertPathDoesNotExist('target/hello')
 
273
        self.assertPathDoesNotExist('target/goodbye')
191
274
 
192
275
    def test_branch_into_existing_dir(self):
193
276
        self.example_branch('a')
203
286
        # force operation
204
287
        self.run_bzr('branch a b --use-existing-dir')
205
288
        # check conflicts
206
 
        self.failUnlessExists('b/hello.moved')
207
 
        self.failIfExists('b/godbye.moved')
 
289
        self.assertPathExists('b/hello.moved')
 
290
        self.assertPathDoesNotExist('b/godbye.moved')
208
291
        # we can't branch into branch
209
292
        out,err = self.run_bzr('branch a b --use-existing-dir', retcode=3)
210
293
        self.assertEqual('', out)
247
330
        self.run_bzr('checkout --lightweight a b')
248
331
        self.assertLength(2, calls)
249
332
 
250
 
 
251
 
class TestBranchStacked(ExternalBase):
 
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):
252
347
    """Tests for branch --stacked"""
253
348
 
254
349
    def assertRevisionInRepository(self, repo_path, revid):
255
 
        """Check that a revision is in a repository, disregarding stacking."""
 
350
        """Check that a revision is in a repo, disregarding stacking."""
256
351
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
257
352
        self.assertTrue(repo.has_revision(revid))
258
353
 
259
354
    def assertRevisionNotInRepository(self, repo_path, revid):
260
 
        """Check that a revision is not in a repository, disregarding stacking."""
 
355
        """Check that a revision is not in a repo, disregarding stacking."""
261
356
        repo = bzrdir.BzrDir.open(repo_path).open_repository()
262
357
        self.assertFalse(repo.has_revision(revid))
263
358
 
284
379
        # mainline.
285
380
        out, err = self.run_bzr(['branch', 'branch', 'newbranch'])
286
381
        self.assertEqual('', out)
287
 
        self.assertEqual('Branched 2 revision(s).\n',
 
382
        self.assertEqual('Branched 2 revisions.\n',
288
383
            err)
289
384
        # it should have preserved the branch format, and so it should be
290
385
        # capable of supporting stacking, but not actually have a stacked_on
335
430
            trunk_tree.branch.base, err)
336
431
        self.assertRevisionNotInRepository('newbranch', original_revid)
337
432
        new_branch = branch.Branch.open('newbranch')
338
 
        self.assertEqual(trunk_tree.branch.base, new_branch.get_stacked_on_url())
 
433
        self.assertEqual(trunk_tree.branch.base,
 
434
                         new_branch.get_stacked_on_url())
339
435
 
340
436
    def test_branch_stacked_from_smart_server(self):
341
437
        # We can branch stacking on a smart server
376
472
            err)
377
473
 
378
474
 
379
 
class TestSmartServerBranching(ExternalBase):
 
475
class TestSmartServerBranching(tests.TestCaseWithTransport):
380
476
 
381
477
    def test_branch_from_trivial_branch_to_same_server_branch_acceptance(self):
382
478
        self.setup_smart_server_with_call_log()
391
487
        # being too low. If rpc_count increases, more network roundtrips have
392
488
        # become necessary for this use case. Please do not adjust this number
393
489
        # upwards without agreement from bzr's network support maintainers.
394
 
        self.assertLength(38, self.hpss_calls)
 
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)
395
494
 
396
495
    def test_branch_from_trivial_branch_streaming_acceptance(self):
397
496
        self.setup_smart_server_with_call_log()
406
505
        # being too low. If rpc_count increases, more network roundtrips have
407
506
        # become necessary for this use case. Please do not adjust this number
408
507
        # upwards without agreement from bzr's network support maintainers.
 
508
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
409
509
        self.assertLength(10, self.hpss_calls)
 
510
        self.assertLength(1, self.hpss_connections)
410
511
 
411
512
    def test_branch_from_trivial_stacked_branch_streaming_acceptance(self):
412
513
        self.setup_smart_server_with_call_log()
427
528
        # become necessary for this use case. Please do not adjust this number
428
529
        # upwards without agreement from bzr's network support maintainers.
429
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)
430
574
 
431
575
 
432
576
class TestRemoteBranch(TestCaseWithSFTPServer):
452
596
        # Ensure that no working tree what created remotely
453
597
        self.assertFalse(t.has('remote/file'))
454
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)