/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/branch_implementations/test_push.py

merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests for branch.push behaviour."""
18
18
 
 
19
from cStringIO import StringIO
19
20
import os
20
 
 
21
 
from bzrlib import bzrdir, errors
 
21
 
 
22
from bzrlib import (
 
23
    branch,
 
24
    builtins,
 
25
    bzrdir,
 
26
    debug,
 
27
    errors,
 
28
    push,
 
29
    repository,
 
30
    tests,
 
31
    )
22
32
from bzrlib.branch import Branch
23
33
from bzrlib.bzrdir import BzrDir
24
34
from bzrlib.memorytree import MemoryTree
25
 
from bzrlib.remote import RemoteBranch
26
35
from bzrlib.revision import NULL_REVISION
27
 
from bzrlib.tests import TestSkipped
 
36
from bzrlib.smart import client, server
 
37
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
28
38
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
 
39
from bzrlib.transport import get_transport
29
40
from bzrlib.transport.local import LocalURLServer
30
41
 
31
42
 
32
43
class TestPush(TestCaseWithBranch):
33
44
 
34
45
    def test_push_convergence_simple(self):
35
 
        # when revisions are pushed, the left-most accessible parents must 
 
46
        # when revisions are pushed, the left-most accessible parents must
36
47
        # become the revision-history.
37
48
        mine = self.make_branch_and_tree('mine')
38
49
        mine.commit('1st post', rev_id='P1', allow_pointless=True)
154
165
        self.assertEqual(tree.branch.last_revision(),
155
166
                         to_branch.last_revision())
156
167
 
 
168
    def test_push_overwrite_of_non_tip_with_stop_revision(self):
 
169
        """Combining the stop_revision and overwrite options works.
 
170
 
 
171
        This was <https://bugs.launchpad.net/bzr/+bug/234229>.
 
172
        """
 
173
        source = self.make_branch_and_tree('source')
 
174
        target = self.make_branch('target')
 
175
 
 
176
        source.commit('1st commit')
 
177
        source.branch.push(target)
 
178
        source.commit('2nd commit', rev_id='rev-2')
 
179
        source.commit('3rd commit')
 
180
 
 
181
        source.branch.push(target, stop_revision='rev-2', overwrite=True)
 
182
        self.assertEqual('rev-2', target.last_revision())
 
183
 
 
184
    def test_push_with_default_stacking_does_not_create_broken_branch(self):
 
185
        """Pushing a new standalone branch works even when there's a default
 
186
        stacking policy at the destination.
 
187
 
 
188
        The new branch will preserve the repo format (even if it isn't the
 
189
        default for the branch), and will be stacked when the repo format
 
190
        allows (which means that the branch format isn't necessarly preserved).
 
191
        """
 
192
        if isinstance(self.branch_format, branch.BzrBranchFormat4):
 
193
            raise tests.TestNotApplicable('Not a metadir format.')
 
194
        if isinstance(self.branch_format, branch.BranchReferenceFormat):
 
195
            # This test could in principle apply to BranchReferenceFormat, but
 
196
            # make_branch_builder doesn't support it.
 
197
            raise tests.TestSkipped(
 
198
                "BranchBuilder can't make reference branches.")
 
199
        # Make a branch called "local" in a stackable repository
 
200
        # The branch has 3 revisions:
 
201
        #   - rev-1, adds a file
 
202
        #   - rev-2, no changes
 
203
        #   - rev-3, modifies the file.
 
204
        repo = self.make_repository('repo', shared=True, format='1.6')
 
205
        builder = self.make_branch_builder('repo/local')
 
206
        builder.start_series()
 
207
        builder.build_snapshot('rev-1', None, [
 
208
            ('add', ('', 'root-id', 'directory', '')),
 
209
            ('add', ('filename', 'f-id', 'file', 'content\n'))])
 
210
        builder.build_snapshot('rev-2', ['rev-1'], [])
 
211
        builder.build_snapshot('rev-3', ['rev-2'],
 
212
            [('modify', ('f-id', 'new-content\n'))])
 
213
        builder.finish_series()
 
214
        trunk = builder.get_branch()
 
215
        # Sprout rev-1 to "trunk", so that we can stack on it.
 
216
        trunk.bzrdir.sprout(self.get_url('trunk'), revision_id='rev-1')
 
217
        # Set a default stacking policy so that new branches will automatically
 
218
        # stack on trunk.
 
219
        self.make_bzrdir('.').get_config().set_default_stack_on('trunk')
 
220
        # Push rev-2 to a new branch "remote".  It will be stacked on "trunk".
 
221
        output = StringIO()
 
222
        push._show_push_branch(trunk, 'rev-2', self.get_url('remote'), output)
 
223
        # Push rev-3 onto "remote".  If "remote" not stacked and is missing the
 
224
        # fulltext record for f-id @ rev-1, then this will fail.
 
225
        remote_branch = Branch.open(self.get_url('remote'))
 
226
        trunk.push(remote_branch)
 
227
        remote_branch.check()
 
228
 
 
229
    def test_no_get_parent_map_after_insert_stream(self):
 
230
        # Effort test for bug 331823
 
231
        self.setup_smart_server_with_call_log()
 
232
        # Make a local branch with four revisions.  Four revisions because:
 
233
        # one to push, one there for _walk_to_common_revisions to find, one we
 
234
        # don't want to access, one for luck :)
 
235
        if isinstance(self.branch_format, branch.BranchReferenceFormat):
 
236
            # This test could in principle apply to BranchReferenceFormat, but
 
237
            # make_branch_builder doesn't support it.
 
238
            raise tests.TestSkipped(
 
239
                "BranchBuilder can't make reference branches.")
 
240
        try:
 
241
            builder = self.make_branch_builder('local')
 
242
        except (errors.TransportNotPossible, errors.UninitializableFormat):
 
243
            raise tests.TestNotApplicable('format not directly constructable')
 
244
        builder.start_series()
 
245
        builder.build_snapshot('first', None, [
 
246
            ('add', ('', 'root-id', 'directory', ''))])
 
247
        builder.build_snapshot('second', ['first'], [])
 
248
        builder.build_snapshot('third', ['second'], [])
 
249
        builder.build_snapshot('fourth', ['third'], [])
 
250
        builder.finish_series()
 
251
        local = builder.get_branch()
 
252
        local = branch.Branch.open(self.get_vfs_only_url('local'))
 
253
        # Initial push of three revisions
 
254
        remote_bzrdir = local.bzrdir.sprout(
 
255
            self.get_url('remote'), revision_id='third')
 
256
        remote = remote_bzrdir.open_branch()
 
257
        # Push fourth revision
 
258
        self.reset_smart_call_log()
 
259
        self.disableOptimisticGetParentMap()
 
260
        self.assertFalse(local.is_locked())
 
261
        local.push(remote)
 
262
        hpss_call_names = [item.call.method for item in self.hpss_calls]
 
263
        self.assertTrue('Repository.insert_stream' in hpss_call_names)
 
264
        insert_stream_idx = hpss_call_names.index('Repository.insert_stream')
 
265
        calls_after_insert_stream = hpss_call_names[insert_stream_idx:]
 
266
        # After inserting the stream the client has no reason to query the
 
267
        # remote graph any further.
 
268
        self.assertEqual(
 
269
            ['Repository.insert_stream', 'Repository.insert_stream', 'get',
 
270
             'Branch.set_last_revision_info', 'Branch.unlock'],
 
271
            calls_after_insert_stream)
 
272
 
 
273
    def disableOptimisticGetParentMap(self):
 
274
        # Tweak some class variables to stop remote get_parent_map calls asking
 
275
        # for or receiving more data than the caller asked for.
 
276
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
 
277
        inter_class = repository.InterRepository
 
278
        old_batch_size = inter_class._walk_to_common_revisions_batch_size
 
279
        inter_class._walk_to_common_revisions_batch_size = 1
 
280
        SmartServerRepositoryGetParentMap.no_extra_results = True
 
281
        def reset_values():
 
282
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
 
283
            inter_class._walk_to_common_revisions_batch_size = old_batch_size
 
284
        self.addCleanup(reset_values)
 
285
 
157
286
 
158
287
class TestPushHook(TestCaseWithBranch):
159
288
 
163
292
 
164
293
    def capture_post_push_hook(self, result):
165
294
        """Capture post push hook calls to self.hook_calls.
166
 
        
 
295
 
167
296
        The call is logged, as is some state of the two branches.
168
297
        """
169
298
        if result.local_branch:
183
312
    def test_post_push_empty_history(self):
184
313
        target = self.make_branch('target')
185
314
        source = self.make_branch('source')
186
 
        Branch.hooks.install_hook('post_push', self.capture_post_push_hook)
 
315
        Branch.hooks.install_named_hook('post_push',
 
316
                                        self.capture_post_push_hook, None)
187
317
        source.push(target)
188
318
        # with nothing there we should still get a notification, and
189
319
        # have both branches locked at the notification time.
196
326
    def test_post_push_bound_branch(self):
197
327
        # pushing to a bound branch should pass in the master branch to the
198
328
        # hook, allowing the correct number of emails to be sent, while still
199
 
        # allowing hooks that want to modify the target to do so to both 
 
329
        # allowing hooks that want to modify the target to do so to both
200
330
        # instances.
201
331
        target = self.make_branch('target')
202
332
        local = self.make_branch('local')
211
341
            local = BzrDir.create_branch_convenience('local2')
212
342
            local.bind(target)
213
343
        source = self.make_branch('source')
214
 
        Branch.hooks.install_hook('post_push', self.capture_post_push_hook)
 
344
        Branch.hooks.install_named_hook('post_push',
 
345
                                        self.capture_post_push_hook, None)
215
346
        source.push(local)
216
347
        # with nothing there we should still get a notification, and
217
348
        # have both branches locked at the notification time.
230
361
        sourcedir = target.bzrdir.clone(self.get_url('source'))
231
362
        source = MemoryTree.create_on_branch(sourcedir.open_branch())
232
363
        rev2 = source.commit('rev 2')
233
 
        Branch.hooks.install_hook('post_push', self.capture_post_push_hook)
 
364
        Branch.hooks.install_named_hook('post_push',
 
365
                                        self.capture_post_push_hook, None)
234
366
        source.branch.push(target.branch)
235
367
        # with nothing there we should still get a notification, and
236
368
        # have both branches locked at the notification time.
239
371
             2, rev2, True, None, True)
240
372
            ],
241
373
            self.hook_calls)
 
374
 
 
375
 
 
376
class EmptyPushSmartEffortTests(TestCaseWithBranch):
 
377
    """Tests that a push of 0 revisions should make a limited number of smart
 
378
    protocol RPCs.
 
379
    """
 
380
 
 
381
    def setUp(self):
 
382
        # Skip some scenarios that don't apply to these tests.
 
383
        if (self.transport_server is not None and
 
384
            issubclass(self.transport_server, server.SmartTCPServer)):
 
385
            raise tests.TestNotApplicable(
 
386
                'Does not apply when remote backing branch is also '
 
387
                'a smart branch')
 
388
        if isinstance(self.branch_format, branch.BzrBranchFormat4):
 
389
            raise tests.TestNotApplicable(
 
390
                'Branch format 4 is not usable via HPSS.')
 
391
        super(EmptyPushSmartEffortTests, self).setUp()
 
392
        # Create a smart server that publishes whatever the backing VFS server
 
393
        # does.
 
394
        self.smart_server = server.SmartTCPServer_for_testing()
 
395
        self.smart_server.setUp(self.get_server())
 
396
        self.addCleanup(self.smart_server.tearDown)
 
397
        # Make two empty branches, 'empty' and 'target'.
 
398
        self.empty_branch = self.make_branch('empty')
 
399
        self.make_branch('target')
 
400
        # Log all HPSS calls into self.hpss_calls.
 
401
        client._SmartClient.hooks.install_named_hook(
 
402
            'call', self.capture_hpss_call, None)
 
403
        self.hpss_calls = []
 
404
 
 
405
    def capture_hpss_call(self, params):
 
406
        self.hpss_calls.append(params.method)
 
407
 
 
408
    def test_empty_branch_api(self):
 
409
        """The branch_obj.push API should make a limited number of HPSS calls.
 
410
        """
 
411
        transport = get_transport(self.smart_server.get_url()).clone('target')
 
412
        target = Branch.open_from_transport(transport)
 
413
        self.empty_branch.push(target)
 
414
        self.assertEqual(
 
415
            ['BzrDir.open',
 
416
             'BzrDir.open_branchV2',
 
417
             'BzrDir.find_repositoryV3',
 
418
             'Branch.get_stacked_on_url',
 
419
             'Branch.lock_write',
 
420
             'Branch.last_revision_info',
 
421
             'Branch.unlock'],
 
422
            self.hpss_calls)
 
423
 
 
424
    def test_empty_branch_command(self):
 
425
        """The 'bzr push' command should make a limited number of HPSS calls.
 
426
        """
 
427
        cmd = builtins.cmd_push()
 
428
        cmd.outf = tests.StringIOWrapper()
 
429
        cmd.run(
 
430
            directory=self.get_url() + 'empty',
 
431
            location=self.smart_server.get_url() + 'target')
 
432
        # HPSS calls as of 2008/09/22:
 
433
        # [BzrDir.open, BzrDir.open_branch, BzrDir.find_repositoryV2,
 
434
        # Branch.get_stacked_on_url, get, get, Branch.lock_write,
 
435
        # Branch.last_revision_info, Branch.unlock]
 
436
        self.assertTrue(len(self.hpss_calls) <= 9, self.hpss_calls)
 
437
 
 
438
 
 
439
class TestLossyPush(TestCaseWithBranch):
 
440
 
 
441
    def setUp(self):
 
442
        self.hook_calls = []
 
443
        TestCaseWithBranch.setUp(self)
 
444
 
 
445
    def test_lossy_push_raises_same_vcs(self):
 
446
        target = self.make_branch('target')
 
447
        source = self.make_branch('source')
 
448
        self.assertRaises(errors.LossyPushToSameVCS, source.lossy_push, target)