~bzr-pqm/bzr/bzr.dev

4988.10.5 by John Arbash Meinel
Merge bzr.dev 5021 to resolve NEWS
1
# Copyright (C) 2006-2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
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
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
16
17
"""Tests for branch.pull behaviour."""
18
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
19
from bzrlib import (
20
    branch,
21
    bzrdir,
22
    errors,
23
    memorytree,
24
    revision,
25
    )
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
26
from bzrlib.tests import (
27
    fixtures,
28
    per_branch,
29
    TestNotApplicable,
30
    )
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
31
32
33
class TestPull(per_branch.TestCaseWithBranch):
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
34
35
    def test_pull_convergence_simple(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
36
        # when revisions are pulled, the left-most accessible parents must
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
37
        # become the revision-history.
38
        parent = self.make_branch_and_tree('parent')
39
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
40
        mine = parent.bzrdir.sprout('mine').open_workingtree()
41
        mine.commit('my change', rev_id='M1', allow_pointless=True)
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
42
        parent.merge_from_branch(mine.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
43
        parent.commit('merge my change', rev_id='P2')
44
        mine.pull(parent.branch)
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
45
        self.assertEqual('P2', mine.branch.last_revision())
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
46
47
    def test_pull_merged_indirect(self):
48
        # it should be possible to do a pull from one branch into another
49
        # when the tip of the target was merged into the source branch
50
        # via a third branch - so its buried in the ancestry and is not
51
        # directly accessible.
52
        parent = self.make_branch_and_tree('parent')
53
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
54
        mine = parent.bzrdir.sprout('mine').open_workingtree()
55
        mine.commit('my change', rev_id='M1', allow_pointless=True)
56
        other = parent.bzrdir.sprout('other').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
57
        other.merge_from_branch(mine.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
58
        other.commit('merge my change', rev_id='O2')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
59
        parent.merge_from_branch(other.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
60
        parent.commit('merge other', rev_id='P2')
61
        mine.pull(parent.branch)
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
62
        self.assertEqual('P2', mine.branch.last_revision())
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
63
64
    def test_pull_updates_checkout_and_master(self):
65
        """Pulling into a checkout updates the checkout and the master branch"""
66
        master_tree = self.make_branch_and_tree('master')
67
        rev1 = master_tree.commit('master')
68
        checkout = master_tree.branch.create_checkout('checkout')
69
70
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
71
        rev2 = other.commit('other commit')
72
        # now pull, which should update both checkout and master.
73
        checkout.branch.pull(other.branch)
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
74
        self.assertEqual(rev2, checkout.branch.last_revision())
75
        self.assertEqual(rev2, master_tree.branch.last_revision())
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
76
4056.6.3 by Gary van der Merwe
Add local args to pull methods, and add more tests
77
    def test_pull_local_updates_checkout_only(self):
78
        """Pulling --local into a checkout updates the checkout and not the
79
        master branch"""
80
        master_tree = self.make_branch_and_tree('master')
81
        rev1 = master_tree.commit('master')
82
        checkout = master_tree.branch.create_checkout('checkout')
83
84
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
85
        rev2 = other.commit('other commit')
4335.1.1 by Ian Clatworthy
(igc) pull --local (Gary van der Merwe)
86
        # now pull local, which should update checkout but not master.
4056.6.3 by Gary van der Merwe
Add local args to pull methods, and add more tests
87
        checkout.branch.pull(other.branch, local = True)
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
88
        self.assertEqual(rev2, checkout.branch.last_revision())
89
        self.assertEqual(rev1, master_tree.branch.last_revision())
4056.6.3 by Gary van der Merwe
Add local args to pull methods, and add more tests
90
91
    def test_pull_local_raises_LocalRequiresBoundBranch_on_unbound(self):
92
        """Pulling --local into a branch that is not bound should fail."""
93
        master_tree = self.make_branch_and_tree('branch')
94
        rev1 = master_tree.commit('master')
95
96
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
97
        rev2 = other.commit('other commit')
98
        # now pull --local, which should raise LocalRequiresBoundBranch error.
99
        self.assertRaises(errors.LocalRequiresBoundBranch,
100
                          master_tree.branch.pull, other.branch, local = True)
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
101
        self.assertEqual(rev1, master_tree.branch.last_revision())
4056.6.3 by Gary van der Merwe
Add local args to pull methods, and add more tests
102
3482.1.1 by John Arbash Meinel
Fix bug #238149, RemoteBranch.pull needs to return the _real_branch's pull result.
103
    def test_pull_returns_result(self):
104
        parent = self.make_branch_and_tree('parent')
105
        parent.commit('1st post', rev_id='P1')
106
        mine = parent.bzrdir.sprout('mine').open_workingtree()
107
        mine.commit('my change', rev_id='M1')
108
        result = parent.branch.pull(mine.branch)
109
        self.assertIsNot(None, result)
110
        self.assertIs(mine.branch, result.source_branch)
111
        self.assertIs(parent.branch, result.target_branch)
112
        self.assertIs(parent.branch, result.master_branch)
113
        self.assertIs(None, result.local_branch)
114
        self.assertEqual(1, result.old_revno)
115
        self.assertEqual('P1', result.old_revid)
116
        self.assertEqual(2, result.new_revno)
117
        self.assertEqual('M1', result.new_revid)
6112.4.7 by Jelmer Vernooij
Fix tests.
118
        self.assertEqual([], result.tag_conflicts)
3482.1.1 by John Arbash Meinel
Fix bug #238149, RemoteBranch.pull needs to return the _real_branch's pull result.
119
1551.10.23 by Aaron Bentley
Update test case per review
120
    def test_pull_overwrite(self):
121
        tree_a = self.make_branch_and_tree('tree_a')
122
        tree_a.commit('message 1')
123
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
124
        tree_a.commit('message 2', rev_id='rev2a')
125
        tree_b.commit('message 2', rev_id='rev2b')
126
        self.assertRaises(errors.DivergedBranches, tree_a.pull, tree_b.branch)
3052.5.2 by John Arbash Meinel
Use a Graph.heads() check to determine if the ancestries are compatible.
127
        self.assertRaises(errors.DivergedBranches,
128
                          tree_a.branch.pull, tree_b.branch,
129
                          overwrite=False, stop_revision='rev2b')
130
        # It should not have updated the branch tip, but it should have fetched
131
        # the revision
132
        self.assertEqual('rev2a', tree_a.branch.last_revision())
133
        self.assertTrue(tree_a.branch.repository.has_revision('rev2b'))
2975.1.1 by Robert Collins
Minor fixes for foreign format friendliness.
134
        tree_a.branch.pull(tree_b.branch, overwrite=True,
1551.10.23 by Aaron Bentley
Update test case per review
135
                           stop_revision='rev2b')
136
        self.assertEqual('rev2b', tree_a.branch.last_revision())
6165.2.1 by Jelmer Vernooij
Avoid using revision_history in the testsuite, in preparation of deprecating it.
137
        self.assertEqual(tree_b.branch.last_revision(),
138
                         tree_a.branch.last_revision())
1551.10.23 by Aaron Bentley
Update test case per review
139
5535.3.29 by Andrew Bennetts
Add some per-branch tests.
140
    def test_pull_merges_and_fetches_tags(self):
141
        """Tags are updated by br.pull(source), and revisions named in those
142
        tags are fetched.
143
        """
144
        # Make a source, sprout a target off it
145
        try:
146
            builder = self.make_branch_builder('source')
147
        except errors.UninitializableFormat:
148
            raise TestNotApplicable('uninitializeable format')
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
149
        source = fixtures.build_branch_with_non_ancestral_rev(builder)
5535.3.29 by Andrew Bennetts
Add some per-branch tests.
150
        target = source.bzrdir.sprout('target').open_branch()
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
151
        # Add a tag to the source, then pull from source
152
        try:
153
            source.tags.set_tag('tag-a', 'rev-2')
154
        except errors.TagsNotSupported:
155
            raise TestNotApplicable('format does not support tags.')
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
156
        source.tags.set_tag('tag-a', 'rev-2')
6015.15.4 by John Arbash Meinel
Catch a couple more cases that test tag fetching.
157
        source.get_config().set_user_option('branch.fetch_tags', 'True')
5535.3.29 by Andrew Bennetts
Add some per-branch tests.
158
        target.pull(source)
159
        # The tag is present, and so is its revision.
160
        self.assertEqual('rev-2', target.tags.lookup_tag('tag-a'))
161
        target.repository.get_revision('rev-2')
162
163
    def test_pull_stop_revision_merges_and_fetches_tags(self):
164
        """br.pull(source, stop_revision=REV) updates and fetches tags."""
165
        # Make a source, sprout a target off it
166
        try:
167
            builder = self.make_branch_builder('source')
168
        except errors.UninitializableFormat:
169
            raise TestNotApplicable('uninitializeable format')
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
170
        source = fixtures.build_branch_with_non_ancestral_rev(builder)
5535.3.29 by Andrew Bennetts
Add some per-branch tests.
171
        target = source.bzrdir.sprout('target').open_branch()
172
        # Add a new commit to the ancestry
173
        builder.build_commit(message="Rev 2 again", rev_id='rev-2-again')
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
174
        # Add a tag to the source, then pull rev-2-again from source
175
        try:
176
            source.tags.set_tag('tag-a', 'rev-2')
177
        except errors.TagsNotSupported:
178
            raise TestNotApplicable('format does not support tags.')
6015.15.4 by John Arbash Meinel
Catch a couple more cases that test tag fetching.
179
        source.get_config().set_user_option('branch.fetch_tags', 'True')
5535.3.29 by Andrew Bennetts
Add some per-branch tests.
180
        target.pull(source, 'rev-2-again')
181
        # The tag is present, and so is its revision.
182
        self.assertEqual('rev-2', target.tags.lookup_tag('tag-a'))
183
        target.repository.get_revision('rev-2')
184
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
185
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
186
class TestPullHook(per_branch.TestCaseWithBranch):
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
187
188
    def setUp(self):
189
        self.hook_calls = []
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
190
        super(TestPullHook, self).setUp()
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
191
2297.1.1 by Martin Pool
Pull now returns a PullResult rather than just an integer.
192
    def capture_post_pull_hook(self, result):
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
193
        """Capture post pull hook calls to self.hook_calls.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
194
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
195
        The call is logged, as is some state of the two branches.
196
        """
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
197
        if result.local_branch:
198
            local_locked = result.local_branch.is_locked()
199
            local_base = result.local_branch.base
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
200
        else:
201
            local_locked = None
202
            local_base = None
203
        self.hook_calls.append(
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
204
            ('post_pull', result.source_branch, local_base,
205
             result.master_branch.base, result.old_revno,
2297.1.1 by Martin Pool
Pull now returns a PullResult rather than just an integer.
206
             result.old_revid,
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
207
             result.new_revno, result.new_revid,
208
             result.source_branch.is_locked(), local_locked,
209
             result.master_branch.is_locked()))
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
210
211
    def test_post_pull_empty_history(self):
212
        target = self.make_branch('target')
213
        source = self.make_branch('source')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
214
        branch.Branch.hooks.install_named_hook(
215
            'post_pull', self.capture_post_pull_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
216
        target.pull(source)
217
        # with nothing there we should still get a notification, and
218
        # have both branches locked at the notification time.
219
        self.assertEqual([
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
220
            ('post_pull', source, None, target.base, 0, revision.NULL_REVISION,
221
             0, revision.NULL_REVISION, True, None, True)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
222
            ],
223
            self.hook_calls)
224
225
    def test_post_pull_bound_branch(self):
226
        # pulling to a bound branch should pass in the master branch to the
227
        # hook, allowing the correct number of emails to be sent, while still
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
228
        # allowing hooks that want to modify the target to do so to both
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
229
        # instances.
230
        target = self.make_branch('target')
231
        local = self.make_branch('local')
232
        try:
233
            local.bind(target)
234
        except errors.UpgradeRequired:
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
235
            # We can't bind this format to itself- typically it is the local
236
            # branch that doesn't support binding.  As of May 2007
237
            # remotebranches can't be bound.  Let's instead make a new local
238
            # branch of the default type, which does allow binding.
239
            # See https://bugs.launchpad.net/bzr/+bug/112020
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
240
            local = bzrdir.BzrDir.create_branch_convenience('local2')
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
241
            local.bind(target)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
242
        source = self.make_branch('source')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
243
        branch.Branch.hooks.install_named_hook(
244
            'post_pull', self.capture_post_pull_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
245
        local.pull(source)
246
        # with nothing there we should still get a notification, and
247
        # have both branches locked at the notification time.
248
        self.assertEqual([
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
249
            ('post_pull', source, local.base, target.base, 0,
250
             revision.NULL_REVISION, 0, revision.NULL_REVISION,
251
             True, True, True)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
252
            ],
253
            self.hook_calls)
254
255
    def test_post_pull_nonempty_history(self):
256
        target = self.make_branch_and_memory_tree('target')
257
        target.lock_write()
258
        target.add('')
259
        rev1 = target.commit('rev 1')
260
        target.unlock()
261
        sourcedir = target.bzrdir.clone(self.get_url('source'))
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
262
        source = memorytree.MemoryTree.create_on_branch(sourcedir.open_branch())
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
263
        rev2 = source.commit('rev 2')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
264
        branch.Branch.hooks.install_named_hook(
265
            'post_pull', self.capture_post_pull_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
266
        target.branch.pull(source.branch)
267
        # with nothing there we should still get a notification, and
268
        # have both branches locked at the notification time.
269
        self.assertEqual([
270
            ('post_pull', source.branch, None, target.branch.base, 1, rev1,
271
             2, rev2, True, None, True)
272
            ],
273
            self.hook_calls)