/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
1
# Copyright (C) 2004, 2005, 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for branch.push behaviour."""
18
19
import os
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
20
 
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
21
from bzrlib import (
22
    branch,
23
    builtins,
24
    bzrdir,
25
    debug,
26
    errors,
27
    tests,
28
    )
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
29
from bzrlib.branch import Branch
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
30
from bzrlib.bzrdir import BzrDir
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
31
from bzrlib.memorytree import MemoryTree
32
from bzrlib.revision import NULL_REVISION
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
33
from bzrlib.smart import client, server
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
34
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
35
from bzrlib.transport import get_transport
2018.5.130 by Robert Collins
Make all branch_implementations tests pass.
36
from bzrlib.transport.local import LocalURLServer
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
37
38
39
class TestPush(TestCaseWithBranch):
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
40
41
    def test_push_convergence_simple(self):
42
        # when revisions are pushed, the left-most accessible parents must 
43
        # become the revision-history.
44
        mine = self.make_branch_and_tree('mine')
45
        mine.commit('1st post', rev_id='P1', allow_pointless=True)
46
        other = mine.bzrdir.sprout('other').open_workingtree()
47
        other.commit('my change', rev_id='M1', allow_pointless=True)
48
        mine.merge_from_branch(other.branch)
49
        mine.commit('merge my change', rev_id='P2')
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
50
        result = mine.branch.push(other.branch)
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
51
        self.assertEqual(['P1', 'P2'], other.branch.revision_history())
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
52
        # result object contains some structured data
53
        self.assertEqual(result.old_revid, 'M1')
54
        self.assertEqual(result.new_revid, 'P2')
55
        # and it can be treated as an integer for compatibility
56
        self.assertEqual(int(result), 0)
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
57
58
    def test_push_merged_indirect(self):
59
        # it should be possible to do a push from one branch into another
60
        # when the tip of the target was merged into the source branch
61
        # via a third branch - so its buried in the ancestry and is not
62
        # directly accessible.
63
        mine = self.make_branch_and_tree('mine')
64
        mine.commit('1st post', rev_id='P1', allow_pointless=True)
65
        target = mine.bzrdir.sprout('target').open_workingtree()
66
        target.commit('my change', rev_id='M1', allow_pointless=True)
67
        other = mine.bzrdir.sprout('other').open_workingtree()
68
        other.merge_from_branch(target.branch)
69
        other.commit('merge my change', rev_id='O2')
70
        mine.merge_from_branch(other.branch)
71
        mine.commit('merge other', rev_id='P2')
72
        mine.branch.push(target.branch)
73
        self.assertEqual(['P1', 'P2'], target.branch.revision_history())
74
75
    def test_push_to_checkout_updates_master(self):
76
        """Pushing into a checkout updates the checkout and the master branch"""
77
        master_tree = self.make_branch_and_tree('master')
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
78
        checkout = self.make_branch_and_tree('checkout')
79
        try:
80
            checkout.branch.bind(master_tree.branch)
81
        except errors.UpgradeRequired:
82
            # cant bind this format, the test is irrelevant.
83
            return
84
        rev1 = checkout.commit('master')
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
85
86
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
87
        rev2 = other.commit('other commit')
88
        # now push, which should update both checkout and master.
89
        other.branch.push(checkout.branch)
90
        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
91
        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
92
93
    def test_push_raises_specific_error_on_master_connection_error(self):
94
        master_tree = self.make_branch_and_tree('master')
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
95
        checkout = self.make_branch_and_tree('checkout')
96
        try:
97
            checkout.branch.bind(master_tree.branch)
98
        except errors.UpgradeRequired:
99
            # cant bind this format, the test is irrelevant.
100
            return
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
101
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
102
        # move the branch out of the way on disk to cause a connection
103
        # error.
104
        os.rename('master', 'master_gone')
105
        # try to push, which should raise a BoundBranchConnectionFailure.
106
        self.assertRaises(errors.BoundBranchConnectionFailure,
107
                other.branch.push, checkout.branch)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
108
2279.1.1 by John Arbash Meinel
Branch.push() only needs a read lock.
109
    def test_push_uses_read_lock(self):
110
        """Push should only need a read lock on the source side."""
111
        source = self.make_branch_and_tree('source')
112
        target = self.make_branch('target')
113
2381.1.3 by Robert Collins
Review feedback.
114
        self.build_tree(['source/a'])
2279.1.1 by John Arbash Meinel
Branch.push() only needs a read lock.
115
        source.add(['a'])
116
        source.commit('a')
117
118
        source.branch.lock_read()
119
        try:
120
            target.lock_write()
121
            try:
122
                source.branch.push(target, stop_revision=source.last_revision())
123
            finally:
124
                target.unlock()
125
        finally:
126
            source.branch.unlock()
127
2279.1.3 by John Arbash Meinel
Switch the test to being a branch_implementation test.
128
    def test_push_within_repository(self):
129
        """Push from one branch to another inside the same repository."""
130
        try:
131
            repo = self.make_repository('repo', shared=True)
132
        except (errors.IncompatibleFormat, errors.UninitializableFormat):
133
            # This Branch format cannot create shared repositories
134
            return
135
        # This is a little bit trickier because make_branch_and_tree will not
136
        # re-use a shared repository.
137
        a_bzrdir = self.make_bzrdir('repo/tree')
138
        try:
139
            a_branch = self.branch_format.initialize(a_bzrdir)
140
        except (errors.UninitializableFormat):
141
            # Cannot create these branches
142
            return
2018.5.97 by Andrew Bennetts
Fix more tests.
143
        try:
144
            tree = a_branch.bzrdir.create_workingtree()
145
        except errors.NotLocalUrl:
2018.5.130 by Robert Collins
Make all branch_implementations tests pass.
146
            if self.vfs_transport_factory is LocalURLServer:
147
                # the branch is colocated on disk, we cannot create a checkout.
148
                # hopefully callers will expect this.
149
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url('repo/tree'))
150
                tree = local_controldir.create_workingtree()
151
            else:
152
                tree = a_branch.create_checkout('repo/tree', lightweight=True)
2381.1.3 by Robert Collins
Review feedback.
153
        self.build_tree(['repo/tree/a'])
2279.1.3 by John Arbash Meinel
Switch the test to being a branch_implementation test.
154
        tree.add(['a'])
155
        tree.commit('a')
156
157
        to_bzrdir = self.make_bzrdir('repo/branch')
158
        to_branch = self.branch_format.initialize(to_bzrdir)
159
        tree.branch.push(to_branch)
160
161
        self.assertEqual(tree.branch.last_revision(),
162
                         to_branch.last_revision())
163
3449.1.2 by Andrew Bennetts
Add test and NEWS entry.
164
    def test_push_overwrite_of_non_tip_with_stop_revision(self):
165
        """Combining the stop_revision and overwrite options works.
166
        
167
        This was <https://bugs.launchpad.net/bzr/+bug/234229>.
168
        """
169
        source = self.make_branch_and_tree('source')
170
        target = self.make_branch('target')
171
172
        source.commit('1st commit')
173
        source.branch.push(target)
174
        source.commit('2nd commit', rev_id='rev-2')
175
        source.commit('3rd commit')
176
177
        source.branch.push(target, stop_revision='rev-2', overwrite=True)
178
        self.assertEqual('rev-2', target.last_revision())
179
3904.3.4 by Andrew Bennetts
First cut of a branch_implementations test. It fails.
180
    def test_push_doesnt_create_broken_branch(self):
181
        self.make_repository('repo', shared=True, format='1.6')
182
        builder = self.make_branch_builder('repo/local')#, format='pack-0.92')
183
        builder.start_series()
184
        builder.build_snapshot('rev-1', None, [
185
            ('add', ('', 'root-id', 'directory', '')),
186
            ('add', ('filename', 'f-id', 'file', 'content\n'))])
187
        builder.build_snapshot('rev-2', ['rev-1'], [])
188
        builder.build_snapshot('rev-3', ['rev-2'],
189
            [('modify', ('f-id', 'new-content\n'))])
190
        builder.finish_series()
191
        branch = builder.get_branch()
192
        branch.bzrdir.sprout(self.get_url('trunk'), revision_id='rev-1')
193
        #self.run_bzr('push -d repo/local trunk -r 1')
194
        self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
195
        #out, err = self.run_bzr('push -d repo/local remote -r 2')
196
        remote = branch.bzrdir.sprout(
197
            self.get_url('remote'), revision_id='rev-2')
198
        remote_branch = remote.open_branch()
199
#        self.assertContainsRe(
200
#            err, 'Using default stacking branch trunk at .*')
201
        branch.push(remote_branch)
202
        #out, err = self.run_bzr('push -d repo/local remote -r 3')
203
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
204
205
class TestPushHook(TestCaseWithBranch):
206
207
    def setUp(self):
208
        self.hook_calls = []
209
        TestCaseWithBranch.setUp(self)
210
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
211
    def capture_post_push_hook(self, result):
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
212
        """Capture post push hook calls to self.hook_calls.
213
        
214
        The call is logged, as is some state of the two branches.
215
        """
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
216
        if result.local_branch:
217
            local_locked = result.local_branch.is_locked()
218
            local_base = result.local_branch.base
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
219
        else:
220
            local_locked = None
221
            local_base = None
222
        self.hook_calls.append(
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
223
            ('post_push', result.source_branch, local_base,
224
             result.master_branch.base,
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
225
             result.old_revno, result.old_revid,
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
226
             result.new_revno, result.new_revid,
227
             result.source_branch.is_locked(), local_locked,
228
             result.master_branch.is_locked()))
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
229
230
    def test_post_push_empty_history(self):
231
        target = self.make_branch('target')
232
        source = self.make_branch('source')
3256.2.14 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_push.
233
        Branch.hooks.install_named_hook('post_push',
234
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
235
        source.push(target)
236
        # with nothing there we should still get a notification, and
237
        # have both branches locked at the notification time.
238
        self.assertEqual([
239
            ('post_push', source, None, target.base, 0, NULL_REVISION,
240
             0, NULL_REVISION, True, None, True)
241
            ],
242
            self.hook_calls)
243
244
    def test_post_push_bound_branch(self):
245
        # pushing to a bound branch should pass in the master branch to the
246
        # hook, allowing the correct number of emails to be sent, while still
247
        # allowing hooks that want to modify the target to do so to both 
248
        # instances.
249
        target = self.make_branch('target')
250
        local = self.make_branch('local')
251
        try:
252
            local.bind(target)
253
        except errors.UpgradeRequired:
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
254
            # We can't bind this format to itself- typically it is the local
255
            # branch that doesn't support binding.  As of May 2007
256
            # remotebranches can't be bound.  Let's instead make a new local
257
            # branch of the default type, which does allow binding.
258
            # See https://bugs.launchpad.net/bzr/+bug/112020
2477.1.9 by Martin Pool
Review cleanups from John, mostly docs
259
            local = BzrDir.create_branch_convenience('local2')
260
            local.bind(target)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
261
        source = self.make_branch('source')
3256.2.14 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_push.
262
        Branch.hooks.install_named_hook('post_push',
263
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
264
        source.push(local)
265
        # with nothing there we should still get a notification, and
266
        # have both branches locked at the notification time.
267
        self.assertEqual([
268
            ('post_push', source, local.base, target.base, 0, NULL_REVISION,
269
             0, NULL_REVISION, True, True, True)
270
            ],
271
            self.hook_calls)
272
273
    def test_post_push_nonempty_history(self):
274
        target = self.make_branch_and_memory_tree('target')
275
        target.lock_write()
276
        target.add('')
277
        rev1 = target.commit('rev 1')
278
        target.unlock()
279
        sourcedir = target.bzrdir.clone(self.get_url('source'))
280
        source = MemoryTree.create_on_branch(sourcedir.open_branch())
281
        rev2 = source.commit('rev 2')
3256.2.14 by Daniel Watkins
Updated uses of Hooks.install_hook to Hooks.install_named_hook in tests.branch_implementation.test_push.
282
        Branch.hooks.install_named_hook('post_push',
283
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
284
        source.branch.push(target.branch)
285
        # with nothing there we should still get a notification, and
286
        # have both branches locked at the notification time.
287
        self.assertEqual([
288
            ('post_push', source.branch, None, target.branch.base, 1, rev1,
289
             2, rev2, True, None, True)
290
            ],
291
            self.hook_calls)
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
292
293
294
class EmptyPushSmartEffortTests(TestCaseWithBranch):
295
    """Tests that a push of 0 revisions should make a limited number of smart
296
    protocol RPCs.
297
    """
298
299
    def setUp(self):
300
        # Skip some scenarios that don't apply to these tests.
301
        if (self.transport_server is not None and
302
            issubclass(self.transport_server, server.SmartTCPServer)):
303
            raise tests.TestNotApplicable(
304
                'Does not apply when remote backing branch is also '
305
                'a smart branch')
306
        if isinstance(self.branch_format, branch.BzrBranchFormat4):
307
            raise tests.TestNotApplicable(
308
                'Branch format 4 is not usable via HPSS.')
309
        super(EmptyPushSmartEffortTests, self).setUp()
310
        # Create a smart server that publishes whatever the backing VFS server
311
        # does.
312
        self.smart_server = server.SmartTCPServer_for_testing()
313
        self.smart_server.setUp(self.get_server())
314
        self.addCleanup(self.smart_server.tearDown)
315
        # Make two empty branches, 'empty' and 'target'.
316
        self.empty_branch = self.make_branch('empty')
317
        self.make_branch('target')
318
        # Log all HPSS calls into self.hpss_calls.
319
        client._SmartClient.hooks.install_named_hook(
320
            'call', self.capture_hpss_call, None)
321
        self.hpss_calls = []
322
323
    def capture_hpss_call(self, params):
324
        self.hpss_calls.append(params.method)
325
326
    def test_empty_branch_api(self):
327
        """The branch_obj.push API should make a limited number of HPSS calls.
328
        """
329
        transport = get_transport(self.smart_server.get_url()).clone('target')
330
        target = Branch.open_from_transport(transport)
331
        self.empty_branch.push(target)
332
        self.assertEqual(
333
            ['BzrDir.open',
334
             'BzrDir.open_branch',
335
             'BzrDir.find_repositoryV2',
336
             'Branch.get_stacked_on_url',
337
             'Branch.lock_write',
338
             'Branch.last_revision_info',
339
             'Branch.unlock'],
340
            self.hpss_calls)
341
342
    def test_empty_branch_command(self):
343
        """The 'bzr push' command should make a limited number of HPSS calls.
344
        """
345
        cmd = builtins.cmd_push()
346
        cmd.outf = tests.StringIOWrapper()
347
        cmd.run(
348
            directory=self.get_url() + 'empty',
349
            location=self.smart_server.get_url() + 'target')
350
        # HPSS calls as of 2008/09/22:
351
        # [BzrDir.open, BzrDir.open_branch, BzrDir.find_repositoryV2,
352
        # Branch.get_stacked_on_url, get, get, Branch.lock_write,
353
        # Branch.last_revision_info, Branch.unlock]
354
        self.assertTrue(len(self.hpss_calls) <= 9, self.hpss_calls)
355
356