~bzr-pqm/bzr/bzr.dev

2524.1.1 by Aaron Bentley
Revert broken changes
1
# Copyright (C) 2007 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2524.1.1 by Aaron Bentley
Revert broken changes
16
17
"""Tests for Branch.sprout()"""
18
3763.9.4 by Daniel Clemente
New test for utf-8 symlinks in BzrDir.sprout
19
import os
2524.1.1 by Aaron Bentley
Revert broken changes
20
from bzrlib import (
3834.5.1 by Andrew Bennetts
Improve test_sprout.
21
    branch as _mod_branch,
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
22
    errors,
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
23
    osutils,
2524.1.1 by Aaron Bentley
Revert broken changes
24
    remote,
2487.2.4 by Aaron Bentley
Add test to ensure we can branch from repository revisions
25
    revision as _mod_revision,
2524.1.1 by Aaron Bentley
Revert broken changes
26
    tests,
27
    )
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
28
from bzrlib.tests import (
29
    features,
30
    )
4523.1.1 by Martin Pool
Rename tests.branch_implementations to per_branch
31
from bzrlib.tests.per_branch import TestCaseWithBranch
2524.1.1 by Aaron Bentley
Revert broken changes
32
33
34
class TestSprout(TestCaseWithBranch):
35
36
    def test_sprout_branch_nickname(self):
37
        # test the nick name is reset always
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
38
        raise tests.TestSkipped('XXX branch sprouting is not yet tested.')
2524.1.1 by Aaron Bentley
Revert broken changes
39
40
    def test_sprout_branch_parent(self):
41
        source = self.make_branch('source')
42
        target = source.bzrdir.sprout(self.get_url('target')).open_branch()
43
        self.assertEqual(source.bzrdir.root_transport.base, target.get_parent())
44
3834.5.2 by John Arbash Meinel
Track down the various BranchFormats that weren't setting the branch format as part of the _matchingbzrdir format.
45
    def test_sprout_uses_bzrdir_branch_format(self):
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
46
        # branch.sprout(bzrdir) is defined as using the branch format selected
47
        # by bzrdir; format preservation is achieved by parameterising the
48
        # bzrdir during bzrdir.sprout, which is where stacking compatibility
49
        # checks are done. So this test tests that each implementation of
50
        # Branch.sprout delegates appropriately to the bzrdir which the
51
        # branch is being created in, rather than testing that the result is
52
        # in the format that we are testing (which is what would happen if
53
        # the branch did not delegate appropriately).
3834.5.1 by Andrew Bennetts
Improve test_sprout.
54
        if isinstance(self.branch_format, _mod_branch.BranchReferenceFormat):
55
            raise tests.TestNotApplicable('cannot sprout to a reference')
56
        # Start with a format that is unlikely to be the target format
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
57
        # We call the super class to allow overriding the format of creation)
3834.5.1 by Andrew Bennetts
Improve test_sprout.
58
        source = tests.TestCaseWithTransport.make_branch(self, 'old-branch',
5582.10.96 by Jelmer Vernooij
Support running without plugins.
59
                                                         format='knit')
3834.5.2 by John Arbash Meinel
Track down the various BranchFormats that weren't setting the branch format as part of the _matchingbzrdir format.
60
        target_bzrdir = self.make_bzrdir('target')
61
        target_bzrdir.create_repository()
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
62
        result_format = self.branch_format
63
        if isinstance(target_bzrdir, remote.RemoteBzrDir):
64
            # for a remote bzrdir, we need to parameterise it with a branch
65
            # format, as, after creation, the newly opened remote objects
66
            # do not have one unless a branch was created at the time.
67
            # We use branch format 6 because its not the default, and its not
68
            # metaweave either.
69
            target_bzrdir._format.set_branch_format(_mod_branch.BzrBranchFormat6())
70
            result_format = target_bzrdir._format.get_branch_format()
3834.5.1 by Andrew Bennetts
Improve test_sprout.
71
        target = source.sprout(target_bzrdir)
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
72
        if isinstance(target, remote.RemoteBranch):
73
            # we have to look at the real branch to see whether RemoteBranch
74
            # did the right thing.
75
            target._ensure_real()
76
            target = target._real_branch
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
77
        if isinstance(result_format, remote.RemoteBranchFormat):
78
            # Unwrap a parameterised RemoteBranchFormat for comparison.
79
            result_format = result_format._custom_format
4005.2.1 by Robert Collins
Fix RemoteBranch to be used correctly in tests using bzr+ssh, to fire off Branch hooks correctly, and improve the branch_implementations tests to check that making a branch gets the right format under test.
80
        self.assertIs(result_format.__class__, target._format.__class__)
2524.1.1 by Aaron Bentley
Revert broken changes
81
82
    def test_sprout_partial(self):
83
        # test sprouting with a prefix of the revision-history.
84
        # also needs not-on-revision-history behaviour defined.
85
        wt_a = self.make_branch_and_tree('a')
86
        self.build_tree(['a/one'])
87
        wt_a.add(['one'])
88
        wt_a.commit('commit one', rev_id='1')
89
        self.build_tree(['a/two'])
90
        wt_a.add(['two'])
91
        wt_a.commit('commit two', rev_id='2')
92
        repo_b = self.make_repository('b')
93
        repo_a = wt_a.branch.repository
94
        repo_a.copy_content_into(repo_b)
95
        br_b = wt_a.branch.sprout(repo_b.bzrdir, revision_id='1')
96
        self.assertEqual('1', br_b.last_revision())
97
98
    def test_sprout_partial_not_in_revision_history(self):
99
        """We should be able to sprout from any revision in ancestry."""
100
        wt = self.make_branch_and_tree('source')
101
        self.build_tree(['source/a'])
102
        wt.add('a')
103
        wt.commit('rev1', rev_id='rev1')
104
        wt.commit('rev2-alt', rev_id='rev2-alt')
105
        wt.set_parent_ids(['rev1'])
106
        wt.branch.set_last_revision_info(1, 'rev1')
107
        wt.commit('rev2', rev_id='rev2')
108
        wt.set_parent_ids(['rev2', 'rev2-alt'])
109
        wt.commit('rev3', rev_id='rev3')
110
111
        repo = self.make_repository('target')
112
        repo.fetch(wt.branch.repository)
113
        branch2 = wt.branch.sprout(repo.bzrdir, revision_id='rev2-alt')
114
        self.assertEqual((2, 'rev2-alt'), branch2.last_revision_info())
6165.4.6 by Jelmer Vernooij
Avoid more uses of revision_history.
115
        self.assertEqual('rev2-alt', branch2.last_revision())
2487.2.4 by Aaron Bentley
Add test to ensure we can branch from repository revisions
116
5535.3.38 by Andrew Bennetts
Remove XXX, add some test coverage to prove it works.
117
    def test_sprout_preserves_tags(self):
118
        """Sprout preserves tags, even tags of absent revisions."""
119
        try:
120
            builder = self.make_branch_builder('source')
121
        except errors.UninitializableFormat:
122
            raise tests.TestSkipped('Uninitializable branch format')
123
        builder.build_commit(message="Rev 1", rev_id='rev-1')
124
        source = builder.get_branch()
125
        try:
126
            source.tags.set_tag('tag-a', 'missing-rev')
6123.9.10 by Jelmer Vernooij
Improve tag handling.
127
        except (errors.TagsNotSupported, errors.GhostTagsNotSupported):
5535.3.38 by Andrew Bennetts
Remove XXX, add some test coverage to prove it works.
128
            raise tests.TestNotApplicable(
6123.9.10 by Jelmer Vernooij
Improve tag handling.
129
                'Branch format does not support tags or tags to ghosts.')
5535.3.38 by Andrew Bennetts
Remove XXX, add some test coverage to prove it works.
130
        # Now source has a tag pointing to an absent revision.  Sprout it.
131
        target_bzrdir = self.make_repository('target').bzrdir
132
        new_branch = source.sprout(target_bzrdir)
133
        # The tag is present in the target
134
        self.assertEqual('missing-rev', new_branch.tags.lookup_tag('tag-a'))
135
2487.2.4 by Aaron Bentley
Add test to ensure we can branch from repository revisions
136
    def test_sprout_from_any_repo_revision(self):
137
        """We should be able to sprout from any revision."""
138
        wt = self.make_branch_and_tree('source')
139
        self.build_tree(['source/a'])
140
        wt.add('a')
141
        wt.commit('rev1a', rev_id='rev1a')
142
        # simulated uncommit
143
        wt.branch.set_last_revision_info(0, _mod_revision.NULL_REVISION)
2598.5.3 by Aaron Bentley
Push NULL_REVISION deeper
144
        wt.set_last_revision(_mod_revision.NULL_REVISION)
2796.1.4 by Aaron Bentley
Fix up various test cases
145
        wt.revert()
2487.2.4 by Aaron Bentley
Add test to ensure we can branch from repository revisions
146
        wt.commit('rev1b', rev_id='rev1b')
147
        wt2 = wt.bzrdir.sprout('target',
148
            revision_id='rev1a').open_workingtree()
149
        self.assertEqual('rev1a', wt2.last_revision())
5784.1.3 by Martin Pool
Switch away from using failUnlessExists and failIfExists
150
        self.assertPathExists('target/a')
3763.9.4 by Daniel Clemente
New test for utf-8 symlinks in BzrDir.sprout
151
3763.9.7 by Daniel Clemente
Tested Unicode target rather than always trying to create it in UTF-8. Test renamed
152
    def test_sprout_with_unicode_symlink(self):
3763.9.8 by Daniel Clemente
Broken lines, and prepended # before bug numbers
153
        # this tests bug #272444
3763.9.11 by Daniel Clemente
More detailed comment and in broken line
154
        # Since the trigger function seems to be set_parent_trees, there exists
155
        # also a similar test, with name test_unicode_symlink, in class
4523.1.4 by Martin Pool
Rename remaining *_implementations tests
156
        # TestSetParents at file per_workingtree/test_parents.py
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
157
        self.requireFeature(features.SymlinkFeature)
158
        self.requireFeature(features.UnicodeFilenameFeature)
3763.9.4 by Daniel Clemente
New test for utf-8 symlinks in BzrDir.sprout
159
160
        tree = self.make_branch_and_tree('tree1')
161
3763.9.9 by Daniel Clemente
Used a greek omega instead of an accented 'o' to avoid combining characters
162
        # The link points to a file whose name is an omega
163
        # U+03A9 GREEK CAPITAL LETTER OMEGA
164
        # UTF-8: ce a9  UTF-16BE: 03a9  Decimal: Ω
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
165
        target = u'\u03a9'
166
        link_name = u'\N{Euro Sign}link'
167
        os.symlink(target, 'tree1/' + link_name)
168
        tree.add([link_name],['link-id'])
3763.9.4 by Daniel Clemente
New test for utf-8 symlinks in BzrDir.sprout
169
4095.3.1 by Vincent Ladeuil
Fix #339055 and #277444 by handling non ascii symlink targets.
170
        revision = tree.commit('added a link to a Unicode target')
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
171
        tree.bzrdir.sprout('dest')
4241.14.23 by Vincent Ladeuil
NEWS entry and final cleanup before submission.
172
        self.assertEqual(target, osutils.readlink('dest/' + link_name))
4241.14.12 by Vincent Ladeuil
Far too many modifications for a single commit, need to restart.
173
        tree.lock_read()
174
        self.addCleanup(tree.unlock)
175
        # Check that the symlink target is safely round-tripped in the trees.
176
        self.assertEqual(target, tree.get_symlink_target('link-id'))
177
        self.assertEqual(target,
178
                         tree.basis_tree().get_symlink_target('link-id'))
3763.9.4 by Daniel Clemente
New test for utf-8 symlinks in BzrDir.sprout
179
4266.3.6 by Jelmer Vernooij
Add test for handling ghosts in Branch._synchronize_history if the revision that's being cloned is not the tip.
180
    def test_sprout_with_ghost_in_mainline(self):
181
        tree = self.make_branch_and_tree('tree1')
6164.2.1 by Jelmer Vernooij
Skip tests if the repository doesn't support ghosts.
182
        if not tree.branch.repository._format.supports_ghosts:
183
            raise tests.TestNotApplicable(
184
                "repository format does not support ghosts in mainline")
4266.3.6 by Jelmer Vernooij
Add test for handling ghosts in Branch._synchronize_history if the revision that's being cloned is not the tip.
185
        tree.set_parent_ids(["spooky"], allow_leftmost_as_ghost=True)
186
        tree.add('')
187
        tree.commit('msg1', rev_id='rev1')
188
        tree.commit('msg2', rev_id='rev2')
189
        tree.bzrdir.sprout('target', revision_id='rev1')
190
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
191
    def assertBranchHookBranchIsStacked(self, pre_change_params):
192
        # Just calling will either succeed or fail.
193
        pre_change_params.branch.get_stacked_on_url()
194
        self.hook_calls.append(pre_change_params)
195
196
    def test_sprout_stacked_hooks_get_stacked_branch(self):
197
        tree = self.make_branch_and_tree('source')
198
        tree.commit('a commit')
199
        revid = tree.commit('a second commit')
200
        source = tree.branch
201
        target_transport = self.get_transport('target')
202
        self.hook_calls = []
203
        _mod_branch.Branch.hooks.install_named_hook("pre_change_branch_tip",
204
            self.assertBranchHookBranchIsStacked, None)
205
        try:
206
            dir = source.bzrdir.sprout(target_transport.base,
207
                source.last_revision(), possible_transports=[target_transport],
208
                source_branch=source, stacked=True)
6164.2.8 by Jelmer Vernooij
Move ex_stacked_on
209
        except errors.UnstackableBranchFormat:
5582.9.8 by Jelmer Vernooij
Avoid specifying format 4. Rather, check for consistency with the branch format's own information.
210
            if not self.branch_format.supports_stacking():
211
                raise tests.TestNotApplicable(
212
                    "Format doesn't auto stack successfully.")
4070.3.1 by Robert Collins
Alter branch sprouting with an alternate fix for stacked branches that does not require multiple copy_content_into and set_parent calls, reducing IO and round trips.
213
            else:
214
                raise
215
        result = dir.open_branch()
216
        self.assertEqual(revid, result.last_revision())
217
        self.assertEqual(source.base, result.get_stacked_on_url())
218
        # Smart servers invoke hooks on both sides
219
        if isinstance(result, remote.RemoteBranch):
220
            expected_calls = 2
221
        else:
222
            expected_calls = 1
223
        self.assertEqual(expected_calls, len(self.hook_calls))
224