~bzr-pqm/bzr/bzr.dev

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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
16
17
"""Tests for branch.push behaviour."""
18
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
19
from cStringIO import StringIO
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
20
import os
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
21
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
22
from bzrlib import (
23
    branch,
24
    builtins,
25
    bzrdir,
4332.3.35 by Robert Collins
Fix failing tests.
26
    check,
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
27
    debug,
28
    errors,
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
29
    push,
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
30
    repository,
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
31
    tests,
32
    )
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
33
from bzrlib.branch import Branch
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
34
from bzrlib.bzrdir import BzrDir
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
35
from bzrlib.memorytree import MemoryTree
36
from bzrlib.revision import NULL_REVISION
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
37
from bzrlib.smart import client, server
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
38
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
4523.1.1 by Martin Pool
Rename tests.branch_implementations to per_branch
39
from bzrlib.tests.per_branch.test_branch import TestCaseWithBranch
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
40
from bzrlib.transport import get_transport
2018.5.130 by Robert Collins
Make all branch_implementations tests pass.
41
from bzrlib.transport.local import LocalURLServer
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
42
43
44
class TestPush(TestCaseWithBranch):
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
45
46
    def test_push_convergence_simple(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
47
        # when revisions are pushed, the left-most accessible parents must
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
48
        # become the revision-history.
49
        mine = self.make_branch_and_tree('mine')
50
        mine.commit('1st post', rev_id='P1', allow_pointless=True)
51
        other = mine.bzrdir.sprout('other').open_workingtree()
52
        other.commit('my change', rev_id='M1', allow_pointless=True)
53
        mine.merge_from_branch(other.branch)
54
        mine.commit('merge my change', rev_id='P2')
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
55
        result = mine.branch.push(other.branch)
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
56
        self.assertEqual(['P1', 'P2'], other.branch.revision_history())
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
57
        # result object contains some structured data
58
        self.assertEqual(result.old_revid, 'M1')
59
        self.assertEqual(result.new_revid, 'P2')
60
        # and it can be treated as an integer for compatibility
61
        self.assertEqual(int(result), 0)
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
62
63
    def test_push_merged_indirect(self):
64
        # it should be possible to do a push from one branch into another
65
        # when the tip of the target was merged into the source branch
66
        # via a third branch - so its buried in the ancestry and is not
67
        # directly accessible.
68
        mine = self.make_branch_and_tree('mine')
69
        mine.commit('1st post', rev_id='P1', allow_pointless=True)
70
        target = mine.bzrdir.sprout('target').open_workingtree()
71
        target.commit('my change', rev_id='M1', allow_pointless=True)
72
        other = mine.bzrdir.sprout('other').open_workingtree()
73
        other.merge_from_branch(target.branch)
74
        other.commit('merge my change', rev_id='O2')
75
        mine.merge_from_branch(other.branch)
76
        mine.commit('merge other', rev_id='P2')
77
        mine.branch.push(target.branch)
78
        self.assertEqual(['P1', 'P2'], target.branch.revision_history())
79
80
    def test_push_to_checkout_updates_master(self):
81
        """Pushing into a checkout updates the checkout and the master branch"""
82
        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
83
        checkout = self.make_branch_and_tree('checkout')
84
        try:
85
            checkout.branch.bind(master_tree.branch)
86
        except errors.UpgradeRequired:
87
            # cant bind this format, the test is irrelevant.
88
            return
89
        rev1 = checkout.commit('master')
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
90
91
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
92
        rev2 = other.commit('other commit')
93
        # now push, which should update both checkout and master.
94
        other.branch.push(checkout.branch)
95
        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
96
        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
97
98
    def test_push_raises_specific_error_on_master_connection_error(self):
99
        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
100
        checkout = self.make_branch_and_tree('checkout')
101
        try:
102
            checkout.branch.bind(master_tree.branch)
103
        except errors.UpgradeRequired:
104
            # cant bind this format, the test is irrelevant.
105
            return
2245.2.1 by Robert Collins
Split branch pushing out of branch pulling.
106
        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
107
        # move the branch out of the way on disk to cause a connection
108
        # error.
109
        os.rename('master', 'master_gone')
110
        # try to push, which should raise a BoundBranchConnectionFailure.
111
        self.assertRaises(errors.BoundBranchConnectionFailure,
112
                other.branch.push, checkout.branch)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
113
2279.1.1 by John Arbash Meinel
Branch.push() only needs a read lock.
114
    def test_push_uses_read_lock(self):
115
        """Push should only need a read lock on the source side."""
116
        source = self.make_branch_and_tree('source')
117
        target = self.make_branch('target')
118
2381.1.3 by Robert Collins
Review feedback.
119
        self.build_tree(['source/a'])
2279.1.1 by John Arbash Meinel
Branch.push() only needs a read lock.
120
        source.add(['a'])
121
        source.commit('a')
122
123
        source.branch.lock_read()
124
        try:
125
            target.lock_write()
126
            try:
127
                source.branch.push(target, stop_revision=source.last_revision())
128
            finally:
129
                target.unlock()
130
        finally:
131
            source.branch.unlock()
132
2279.1.3 by John Arbash Meinel
Switch the test to being a branch_implementation test.
133
    def test_push_within_repository(self):
134
        """Push from one branch to another inside the same repository."""
135
        try:
136
            repo = self.make_repository('repo', shared=True)
137
        except (errors.IncompatibleFormat, errors.UninitializableFormat):
138
            # This Branch format cannot create shared repositories
139
            return
140
        # This is a little bit trickier because make_branch_and_tree will not
141
        # re-use a shared repository.
142
        a_bzrdir = self.make_bzrdir('repo/tree')
143
        try:
144
            a_branch = self.branch_format.initialize(a_bzrdir)
145
        except (errors.UninitializableFormat):
146
            # Cannot create these branches
147
            return
2018.5.97 by Andrew Bennetts
Fix more tests.
148
        try:
149
            tree = a_branch.bzrdir.create_workingtree()
150
        except errors.NotLocalUrl:
2018.5.130 by Robert Collins
Make all branch_implementations tests pass.
151
            if self.vfs_transport_factory is LocalURLServer:
152
                # the branch is colocated on disk, we cannot create a checkout.
153
                # hopefully callers will expect this.
154
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url('repo/tree'))
155
                tree = local_controldir.create_workingtree()
156
            else:
157
                tree = a_branch.create_checkout('repo/tree', lightweight=True)
2381.1.3 by Robert Collins
Review feedback.
158
        self.build_tree(['repo/tree/a'])
2279.1.3 by John Arbash Meinel
Switch the test to being a branch_implementation test.
159
        tree.add(['a'])
160
        tree.commit('a')
161
162
        to_bzrdir = self.make_bzrdir('repo/branch')
163
        to_branch = self.branch_format.initialize(to_bzrdir)
164
        tree.branch.push(to_branch)
165
166
        self.assertEqual(tree.branch.last_revision(),
167
                         to_branch.last_revision())
168
3449.1.2 by Andrew Bennetts
Add test and NEWS entry.
169
    def test_push_overwrite_of_non_tip_with_stop_revision(self):
170
        """Combining the stop_revision and overwrite options works.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
171
3449.1.2 by Andrew Bennetts
Add test and NEWS entry.
172
        This was <https://bugs.launchpad.net/bzr/+bug/234229>.
173
        """
174
        source = self.make_branch_and_tree('source')
175
        target = self.make_branch('target')
176
177
        source.commit('1st commit')
178
        source.branch.push(target)
179
        source.commit('2nd commit', rev_id='rev-2')
180
        source.commit('3rd commit')
181
182
        source.branch.push(target, stop_revision='rev-2', overwrite=True)
183
        self.assertEqual('rev-2', target.last_revision())
184
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
185
    def test_push_with_default_stacking_does_not_create_broken_branch(self):
3904.3.7 by Andrew Bennetts
Comment the new tests.
186
        """Pushing a new standalone branch works even when there's a default
187
        stacking policy at the destination.
188
189
        The new branch will preserve the repo format (even if it isn't the
190
        default for the branch), and will be stacked when the repo format
191
        allows (which means that the branch format isn't necessarly preserved).
192
        """
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
193
        if isinstance(self.branch_format, branch.BzrBranchFormat4):
194
            raise tests.TestNotApplicable('Not a metadir format.')
195
        if isinstance(self.branch_format, branch.BranchReferenceFormat):
3904.3.7 by Andrew Bennetts
Comment the new tests.
196
            # This test could in principle apply to BranchReferenceFormat, but
197
            # make_branch_builder doesn't support it.
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
198
            raise tests.TestSkipped(
199
                "BranchBuilder can't make reference branches.")
3904.3.7 by Andrew Bennetts
Comment the new tests.
200
        # Make a branch called "local" in a stackable repository
201
        # The branch has 3 revisions:
202
        #   - rev-1, adds a file
203
        #   - rev-2, no changes
204
        #   - rev-3, modifies the file.
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
205
        repo = self.make_repository('repo', shared=True, format='1.6')
206
        builder = self.make_branch_builder('repo/local')
3904.3.4 by Andrew Bennetts
First cut of a branch_implementations test. It fails.
207
        builder.start_series()
208
        builder.build_snapshot('rev-1', None, [
209
            ('add', ('', 'root-id', 'directory', '')),
210
            ('add', ('filename', 'f-id', 'file', 'content\n'))])
211
        builder.build_snapshot('rev-2', ['rev-1'], [])
212
        builder.build_snapshot('rev-3', ['rev-2'],
213
            [('modify', ('f-id', 'new-content\n'))])
214
        builder.finish_series()
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
215
        trunk = builder.get_branch()
3904.3.7 by Andrew Bennetts
Comment the new tests.
216
        # Sprout rev-1 to "trunk", so that we can stack on it.
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
217
        trunk.bzrdir.sprout(self.get_url('trunk'), revision_id='rev-1')
3904.3.7 by Andrew Bennetts
Comment the new tests.
218
        # Set a default stacking policy so that new branches will automatically
219
        # stack on trunk.
3904.3.4 by Andrew Bennetts
First cut of a branch_implementations test. It fails.
220
        self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
3904.3.7 by Andrew Bennetts
Comment the new tests.
221
        # Push rev-2 to a new branch "remote".  It will be stacked on "trunk".
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
222
        output = StringIO()
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
223
        push._show_push_branch(trunk, 'rev-2', self.get_url('remote'), output)
3904.3.7 by Andrew Bennetts
Comment the new tests.
224
        # Push rev-3 onto "remote".  If "remote" not stacked and is missing the
225
        # fulltext record for f-id @ rev-1, then this will fail.
3904.3.5 by Andrew Bennetts
Improve the test; now 4/7 passing.
226
        remote_branch = Branch.open(self.get_url('remote'))
3904.3.6 by Andrew Bennetts
Skip test for two formats, and fix format 5 by avoiding a full history sync with non-format5 branches.
227
        trunk.push(remote_branch)
4332.3.35 by Robert Collins
Fix failing tests.
228
        check.check_dwim(remote_branch.base, False, True, True)
3904.3.4 by Andrew Bennetts
First cut of a branch_implementations test. It fails.
229
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
230
    def test_no_get_parent_map_after_insert_stream(self):
231
        # Effort test for bug 331823
232
        self.setup_smart_server_with_call_log()
233
        # Make a local branch with four revisions.  Four revisions because:
234
        # one to push, one there for _walk_to_common_revisions to find, one we
235
        # don't want to access, one for luck :)
4035.2.2 by Robert Collins
Minor tweaks to fix failing tests.
236
        if isinstance(self.branch_format, branch.BranchReferenceFormat):
237
            # This test could in principle apply to BranchReferenceFormat, but
238
            # make_branch_builder doesn't support it.
239
            raise tests.TestSkipped(
240
                "BranchBuilder can't make reference branches.")
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
241
        try:
242
            builder = self.make_branch_builder('local')
243
        except (errors.TransportNotPossible, errors.UninitializableFormat):
244
            raise tests.TestNotApplicable('format not directly constructable')
245
        builder.start_series()
246
        builder.build_snapshot('first', None, [
247
            ('add', ('', 'root-id', 'directory', ''))])
248
        builder.build_snapshot('second', ['first'], [])
249
        builder.build_snapshot('third', ['second'], [])
250
        builder.build_snapshot('fourth', ['third'], [])
251
        builder.finish_series()
252
        local = builder.get_branch()
253
        local = branch.Branch.open(self.get_vfs_only_url('local'))
254
        # Initial push of three revisions
255
        remote_bzrdir = local.bzrdir.sprout(
256
            self.get_url('remote'), revision_id='third')
257
        remote = remote_bzrdir.open_branch()
258
        # Push fourth revision
259
        self.reset_smart_call_log()
260
        self.disableOptimisticGetParentMap()
261
        self.assertFalse(local.is_locked())
262
        local.push(remote)
4070.2.6 by Robert Collins
Missed one test.
263
        hpss_call_names = [item.call.method for item in self.hpss_calls]
4476.3.82 by Andrew Bennetts
Mention another bug fix in NEWS, and update verb name, comments, and NEWS additions for landing on 1.19 rather than 1.18.
264
        self.assertTrue('Repository.insert_stream_1.19' in hpss_call_names)
4476.3.18 by Andrew Bennetts
Update some tests that were expecting the pre-1.17 insert_stream verb.
265
        insert_stream_idx = hpss_call_names.index(
4476.3.82 by Andrew Bennetts
Mention another bug fix in NEWS, and update verb name, comments, and NEWS additions for landing on 1.19 rather than 1.18.
266
            'Repository.insert_stream_1.19')
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
267
        calls_after_insert_stream = hpss_call_names[insert_stream_idx:]
268
        # After inserting the stream the client has no reason to query the
269
        # remote graph any further.
270
        self.assertEqual(
4476.3.82 by Andrew Bennetts
Mention another bug fix in NEWS, and update verb name, comments, and NEWS additions for landing on 1.19 rather than 1.18.
271
            ['Repository.insert_stream_1.19', 'Repository.insert_stream_1.19',
4476.3.18 by Andrew Bennetts
Update some tests that were expecting the pre-1.17 insert_stream verb.
272
             'get', 'Branch.set_last_revision_info', 'Branch.unlock'],
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
273
            calls_after_insert_stream)
274
275
    def disableOptimisticGetParentMap(self):
276
        # Tweak some class variables to stop remote get_parent_map calls asking
277
        # for or receiving more data than the caller asked for.
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
278
        self.overrideAttr(repository.InterRepository,
279
                          '_walk_to_common_revisions_batch_size', 1)
280
        self.overrideAttr(SmartServerRepositoryGetParentMap,
281
                          'no_extra_results', True)
4035.2.1 by Andrew Bennetts
Fix unnecessary get_parent_map calls after insert_stream during push.
282
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
283
284
class TestPushHook(TestCaseWithBranch):
285
286
    def setUp(self):
287
        self.hook_calls = []
288
        TestCaseWithBranch.setUp(self)
289
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
290
    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
291
        """Capture post push hook calls to self.hook_calls.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
292
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
293
        The call is logged, as is some state of the two branches.
294
        """
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
295
        if result.local_branch:
296
            local_locked = result.local_branch.is_locked()
297
            local_base = result.local_branch.base
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
298
        else:
299
            local_locked = None
300
            local_base = None
301
        self.hook_calls.append(
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
302
            ('post_push', result.source_branch, local_base,
303
             result.master_branch.base,
2297.1.4 by Martin Pool
Push now returns a PushResult rather than just an integer.
304
             result.old_revno, result.old_revid,
2297.1.6 by Martin Pool
Add docs for Results, give some members cleaner names
305
             result.new_revno, result.new_revid,
306
             result.source_branch.is_locked(), local_locked,
307
             result.master_branch.is_locked()))
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
308
309
    def test_post_push_empty_history(self):
310
        target = self.make_branch('target')
311
        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.
312
        Branch.hooks.install_named_hook('post_push',
313
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
314
        source.push(target)
315
        # with nothing there we should still get a notification, and
316
        # have both branches locked at the notification time.
317
        self.assertEqual([
318
            ('post_push', source, None, target.base, 0, NULL_REVISION,
319
             0, NULL_REVISION, True, None, True)
320
            ],
321
            self.hook_calls)
322
323
    def test_post_push_bound_branch(self):
324
        # pushing to a bound branch should pass in the master branch to the
325
        # 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
326
        # 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
327
        # instances.
328
        target = self.make_branch('target')
329
        local = self.make_branch('local')
330
        try:
331
            local.bind(target)
332
        except errors.UpgradeRequired:
2477.1.2 by Martin Pool
Rename push/pull back to 'run_hooks' (jameinel)
333
            # We can't bind this format to itself- typically it is the local
334
            # branch that doesn't support binding.  As of May 2007
335
            # remotebranches can't be bound.  Let's instead make a new local
336
            # branch of the default type, which does allow binding.
337
            # See https://bugs.launchpad.net/bzr/+bug/112020
2477.1.9 by Martin Pool
Review cleanups from John, mostly docs
338
            local = BzrDir.create_branch_convenience('local2')
339
            local.bind(target)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
340
        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.
341
        Branch.hooks.install_named_hook('post_push',
342
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
343
        source.push(local)
344
        # with nothing there we should still get a notification, and
345
        # have both branches locked at the notification time.
346
        self.assertEqual([
347
            ('post_push', source, local.base, target.base, 0, NULL_REVISION,
348
             0, NULL_REVISION, True, True, True)
349
            ],
350
            self.hook_calls)
351
352
    def test_post_push_nonempty_history(self):
353
        target = self.make_branch_and_memory_tree('target')
354
        target.lock_write()
355
        target.add('')
356
        rev1 = target.commit('rev 1')
357
        target.unlock()
358
        sourcedir = target.bzrdir.clone(self.get_url('source'))
359
        source = MemoryTree.create_on_branch(sourcedir.open_branch())
360
        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.
361
        Branch.hooks.install_named_hook('post_push',
362
                                        self.capture_post_push_hook, None)
2246.1.3 by Robert Collins
New branch hooks: post_push, post_pull, post_commit, post_uncommit. These
363
        source.branch.push(target.branch)
364
        # with nothing there we should still get a notification, and
365
        # have both branches locked at the notification time.
366
        self.assertEqual([
367
            ('post_push', source.branch, None, target.branch.base, 1, rev1,
368
             2, rev2, True, None, True)
369
            ],
370
            self.hook_calls)
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
371
372
373
class EmptyPushSmartEffortTests(TestCaseWithBranch):
374
    """Tests that a push of 0 revisions should make a limited number of smart
375
    protocol RPCs.
376
    """
377
378
    def setUp(self):
379
        # Skip some scenarios that don't apply to these tests.
380
        if (self.transport_server is not None and
381
            issubclass(self.transport_server, server.SmartTCPServer)):
382
            raise tests.TestNotApplicable(
383
                'Does not apply when remote backing branch is also '
384
                'a smart branch')
385
        if isinstance(self.branch_format, branch.BzrBranchFormat4):
386
            raise tests.TestNotApplicable(
387
                'Branch format 4 is not usable via HPSS.')
388
        super(EmptyPushSmartEffortTests, self).setUp()
389
        # Create a smart server that publishes whatever the backing VFS server
390
        # does.
391
        self.smart_server = server.SmartTCPServer_for_testing()
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
392
        self.start_server(self.smart_server, self.get_server())
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
393
        # Make two empty branches, 'empty' and 'target'.
394
        self.empty_branch = self.make_branch('empty')
395
        self.make_branch('target')
396
        # Log all HPSS calls into self.hpss_calls.
397
        client._SmartClient.hooks.install_named_hook(
398
            'call', self.capture_hpss_call, None)
399
        self.hpss_calls = []
400
401
    def capture_hpss_call(self, params):
402
        self.hpss_calls.append(params.method)
403
404
    def test_empty_branch_api(self):
405
        """The branch_obj.push API should make a limited number of HPSS calls.
406
        """
407
        transport = get_transport(self.smart_server.get_url()).clone('target')
408
        target = Branch.open_from_transport(transport)
409
        self.empty_branch.push(target)
410
        self.assertEqual(
4634.47.8 by Andrew Bennetts
Fix per_branch.test_push effort test to expect new verb.
411
            ['BzrDir.open_2.1',
4734.4.13 by Andrew Bennetts
Fix trivial test failure.
412
             'BzrDir.open_branchV3',
4053.1.4 by Robert Collins
Move the fetch control attributes from Repository to RepositoryFormat.
413
             'BzrDir.find_repositoryV3',
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
414
             'Branch.get_stacked_on_url',
415
             'Branch.lock_write',
416
             'Branch.last_revision_info',
417
             'Branch.unlock'],
418
            self.hpss_calls)
419
420
    def test_empty_branch_command(self):
421
        """The 'bzr push' command should make a limited number of HPSS calls.
422
        """
423
        cmd = builtins.cmd_push()
424
        cmd.outf = tests.StringIOWrapper()
425
        cmd.run(
4420.1.2 by Vincent Ladeuil
Fix bug #284038 by adding a --strict option to push.
426
            directory=self.get_url('empty'),
4420.1.4 by Vincent Ladeuil
Cleanup.
427
            location=self.smart_server.get_url() + 'target')
3703.3.7 by Andrew Bennetts
Move empty push effort tests to branch_implementations.
428
        # HPSS calls as of 2008/09/22:
429
        # [BzrDir.open, BzrDir.open_branch, BzrDir.find_repositoryV2,
430
        # Branch.get_stacked_on_url, get, get, Branch.lock_write,
431
        # Branch.last_revision_info, Branch.unlock]
432
        self.assertTrue(len(self.hpss_calls) <= 9, self.hpss_calls)
433
434
4347.3.2 by Jelmer Vernooij
Add some basic tests for lossy_push.
435
class TestLossyPush(TestCaseWithBranch):
436
437
    def setUp(self):
438
        self.hook_calls = []
439
        TestCaseWithBranch.setUp(self)
440
441
    def test_lossy_push_raises_same_vcs(self):
442
        target = self.make_branch('target')
443
        source = self.make_branch('source')
444
        self.assertRaises(errors.LossyPushToSameVCS, source.lossy_push, target)