~bzr-pqm/bzr/bzr.dev

5273.1.5 by Vincent Ladeuil
Merge bzr.dev into cleanup
1
# Copyright (C) 2009, 2010 Canonical Ltd
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
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
4000.5.16 by Jelmer Vernooij
Fix FSF address.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
16
17
"""Tests for InterBranch.pull behaviour."""
18
19
import os
20
21
from bzrlib.branch import Branch
22
from bzrlib.bzrdir import BzrDir
23
from bzrlib import errors
24
from bzrlib.memorytree import MemoryTree
25
from bzrlib.revision import NULL_REVISION
26
from bzrlib.tests.per_interbranch import TestCaseWithInterBranch
27
28
4000.5.23 by Jelmer Vernooij
Review feedback from Ian; add some comments about origin of tests, comment on further work in pull.
29
# The tests here are based on the tests in 
4523.1.1 by Martin Pool
Rename tests.branch_implementations to per_branch
30
# bzrlib.tests.per_branch.test_pull
4000.5.23 by Jelmer Vernooij
Review feedback from Ian; add some comments about origin of tests, comment on further work in pull.
31
32
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
33
class TestPull(TestCaseWithInterBranch):
34
35
    def test_pull_convergence_simple(self):
36
        # when revisions are pulled, the left-most accessible parents must
37
        # become the revision-history.
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
38
        parent = self.make_from_branch_and_tree('parent')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
39
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
40
        mine = self.sprout_to(parent.bzrdir, 'mine').open_workingtree()
41
        mine.commit('my change', rev_id='M1', allow_pointless=True)
42
        parent.merge_from_branch(mine.branch)
43
        parent.commit('merge my change', rev_id='P2')
44
        mine.pull(parent.branch)
45
        self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
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.
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
52
        parent = self.make_from_branch_and_tree('parent')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
53
        parent.commit('1st post', rev_id='P1', allow_pointless=True)
54
        mine = self.sprout_to(parent.bzrdir, 'mine').open_workingtree()
55
        mine.commit('my change', rev_id='M1', allow_pointless=True)
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
56
        other = self.sprout_to(parent.bzrdir, 'other').open_workingtree()
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
57
        other.merge_from_branch(mine.branch)
58
        other.commit('merge my change', rev_id='O2')
59
        parent.merge_from_branch(other.branch)
60
        parent.commit('merge other', rev_id='P2')
61
        mine.pull(parent.branch)
62
        self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
63
64
    def test_pull_updates_checkout_and_master(self):
65
        """Pulling into a checkout updates the checkout and the master branch"""
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
66
        master_tree = self.make_from_branch_and_tree('master')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
67
        rev1 = master_tree.commit('master')
68
        checkout = master_tree.branch.create_checkout('checkout')
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
69
        other = self.sprout_to(master_tree.branch.bzrdir, 'other').open_workingtree()
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
70
        rev2 = other.commit('other commit')
71
        # now pull, which should update both checkout and master.
72
        checkout.branch.pull(other.branch)
73
        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
74
        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
75
76
    def test_pull_raises_specific_error_on_master_connection_error(self):
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
77
        master_tree = self.make_from_branch_and_tree('master')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
78
        checkout = master_tree.branch.create_checkout('checkout')
5284.4.1 by Robert Collins
* Fetching was slightly confused about the best code to use and was
79
        other = self.sprout_to(master_tree.branch.bzrdir, 'other').open_branch()
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
80
        # move the branch out of the way on disk to cause a connection
81
        # error.
82
        os.rename('master', 'master_gone')
83
        # try to pull, which should raise a BoundBranchConnectionFailure.
84
        self.assertRaises(errors.BoundBranchConnectionFailure,
5284.4.1 by Robert Collins
* Fetching was slightly confused about the best code to use and was
85
                checkout.branch.pull, other)
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
86
87
    def test_pull_returns_result(self):
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
88
        parent = self.make_from_branch_and_tree('parent')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
89
        parent.commit('1st post', rev_id='P1')
90
        mine = self.sprout_to(parent.bzrdir, 'mine').open_workingtree()
91
        mine.commit('my change', rev_id='M1')
92
        result = parent.branch.pull(mine.branch)
93
        self.assertIsNot(None, result)
94
        self.assertIs(mine.branch, result.source_branch)
95
        self.assertIs(parent.branch, result.target_branch)
96
        self.assertIs(parent.branch, result.master_branch)
97
        self.assertIs(None, result.local_branch)
98
        self.assertEqual(1, result.old_revno)
99
        self.assertEqual('P1', result.old_revid)
100
        self.assertEqual(2, result.new_revno)
101
        self.assertEqual('M1', result.new_revid)
102
        self.assertEqual(None, result.tag_conflicts)
103
104
    def test_pull_overwrite(self):
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
105
        tree_a = self.make_from_branch_and_tree('tree_a')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
106
        tree_a.commit('message 1')
107
        tree_b = self.sprout_to(tree_a.bzrdir, 'tree_b').open_workingtree()
108
        tree_a.commit('message 2', rev_id='rev2a')
109
        tree_b.commit('message 2', rev_id='rev2b')
110
        self.assertRaises(errors.DivergedBranches, tree_a.pull, tree_b.branch)
111
        self.assertRaises(errors.DivergedBranches,
112
                          tree_a.branch.pull, tree_b.branch,
113
                          overwrite=False, stop_revision='rev2b')
114
        # It should not have updated the branch tip, but it should have fetched
115
        # the revision
116
        self.assertEqual('rev2a', tree_a.branch.last_revision())
117
        self.assertTrue(tree_a.branch.repository.has_revision('rev2b'))
118
        tree_a.branch.pull(tree_b.branch, overwrite=True,
119
                           stop_revision='rev2b')
120
        self.assertEqual('rev2b', tree_a.branch.last_revision())
121
        self.assertEqual(tree_b.branch.revision_history(),
122
                         tree_a.branch.revision_history())
123
124
125
class TestPullHook(TestCaseWithInterBranch):
126
127
    def setUp(self):
128
        self.hook_calls = []
129
        TestCaseWithInterBranch.setUp(self)
130
131
    def capture_post_pull_hook(self, result):
132
        """Capture post pull hook calls to self.hook_calls.
133
134
        The call is logged, as is some state of the two branches.
135
        """
136
        if result.local_branch:
137
            local_locked = result.local_branch.is_locked()
138
            local_base = result.local_branch.base
139
        else:
140
            local_locked = None
141
            local_base = None
142
        self.hook_calls.append(
143
            ('post_pull', result.source_branch, local_base,
144
             result.master_branch.base, result.old_revno,
145
             result.old_revid,
146
             result.new_revno, result.new_revid,
147
             result.source_branch.is_locked(), local_locked,
148
             result.master_branch.is_locked()))
149
150
    def test_post_pull_empty_history(self):
151
        target = self.make_to_branch('target')
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
152
        source = self.make_from_branch('source')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
153
        Branch.hooks.install_named_hook('post_pull',
154
            self.capture_post_pull_hook, None)
155
        target.pull(source)
156
        # with nothing there we should still get a notification, and
157
        # have both branches locked at the notification time.
158
        self.assertEqual([
159
            ('post_pull', source, None, target.base, 0, NULL_REVISION,
160
             0, NULL_REVISION, True, None, True)
161
            ],
162
            self.hook_calls)
163
164
    def test_post_pull_bound_branch(self):
165
        # pulling to a bound branch should pass in the master branch to the
166
        # hook, allowing the correct number of emails to be sent, while still
167
        # allowing hooks that want to modify the target to do so to both
168
        # instances.
169
        target = self.make_to_branch('target')
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
170
        local = self.make_from_branch('local')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
171
        try:
172
            local.bind(target)
173
        except errors.UpgradeRequired:
174
            # We can't bind this format to itself- typically it is the local
175
            # branch that doesn't support binding.  As of May 2007
176
            # remotebranches can't be bound.  Let's instead make a new local
177
            # branch of the default type, which does allow binding.
178
            # See https://bugs.launchpad.net/bzr/+bug/112020
179
            local = BzrDir.create_branch_convenience('local2')
180
            local.bind(target)
4000.5.20 by Jelmer Vernooij
Fix InterBranch.pull tests.
181
        source = self.make_from_branch('source')
4000.5.11 by Jelmer Vernooij
Improve tests for InterBranch.pull.
182
        Branch.hooks.install_named_hook('post_pull',
183
            self.capture_post_pull_hook, None)
184
        local.pull(source)
185
        # with nothing there we should still get a notification, and
186
        # have both branches locked at the notification time.
187
        self.assertEqual([
188
            ('post_pull', source, local.base, target.base, 0, NULL_REVISION,
189
             0, NULL_REVISION, True, True, True)
190
            ],
191
            self.hook_calls)
192
193
    def test_post_pull_nonempty_history(self):
194
        target = self.make_to_branch_and_memory_tree('target')
195
        target.lock_write()
196
        target.add('')
197
        rev1 = target.commit('rev 1')
198
        target.unlock()
199
        sourcedir = target.bzrdir.clone(self.get_url('source'))
200
        source = MemoryTree.create_on_branch(sourcedir.open_branch())
201
        rev2 = source.commit('rev 2')
202
        Branch.hooks.install_named_hook('post_pull',
203
            self.capture_post_pull_hook, None)
204
        target.branch.pull(source.branch)
205
        # with nothing there we should still get a notification, and
206
        # have both branches locked at the notification time.
207
        self.assertEqual([
208
            ('post_pull', source.branch, None, target.branch.base, 1, rev1,
209
             2, rev2, True, None, True)
210
            ],
211
            self.hook_calls)