~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
19
import os
20
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
21
from bzrlib import (
22
    branch,
23
    bzrdir,
24
    errors,
25
    memorytree,
26
    revision,
27
    )
28
from bzrlib.tests import per_branch
29
30
31
class TestPull(per_branch.TestCaseWithBranch):
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
32
33
    def test_pull_convergence_simple(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
34
        # 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
35
        # become the revision-history.
36
        parent = self.make_branch_and_tree('parent')
37
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
38
        mine = parent.bzrdir.sprout('mine').open_workingtree()
39
        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.
40
        parent.merge_from_branch(mine.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
41
        parent.commit('merge my change', rev_id='P2')
42
        mine.pull(parent.branch)
43
        self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
44
45
    def test_pull_merged_indirect(self):
46
        # it should be possible to do a pull from one branch into another
47
        # when the tip of the target was merged into the source branch
48
        # via a third branch - so its buried in the ancestry and is not
49
        # directly accessible.
50
        parent = self.make_branch_and_tree('parent')
51
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
52
        mine = parent.bzrdir.sprout('mine').open_workingtree()
53
        mine.commit('my change', rev_id='M1', allow_pointless=True)
54
        other = parent.bzrdir.sprout('other').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
55
        other.merge_from_branch(mine.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
56
        other.commit('merge my change', rev_id='O2')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
57
        parent.merge_from_branch(other.branch)
1649.1.1 by Robert Collins
* 'pull' and 'push' now normalise the revision history, so that any two
58
        parent.commit('merge other', rev_id='P2')
59
        mine.pull(parent.branch)
60
        self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
61
62
    def test_pull_updates_checkout_and_master(self):
63
        """Pulling into a checkout updates the checkout and the master branch"""
64
        master_tree = self.make_branch_and_tree('master')
65
        rev1 = master_tree.commit('master')
66
        checkout = master_tree.branch.create_checkout('checkout')
67
68
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
69
        rev2 = other.commit('other commit')
70
        # now pull, which should update both checkout and master.
71
        checkout.branch.pull(other.branch)
72
        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
73
        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
74
4056.6.3 by Gary van der Merwe
Add local args to pull methods, and add more tests
75
    def test_pull_local_updates_checkout_only(self):
76
        """Pulling --local into a checkout updates the checkout and not the
77
        master branch"""
78
        master_tree = self.make_branch_and_tree('master')
79
        rev1 = master_tree.commit('master')
80
        checkout = master_tree.branch.create_checkout('checkout')
81
82
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
83
        rev2 = other.commit('other commit')
4335.1.1 by Ian Clatworthy
(igc) pull --local (Gary van der Merwe)
84
        # 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
85
        checkout.branch.pull(other.branch, local = True)
86
        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
87
        self.assertEqual([rev1], master_tree.branch.revision_history())
88
89
    def test_pull_local_raises_LocalRequiresBoundBranch_on_unbound(self):
90
        """Pulling --local into a branch that is not bound should fail."""
91
        master_tree = self.make_branch_and_tree('branch')
92
        rev1 = master_tree.commit('master')
93
94
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
95
        rev2 = other.commit('other commit')
96
        # now pull --local, which should raise LocalRequiresBoundBranch error.
97
        self.assertRaises(errors.LocalRequiresBoundBranch,
98
                          master_tree.branch.pull, other.branch, local = True)
99
        self.assertEqual([rev1], master_tree.branch.revision_history())
100
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
101
    def test_pull_raises_specific_error_on_master_connection_error(self):
102
        master_tree = self.make_branch_and_tree('master')
103
        checkout = master_tree.branch.create_checkout('checkout')
104
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
105
        # move the branch out of the way on disk to cause a connection
106
        # error.
107
        os.rename('master', 'master_gone')
108
        # try to pull, which should raise a BoundBranchConnectionFailure.
109
        self.assertRaises(errors.BoundBranchConnectionFailure,
110
                checkout.branch.pull, other.branch)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
111
3482.1.1 by John Arbash Meinel
Fix bug #238149, RemoteBranch.pull needs to return the _real_branch's pull result.
112
    def test_pull_returns_result(self):
113
        parent = self.make_branch_and_tree('parent')
114
        parent.commit('1st post', rev_id='P1')
115
        mine = parent.bzrdir.sprout('mine').open_workingtree()
116
        mine.commit('my change', rev_id='M1')
117
        result = parent.branch.pull(mine.branch)
118
        self.assertIsNot(None, result)
119
        self.assertIs(mine.branch, result.source_branch)
120
        self.assertIs(parent.branch, result.target_branch)
121
        self.assertIs(parent.branch, result.master_branch)
122
        self.assertIs(None, result.local_branch)
123
        self.assertEqual(1, result.old_revno)
124
        self.assertEqual('P1', result.old_revid)
125
        self.assertEqual(2, result.new_revno)
126
        self.assertEqual('M1', result.new_revid)
127
        self.assertEqual(None, result.tag_conflicts)
128
1551.10.23 by Aaron Bentley
Update test case per review
129
    def test_pull_overwrite(self):
130
        tree_a = self.make_branch_and_tree('tree_a')
131
        tree_a.commit('message 1')
132
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
133
        tree_a.commit('message 2', rev_id='rev2a')
134
        tree_b.commit('message 2', rev_id='rev2b')
135
        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.
136
        self.assertRaises(errors.DivergedBranches,
137
                          tree_a.branch.pull, tree_b.branch,
138
                          overwrite=False, stop_revision='rev2b')
139
        # It should not have updated the branch tip, but it should have fetched
140
        # the revision
141
        self.assertEqual('rev2a', tree_a.branch.last_revision())
142
        self.assertTrue(tree_a.branch.repository.has_revision('rev2b'))
2975.1.1 by Robert Collins
Minor fixes for foreign format friendliness.
143
        tree_a.branch.pull(tree_b.branch, overwrite=True,
1551.10.23 by Aaron Bentley
Update test case per review
144
                           stop_revision='rev2b')
145
        self.assertEqual('rev2b', tree_a.branch.last_revision())
146
        self.assertEqual(tree_b.branch.revision_history(),
147
                         tree_a.branch.revision_history())
148
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
149
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
150
class TestPullHook(per_branch.TestCaseWithBranch):
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
151
152
    def setUp(self):
153
        self.hook_calls = []
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
154
        super(TestPullHook, self).setUp()
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
155
2297.1.1 by Martin Pool
Pull now returns a PullResult rather than just an integer.
156
    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
157
        """Capture post pull hook calls to self.hook_calls.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
158
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
159
        The call is logged, as is some state of the two branches.
160
        """
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
161
        if result.local_branch:
162
            local_locked = result.local_branch.is_locked()
163
            local_base = result.local_branch.base
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
164
        else:
165
            local_locked = None
166
            local_base = None
167
        self.hook_calls.append(
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
168
            ('post_pull', result.source_branch, local_base,
169
             result.master_branch.base, result.old_revno,
2297.1.1 by Martin Pool
Pull now returns a PullResult rather than just an integer.
170
             result.old_revid,
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
171
             result.new_revno, result.new_revid,
172
             result.source_branch.is_locked(), local_locked,
173
             result.master_branch.is_locked()))
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
174
175
    def test_post_pull_empty_history(self):
176
        target = self.make_branch('target')
177
        source = self.make_branch('source')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
178
        branch.Branch.hooks.install_named_hook(
179
            '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
180
        target.pull(source)
181
        # with nothing there we should still get a notification, and
182
        # have both branches locked at the notification time.
183
        self.assertEqual([
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
184
            ('post_pull', source, None, target.base, 0, revision.NULL_REVISION,
185
             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
186
            ],
187
            self.hook_calls)
188
189
    def test_post_pull_bound_branch(self):
190
        # pulling to a bound branch should pass in the master branch to the
191
        # 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
192
        # 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
193
        # instances.
194
        target = self.make_branch('target')
195
        local = self.make_branch('local')
196
        try:
197
            local.bind(target)
198
        except errors.UpgradeRequired:
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
199
            # We can't bind this format to itself- typically it is the local
200
            # branch that doesn't support binding.  As of May 2007
201
            # remotebranches can't be bound.  Let's instead make a new local
202
            # branch of the default type, which does allow binding.
203
            # See https://bugs.launchpad.net/bzr/+bug/112020
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
204
            local = bzrdir.BzrDir.create_branch_convenience('local2')
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
205
            local.bind(target)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
206
        source = self.make_branch('source')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
207
        branch.Branch.hooks.install_named_hook(
208
            '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
209
        local.pull(source)
210
        # with nothing there we should still get a notification, and
211
        # have both branches locked at the notification time.
212
        self.assertEqual([
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
213
            ('post_pull', source, local.base, target.base, 0,
214
             revision.NULL_REVISION, 0, revision.NULL_REVISION,
215
             True, True, True)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
216
            ],
217
            self.hook_calls)
218
219
    def test_post_pull_nonempty_history(self):
220
        target = self.make_branch_and_memory_tree('target')
221
        target.lock_write()
222
        target.add('')
223
        rev1 = target.commit('rev 1')
224
        target.unlock()
225
        sourcedir = target.bzrdir.clone(self.get_url('source'))
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
226
        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
227
        rev2 = source.commit('rev 2')
5010.2.17 by Vincent Ladeuil
Fix imports in per_branch/test_pull.py.
228
        branch.Branch.hooks.install_named_hook(
229
            '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
230
        target.branch.pull(source.branch)
231
        # with nothing there we should still get a notification, and
232
        # have both branches locked at the notification time.
233
        self.assertEqual([
234
            ('post_pull', source.branch, None, target.branch.base, 1, rev1,
235
             2, rev2, True, None, True)
236
            ],
237
            self.hook_calls)