~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-06-18 20:25:52 UTC
  • mfrom: (4413.5.15 1.16-chk-direct)
  • Revision ID: pqm@pqm.ubuntu.com-20090618202552-xyl6tcvbxtm8bupf
(jam) Improve initial commit performance by creating a CHKMap in bulk,
        rather than via O(tree) map() calls.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
from cStringIO import StringIO
28
28
 
29
29
from bzrlib import (
30
 
    branch,
31
30
    bzrdir,
32
31
    config,
33
 
    controldir,
34
32
    errors,
35
33
    graph,
36
 
    inventory,
37
 
    inventory_delta,
 
34
    pack,
38
35
    remote,
39
36
    repository,
 
37
    smart,
40
38
    tests,
41
 
    transport,
42
39
    treebuilder,
43
 
    versionedfile,
 
40
    urlutils,
44
41
    )
45
42
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import (
47
 
    BzrDir,
48
 
    BzrDirFormat,
49
 
    RemoteBzrProber,
50
 
    )
 
43
from bzrlib.bzrdir import BzrDir, BzrDirFormat
51
44
from bzrlib.remote import (
52
45
    RemoteBranch,
53
46
    RemoteBranchFormat,
54
47
    RemoteBzrDir,
 
48
    RemoteBzrDirFormat,
55
49
    RemoteRepository,
56
50
    RemoteRepositoryFormat,
57
51
    )
58
52
from bzrlib.repofmt import groupcompress_repo, pack_repo
59
53
from bzrlib.revision import NULL_REVISION
60
 
from bzrlib.smart import medium
 
54
from bzrlib.smart import server, medium
61
55
from bzrlib.smart.client import _SmartClient
62
56
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
63
57
from bzrlib.tests import (
64
58
    condition_isinstance,
65
59
    split_suite_by_condition,
66
60
    multiply_tests,
67
 
    test_server,
 
61
    KnownFailure,
68
62
    )
 
63
from bzrlib.transport import get_transport, http
69
64
from bzrlib.transport.memory import MemoryTransport
70
65
from bzrlib.transport.remote import (
71
66
    RemoteTransport,
78
73
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
79
74
    smart_server_version_scenarios = [
80
75
        ('HPSS-v2',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
76
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
82
77
        ('HPSS-v3',
83
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
 
78
            {'transport_server': server.SmartTCPServer_for_testing})]
84
79
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
80
 
86
81
 
91
86
        self.transport = self.get_transport()
92
87
        # make a branch that can be opened over the smart transport
93
88
        self.local_wt = BzrDir.create_standalone_workingtree('.')
94
 
        self.addCleanup(self.transport.disconnect)
 
89
 
 
90
    def tearDown(self):
 
91
        self.transport.disconnect()
 
92
        tests.TestCaseWithTransport.tearDown(self)
95
93
 
96
94
    def test_create_remote_bzrdir(self):
97
95
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
121
119
    def test_find_correct_format(self):
122
120
        """Should open a RemoteBzrDir over a RemoteTransport"""
123
121
        fmt = BzrDirFormat.find_format(self.transport)
124
 
        self.assertTrue(bzrdir.RemoteBzrProber
125
 
                        in controldir.ControlDirFormat._server_probers)
 
122
        self.assertTrue(RemoteBzrDirFormat
 
123
                        in BzrDirFormat._control_server_formats)
126
124
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
127
125
 
128
126
    def test_open_detected_smart_format(self):
134
132
        b = BzrDir.open_from_transport(self.transport).open_branch()
135
133
        self.assertStartsWith(str(b), 'RemoteBranch(')
136
134
 
137
 
    def test_remote_bzrdir_repr(self):
138
 
        b = BzrDir.open_from_transport(self.transport)
139
 
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
140
 
 
141
135
    def test_remote_branch_format_supports_stacking(self):
142
136
        t = self.transport
143
137
        self.make_branch('unstackable', format='pack-0.92')
283
277
        self.expecting_body = True
284
278
        return result[1], FakeProtocol(result[2], self)
285
279
 
286
 
    def call_with_body_bytes(self, method, args, body):
287
 
        self._check_call(method, args)
288
 
        self._calls.append(('call_with_body_bytes', method, args, body))
289
 
        result = self._get_next_response()
290
 
        return result[1], FakeProtocol(result[2], self)
291
 
 
292
280
    def call_with_body_bytes_expecting_body(self, method, args, body):
293
281
        self._check_call(method, args)
294
282
        self._calls.append(('call_with_body_bytes_expecting_body', method,
344
332
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
345
333
        return reference_bzrdir_format.repository_format
346
334
 
347
 
    def assertFinished(self, fake_client):
348
 
        """Assert that all of a FakeClient's expected calls have occurred."""
349
 
        fake_client.finished_test()
 
335
    def disable_verb(self, verb):
 
336
        """Disable a verb for one test."""
 
337
        request_handlers = smart.request.request_handlers
 
338
        orig_method = request_handlers.get(verb)
 
339
        request_handlers.remove(verb)
 
340
        def restoreVerb():
 
341
            request_handlers.register(verb, orig_method)
 
342
        self.addCleanup(restoreVerb)
350
343
 
351
344
 
352
345
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
358
351
        a given client_base and transport_base.
359
352
        """
360
353
        client_medium = medium.SmartClientMedium(client_base)
361
 
        t = transport.get_transport(transport_base)
362
 
        result = client_medium.remote_path_from_transport(t)
 
354
        transport = get_transport(transport_base)
 
355
        result = client_medium.remote_path_from_transport(transport)
363
356
        self.assertEqual(expected, result)
364
357
 
365
358
    def test_remote_path_from_transport(self):
376
369
        a given transport_base and relpath of that transport.  (Note that
377
370
        HttpTransportBase is a subclass of SmartClientMedium)
378
371
        """
379
 
        base_transport = transport.get_transport(transport_base)
 
372
        base_transport = get_transport(transport_base)
380
373
        client_medium = base_transport.get_smart_medium()
381
374
        cloned_transport = base_transport.clone(relpath)
382
375
        result = client_medium.remote_path_from_transport(cloned_transport)
417
410
        # Calling _remember_remote_is_before again with a lower value works.
418
411
        client_medium._remember_remote_is_before((1, 5))
419
412
        self.assertTrue(client_medium._is_remote_before((1, 5)))
420
 
        # If you call _remember_remote_is_before with a higher value it logs a
421
 
        # warning, and continues to remember the lower value.
422
 
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
423
 
        client_medium._remember_remote_is_before((1, 9))
424
 
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
425
 
        self.assertTrue(client_medium._is_remote_before((1, 5)))
 
413
        # You cannot call _remember_remote_is_before with a larger value.
 
414
        self.assertRaises(
 
415
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
426
416
 
427
417
 
428
418
class TestBzrDirCloningMetaDir(TestRemote):
447
437
            'BzrDir.cloning_metadir', ('quack/', 'False'),
448
438
            'error', ('BranchReference',)),
449
439
        client.add_expected_call(
450
 
            'BzrDir.open_branchV3', ('quack/',),
 
440
            'BzrDir.open_branchV2', ('quack/',),
451
441
            'success', ('ref', self.get_url('referenced'))),
452
442
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
453
443
            _client=client)
456
446
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
457
447
        self.assertEqual(expected._repository_format, result._repository_format)
458
448
        self.assertEqual(expected._branch_format, result._branch_format)
459
 
        self.assertFinished(client)
 
449
        client.finished_test()
460
450
 
461
451
    def test_current_server(self):
462
452
        transport = self.get_transport('.')
477
467
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
478
468
        self.assertEqual(None, result._repository_format)
479
469
        self.assertEqual(None, result._branch_format)
480
 
        self.assertFinished(client)
481
 
 
482
 
 
483
 
class TestBzrDirOpen(TestRemote):
484
 
 
485
 
    def make_fake_client_and_transport(self, path='quack'):
486
 
        transport = MemoryTransport()
487
 
        transport.mkdir(path)
488
 
        transport = transport.clone(path)
489
 
        client = FakeClient(transport.base)
490
 
        return client, transport
491
 
 
492
 
    def test_absent(self):
493
 
        client, transport = self.make_fake_client_and_transport()
494
 
        client.add_expected_call(
495
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
496
 
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
497
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
498
 
        self.assertFinished(client)
499
 
 
500
 
    def test_present_without_workingtree(self):
501
 
        client, transport = self.make_fake_client_and_transport()
502
 
        client.add_expected_call(
503
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
504
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
505
 
            _client=client, _force_probe=True)
506
 
        self.assertIsInstance(bd, RemoteBzrDir)
507
 
        self.assertFalse(bd.has_workingtree())
508
 
        self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
509
 
        self.assertFinished(client)
510
 
 
511
 
    def test_present_with_workingtree(self):
512
 
        client, transport = self.make_fake_client_and_transport()
513
 
        client.add_expected_call(
514
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
515
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
516
 
            _client=client, _force_probe=True)
517
 
        self.assertIsInstance(bd, RemoteBzrDir)
518
 
        self.assertTrue(bd.has_workingtree())
519
 
        self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
520
 
        self.assertFinished(client)
521
 
 
522
 
    def test_backwards_compat(self):
523
 
        client, transport = self.make_fake_client_and_transport()
524
 
        client.add_expected_call(
525
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
526
 
        client.add_expected_call(
527
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
528
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
529
 
            _client=client, _force_probe=True)
530
 
        self.assertIsInstance(bd, RemoteBzrDir)
531
 
        self.assertFinished(client)
532
 
 
533
 
    def test_backwards_compat_hpss_v2(self):
534
 
        client, transport = self.make_fake_client_and_transport()
535
 
        # Monkey-patch fake client to simulate real-world behaviour with v2
536
 
        # server: upon first RPC call detect the protocol version, and because
537
 
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
538
 
        # continuing with the RPC.
539
 
        orig_check_call = client._check_call
540
 
        def check_call(method, args):
541
 
            client._medium._protocol_version = 2
542
 
            client._medium._remember_remote_is_before((1, 6))
543
 
            client._check_call = orig_check_call
544
 
            client._check_call(method, args)
545
 
        client._check_call = check_call
546
 
        client.add_expected_call(
547
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
548
 
        client.add_expected_call(
549
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
550
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
551
 
            _client=client, _force_probe=True)
552
 
        self.assertIsInstance(bd, RemoteBzrDir)
553
 
        self.assertFinished(client)
 
470
        client.finished_test()
554
471
 
555
472
 
556
473
class TestBzrDirOpenBranch(TestRemote):
560
477
        self.make_branch('.')
561
478
        a_dir = BzrDir.open(self.get_url('.'))
562
479
        self.reset_smart_call_log()
563
 
        verb = 'BzrDir.open_branchV3'
 
480
        verb = 'BzrDir.open_branchV2'
564
481
        self.disable_verb(verb)
565
482
        format = a_dir.open_branch()
566
483
        call_count = len([call for call in self.hpss_calls if
576
493
        transport = transport.clone('quack')
577
494
        client = FakeClient(transport.base)
578
495
        client.add_expected_call(
579
 
            'BzrDir.open_branchV3', ('quack/',),
 
496
            'BzrDir.open_branchV2', ('quack/',),
580
497
            'success', ('branch', branch_network_name))
581
498
        client.add_expected_call(
582
499
            'BzrDir.find_repositoryV3', ('quack/',),
589
506
        result = bzrdir.open_branch()
590
507
        self.assertIsInstance(result, RemoteBranch)
591
508
        self.assertEqual(bzrdir, result.bzrdir)
592
 
        self.assertFinished(client)
 
509
        client.finished_test()
593
510
 
594
511
    def test_branch_missing(self):
595
512
        transport = MemoryTransport()
601
518
            _client=client)
602
519
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
603
520
        self.assertEqual(
604
 
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
 
521
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
605
522
            client._calls)
606
523
 
607
524
    def test__get_tree_branch(self):
608
525
        # _get_tree_branch is a form of open_branch, but it should only ask for
609
526
        # branch opening, not any other network requests.
610
527
        calls = []
611
 
        def open_branch(name=None):
 
528
        def open_branch():
612
529
            calls.append("Called")
613
530
            return "a-branch"
614
531
        transport = MemoryTransport()
631
548
        network_name = reference_format.network_name()
632
549
        branch_network_name = self.get_branch_format().network_name()
633
550
        client.add_expected_call(
634
 
            'BzrDir.open_branchV3', ('~hello/',),
 
551
            'BzrDir.open_branchV2', ('~hello/',),
635
552
            'success', ('branch', branch_network_name))
636
553
        client.add_expected_call(
637
554
            'BzrDir.find_repositoryV3', ('~hello/',),
642
559
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
643
560
            _client=client)
644
561
        result = bzrdir.open_branch()
645
 
        self.assertFinished(client)
 
562
        client.finished_test()
646
563
 
647
564
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
648
565
        reference_format = self.get_repo_format()
685
602
        old.
686
603
        """
687
604
        self.assertRaises(errors.NotBranchError,
688
 
            RemoteBzrProber.probe_transport, OldServerTransport())
 
605
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
689
606
 
690
607
 
691
608
class TestBzrDirCreateBranch(TestRemote):
746
663
        network_name = reference_format.network_name()
747
664
        client.add_expected_call(
748
665
            'BzrDir.create_repository', ('quack/',
749
 
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
750
 
                'False'),
751
 
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
 
666
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
 
667
            'success', ('ok', 'no', 'no', 'no', network_name))
752
668
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
753
669
            _client=client)
754
670
        repo = a_bzrdir.create_repository()
756
672
        self.assertIsInstance(repo, remote.RemoteRepository)
757
673
        # its format should have the settings from the response
758
674
        format = repo._format
759
 
        self.assertTrue(format.rich_root_data)
760
 
        self.assertTrue(format.supports_tree_reference)
761
 
        self.assertTrue(format.supports_external_lookups)
 
675
        self.assertFalse(format.rich_root_data)
 
676
        self.assertFalse(format.supports_tree_reference)
 
677
        self.assertFalse(format.supports_external_lookups)
762
678
        self.assertEqual(network_name, format.network_name())
763
679
 
764
680
 
768
684
        # fallback all the way to the first version.
769
685
        reference_format = self.get_repo_format()
770
686
        network_name = reference_format.network_name()
771
 
        server_url = 'bzr://example.com/'
772
 
        self.permit_url(server_url)
773
 
        client = FakeClient(server_url)
 
687
        client = FakeClient('bzr://example.com/')
774
688
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
775
689
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
776
690
        client.add_success_response('ok', '', 'no', 'no')
782
696
            reference_format.get_format_string(), 'ok')
783
697
        # PackRepository wants to do a stat
784
698
        client.add_success_response('stat', '0', '65535')
785
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
699
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
786
700
            _client=client)
787
701
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
788
702
            _client=client)
802
716
        # fallback to find_repositoryV2
803
717
        reference_format = self.get_repo_format()
804
718
        network_name = reference_format.network_name()
805
 
        server_url = 'bzr://example.com/'
806
 
        self.permit_url(server_url)
807
 
        client = FakeClient(server_url)
 
719
        client = FakeClient('bzr://example.com/')
808
720
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
809
721
        client.add_success_response('ok', '', 'no', 'no', 'no')
810
722
        # A real repository instance will be created to determine the network
815
727
            reference_format.get_format_string(), 'ok')
816
728
        # PackRepository wants to do a stat
817
729
        client.add_success_response('stat', '0', '65535')
818
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
730
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
819
731
            _client=client)
820
732
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
821
733
            _client=client)
867
779
        # transport connected to a real server.
868
780
        result = fmt._initialize_on_transport_ex_rpc(client, 'path',
869
781
            transport, False, False, False, None, None, None, None, False)
870
 
        self.assertFinished(client)
 
782
        client.finished_test()
871
783
 
872
784
    def test_error(self):
873
785
        """Error responses are translated, e.g. 'PermissionDenied' raises the
891
803
            False, False, False, None, None, None, None, False)
892
804
        self.assertEqual('path', err.path)
893
805
        self.assertEqual(': extra info', err.extra)
894
 
        self.assertFinished(client)
 
806
        client.finished_test()
895
807
 
896
808
    def test_error_from_real_server(self):
897
809
        """Integration test for error translation."""
940
852
 
941
853
class RemoteBranchTestCase(RemoteBzrDirTestCase):
942
854
 
943
 
    def lock_remote_branch(self, branch):
944
 
        """Trick a RemoteBranch into thinking it is locked."""
945
 
        branch._lock_mode = 'w'
946
 
        branch._lock_count = 2
947
 
        branch._lock_token = 'branch token'
948
 
        branch._repo_lock_token = 'repo token'
949
 
        branch.repository._lock_mode = 'w'
950
 
        branch.repository._lock_count = 2
951
 
        branch.repository._lock_token = 'repo token'
952
 
 
953
855
    def make_remote_branch(self, transport, client):
954
856
        """Make a RemoteBranch using 'client' as its _SmartClient.
955
857
 
982
884
        transport = transport.clone('quack')
983
885
        branch = self.make_remote_branch(transport, client)
984
886
        result = branch.get_parent()
985
 
        self.assertFinished(client)
 
887
        client.finished_test()
986
888
        self.assertEqual(None, result)
987
889
 
988
890
    def test_parent_relative(self):
1014
916
        branch = self.make_remote_branch(transport, client)
1015
917
        result = branch.get_parent()
1016
918
        self.assertEqual('http://foo/', result)
1017
 
        self.assertFinished(client)
 
919
        client.finished_test()
1018
920
 
1019
921
 
1020
922
class TestBranchSetParentLocation(RemoteBranchTestCase):
1035
937
        branch._lock_token = 'b'
1036
938
        branch._repo_lock_token = 'r'
1037
939
        branch._set_parent_location(None)
1038
 
        self.assertFinished(client)
 
940
        client.finished_test()
1039
941
 
1040
942
    def test_parent(self):
1041
943
        transport = MemoryTransport()
1052
954
        branch._lock_token = 'b'
1053
955
        branch._repo_lock_token = 'r'
1054
956
        branch._set_parent_location('foo')
1055
 
        self.assertFinished(client)
 
957
        client.finished_test()
1056
958
 
1057
959
    def test_backwards_compat(self):
1058
960
        self.setup_smart_server_with_call_log()
1090
992
        transport = transport.clone('quack')
1091
993
        branch = self.make_remote_branch(transport, client)
1092
994
        result = branch.tags.get_tag_dict()
1093
 
        self.assertFinished(client)
 
995
        client.finished_test()
1094
996
        self.assertEqual({}, result)
1095
997
 
1096
998
 
1097
 
class TestBranchSetTagsBytes(RemoteBranchTestCase):
1098
 
 
1099
 
    def test_trivial(self):
1100
 
        transport = MemoryTransport()
1101
 
        client = FakeClient(transport.base)
1102
 
        client.add_expected_call(
1103
 
            'Branch.get_stacked_on_url', ('quack/',),
1104
 
            'error', ('NotStacked',))
1105
 
        client.add_expected_call(
1106
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1107
 
            'success', ('',))
1108
 
        transport.mkdir('quack')
1109
 
        transport = transport.clone('quack')
1110
 
        branch = self.make_remote_branch(transport, client)
1111
 
        self.lock_remote_branch(branch)
1112
 
        branch._set_tags_bytes('tags bytes')
1113
 
        self.assertFinished(client)
1114
 
        self.assertEqual('tags bytes', client._calls[-1][-1])
1115
 
 
1116
 
    def test_backwards_compatible(self):
1117
 
        transport = MemoryTransport()
1118
 
        client = FakeClient(transport.base)
1119
 
        client.add_expected_call(
1120
 
            'Branch.get_stacked_on_url', ('quack/',),
1121
 
            'error', ('NotStacked',))
1122
 
        client.add_expected_call(
1123
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1124
 
            'unknown', ('Branch.set_tags_bytes',))
1125
 
        transport.mkdir('quack')
1126
 
        transport = transport.clone('quack')
1127
 
        branch = self.make_remote_branch(transport, client)
1128
 
        self.lock_remote_branch(branch)
1129
 
        class StubRealBranch(object):
1130
 
            def __init__(self):
1131
 
                self.calls = []
1132
 
            def _set_tags_bytes(self, bytes):
1133
 
                self.calls.append(('set_tags_bytes', bytes))
1134
 
        real_branch = StubRealBranch()
1135
 
        branch._real_branch = real_branch
1136
 
        branch._set_tags_bytes('tags bytes')
1137
 
        # Call a second time, to exercise the 'remote version already inferred'
1138
 
        # code path.
1139
 
        branch._set_tags_bytes('tags bytes')
1140
 
        self.assertFinished(client)
1141
 
        self.assertEqual(
1142
 
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1143
 
 
1144
 
 
1145
999
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1146
1000
 
1147
1001
    def test_empty_branch(self):
1158
1012
        transport = transport.clone('quack')
1159
1013
        branch = self.make_remote_branch(transport, client)
1160
1014
        result = branch.last_revision_info()
1161
 
        self.assertFinished(client)
 
1015
        client.finished_test()
1162
1016
        self.assertEqual((0, NULL_REVISION), result)
1163
1017
 
1164
1018
    def test_non_empty_branch(self):
1219
1073
        client = FakeClient(self.get_url())
1220
1074
        branch_network_name = self.get_branch_format().network_name()
1221
1075
        client.add_expected_call(
1222
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1076
            'BzrDir.open_branchV2', ('stacked/',),
1223
1077
            'success', ('branch', branch_network_name))
1224
1078
        client.add_expected_call(
1225
1079
            'BzrDir.find_repositoryV3', ('stacked/',),
1239
1093
        branch = bzrdir.open_branch()
1240
1094
        result = branch.get_stacked_on_url()
1241
1095
        self.assertEqual('../base', result)
1242
 
        self.assertFinished(client)
 
1096
        client.finished_test()
1243
1097
        # it's in the fallback list both for the RemoteRepository and its vfs
1244
1098
        # repository
1245
1099
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1247
1101
            len(branch.repository._real_repository._fallback_repositories))
1248
1102
 
1249
1103
    def test_get_stacked_on_real_branch(self):
1250
 
        base_branch = self.make_branch('base')
1251
 
        stacked_branch = self.make_branch('stacked')
 
1104
        base_branch = self.make_branch('base', format='1.6')
 
1105
        stacked_branch = self.make_branch('stacked', format='1.6')
1252
1106
        stacked_branch.set_stacked_on_url('../base')
1253
1107
        reference_format = self.get_repo_format()
1254
1108
        network_name = reference_format.network_name()
1255
1109
        client = FakeClient(self.get_url())
1256
1110
        branch_network_name = self.get_branch_format().network_name()
1257
1111
        client.add_expected_call(
1258
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1112
            'BzrDir.open_branchV2', ('stacked/',),
1259
1113
            'success', ('branch', branch_network_name))
1260
1114
        client.add_expected_call(
1261
1115
            'BzrDir.find_repositoryV3', ('stacked/',),
1262
 
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
 
1116
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
1263
1117
        # called twice, once from constructor and then again by us
1264
1118
        client.add_expected_call(
1265
1119
            'Branch.get_stacked_on_url', ('stacked/',),
1272
1126
        branch = bzrdir.open_branch()
1273
1127
        result = branch.get_stacked_on_url()
1274
1128
        self.assertEqual('../base', result)
1275
 
        self.assertFinished(client)
 
1129
        client.finished_test()
1276
1130
        # it's in the fallback list both for the RemoteRepository.
1277
1131
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1278
1132
        # And we haven't had to construct a real repository.
1313
1167
        result = branch.set_revision_history([])
1314
1168
        branch.unlock()
1315
1169
        self.assertEqual(None, result)
1316
 
        self.assertFinished(client)
 
1170
        client.finished_test()
1317
1171
 
1318
1172
    def test_set_nonempty(self):
1319
1173
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1351
1205
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1352
1206
        branch.unlock()
1353
1207
        self.assertEqual(None, result)
1354
 
        self.assertFinished(client)
 
1208
        client.finished_test()
1355
1209
 
1356
1210
    def test_no_such_revision(self):
1357
1211
        transport = MemoryTransport()
1386
1240
        self.assertRaises(
1387
1241
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1388
1242
        branch.unlock()
1389
 
        self.assertFinished(client)
 
1243
        client.finished_test()
1390
1244
 
1391
1245
    def test_tip_change_rejected(self):
1392
1246
        """TipChangeRejected responses cause a TipChangeRejected exception to
1429
1283
        self.assertIsInstance(err.msg, unicode)
1430
1284
        self.assertEqual(rejection_msg_unicode, err.msg)
1431
1285
        branch.unlock()
1432
 
        self.assertFinished(client)
 
1286
        client.finished_test()
1433
1287
 
1434
1288
 
1435
1289
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
1489
1343
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1490
1344
        branch.unlock()
1491
1345
 
 
1346
    def lock_remote_branch(self, branch):
 
1347
        """Trick a RemoteBranch into thinking it is locked."""
 
1348
        branch._lock_mode = 'w'
 
1349
        branch._lock_count = 2
 
1350
        branch._lock_token = 'branch token'
 
1351
        branch._repo_lock_token = 'repo token'
 
1352
        branch.repository._lock_mode = 'w'
 
1353
        branch.repository._lock_count = 2
 
1354
        branch.repository._lock_token = 'repo token'
 
1355
 
1492
1356
    def test_backwards_compatibility(self):
1493
1357
        """If the server does not support the Branch.set_last_revision_info
1494
1358
        verb (which is new in 1.4), then the client falls back to VFS methods.
1535
1399
        self.assertEqual(
1536
1400
            [('set_last_revision_info', 1234, 'a-revision-id')],
1537
1401
            real_branch.calls)
1538
 
        self.assertFinished(client)
 
1402
        client.finished_test()
1539
1403
 
1540
1404
    def test_unexpected_error(self):
1541
1405
        # If the server sends an error the client doesn't understand, it gets
1617
1481
    def test_get_multi_line_branch_conf(self):
1618
1482
        # Make sure that multiple-line branch.conf files are supported
1619
1483
        #
1620
 
        # https://bugs.launchpad.net/bzr/+bug/354075
 
1484
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1621
1485
        client = FakeClient()
1622
1486
        client.add_expected_call(
1623
1487
            'Branch.get_stacked_on_url', ('memory:///',),
1649
1513
        config = branch._get_config()
1650
1514
        config.set_option('foo', 'bar')
1651
1515
        branch.unlock()
1652
 
        self.assertFinished(client)
1653
 
 
1654
 
    def test_set_option_with_dict(self):
1655
 
        client = FakeClient()
1656
 
        client.add_expected_call(
1657
 
            'Branch.get_stacked_on_url', ('memory:///',),
1658
 
            'error', ('NotStacked',),)
1659
 
        client.add_expected_call(
1660
 
            'Branch.lock_write', ('memory:///', '', ''),
1661
 
            'success', ('ok', 'branch token', 'repo token'))
1662
 
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1663
 
        client.add_expected_call(
1664
 
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
1665
 
            'repo token', encoded_dict_value, 'foo', ''),
1666
 
            'success', ())
1667
 
        client.add_expected_call(
1668
 
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1669
 
            'success', ('ok',))
1670
 
        transport = MemoryTransport()
1671
 
        branch = self.make_remote_branch(transport, client)
1672
 
        branch.lock_write()
1673
 
        config = branch._get_config()
1674
 
        config.set_option(
1675
 
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1676
 
            'foo')
1677
 
        branch.unlock()
1678
 
        self.assertFinished(client)
 
1516
        client.finished_test()
1679
1517
 
1680
1518
    def test_backwards_compat_set_option(self):
1681
1519
        self.setup_smart_server_with_call_log()
1689
1527
        self.assertLength(10, self.hpss_calls)
1690
1528
        self.assertEqual('value', branch._get_config().get_option('name'))
1691
1529
 
1692
 
    def test_backwards_compat_set_option_with_dict(self):
1693
 
        self.setup_smart_server_with_call_log()
1694
 
        branch = self.make_branch('.')
1695
 
        verb = 'Branch.set_config_option_dict'
1696
 
        self.disable_verb(verb)
1697
 
        branch.lock_write()
1698
 
        self.addCleanup(branch.unlock)
1699
 
        self.reset_smart_call_log()
1700
 
        config = branch._get_config()
1701
 
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1702
 
        config.set_option(value_dict, 'name')
1703
 
        self.assertLength(10, self.hpss_calls)
1704
 
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
1705
 
 
1706
1530
 
1707
1531
class TestBranchLockWrite(RemoteBranchTestCase):
1708
1532
 
1719
1543
        transport = transport.clone('quack')
1720
1544
        branch = self.make_remote_branch(transport, client)
1721
1545
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
1722
 
        self.assertFinished(client)
 
1546
        client.finished_test()
1723
1547
 
1724
1548
 
1725
1549
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1850
1674
        return repo, client
1851
1675
 
1852
1676
 
1853
 
def remoted_description(format):
1854
 
    return 'Remote: ' + format.get_format_description()
1855
 
 
1856
 
 
1857
 
class TestBranchFormat(tests.TestCase):
1858
 
 
1859
 
    def test_get_format_description(self):
1860
 
        remote_format = RemoteBranchFormat()
1861
 
        real_format = branch.BranchFormat.get_default_format()
1862
 
        remote_format._network_name = real_format.network_name()
1863
 
        self.assertEqual(remoted_description(real_format),
1864
 
            remote_format.get_format_description())
1865
 
 
1866
 
 
1867
1677
class TestRepositoryFormat(TestRemoteRepository):
1868
1678
 
1869
1679
    def test_fast_delta(self):
1876
1686
        false_format._network_name = false_name
1877
1687
        self.assertEqual(False, false_format.fast_deltas)
1878
1688
 
1879
 
    def test_get_format_description(self):
1880
 
        remote_repo_format = RemoteRepositoryFormat()
1881
 
        real_format = repository.RepositoryFormat.get_default_format()
1882
 
        remote_repo_format._network_name = real_format.network_name()
1883
 
        self.assertEqual(remoted_description(real_format),
1884
 
            remote_repo_format.get_format_description())
1885
 
 
1886
1689
 
1887
1690
class TestRepositoryGatherStats(TestRemoteRepository):
1888
1691
 
2073
1876
        self.assertLength(1, self.hpss_calls)
2074
1877
 
2075
1878
    def disableExtraResults(self):
2076
 
        self.overrideAttr(SmartServerRepositoryGetParentMap,
2077
 
                          'no_extra_results', True)
 
1879
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
 
1880
        SmartServerRepositoryGetParentMap.no_extra_results = True
 
1881
        def reset_values():
 
1882
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
 
1883
        self.addCleanup(reset_values)
2078
1884
 
2079
1885
    def test_null_cached_missing_and_stop_key(self):
2080
1886
        self.setup_smart_server_with_call_log()
2139
1945
 
2140
1946
    def test_allows_new_revisions(self):
2141
1947
        """get_parent_map's results can be updated by commit."""
2142
 
        smart_server = test_server.SmartTCPServer_for_testing()
2143
 
        self.start_server(smart_server)
 
1948
        smart_server = server.SmartTCPServer_for_testing()
 
1949
        smart_server.setUp()
 
1950
        self.addCleanup(smart_server.tearDown)
2144
1951
        self.make_branch('branch')
2145
1952
        branch = Branch.open(smart_server.get_url() + '/branch')
2146
1953
        tree = branch.create_checkout('tree', lightweight=True)
2238
2045
            'success', ('ok', 'rev-five'))
2239
2046
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2240
2047
        self.assertEqual((True, 'rev-five'), result)
2241
 
        self.assertFinished(client)
 
2048
        client.finished_test()
2242
2049
 
2243
2050
    def test_history_incomplete(self):
2244
2051
        repo, client = self.setup_fake_client_and_repository('quack')
2247
2054
            'success', ('history-incomplete', 10, 'rev-ten'))
2248
2055
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2249
2056
        self.assertEqual((False, (10, 'rev-ten')), result)
2250
 
        self.assertFinished(client)
 
2057
        client.finished_test()
2251
2058
 
2252
2059
    def test_history_incomplete_with_fallback(self):
2253
2060
        """A 'history-incomplete' response causes the fallback repository to be
2255
2062
        """
2256
2063
        # Make a repo with a fallback repo, both using a FakeClient.
2257
2064
        format = remote.response_tuple_to_repo_format(
2258
 
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
 
2065
            ('yes', 'no', 'yes', 'fake-network-name'))
2259
2066
        repo, client = self.setup_fake_client_and_repository('quack')
2260
2067
        repo._format = format
2261
2068
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2262
2069
            'fallback')
2263
2070
        fallback_repo._client = client
2264
 
        fallback_repo._format = format
2265
2071
        repo.add_fallback_repository(fallback_repo)
2266
2072
        # First the client should ask the primary repo
2267
2073
        client.add_expected_call(
2274
2080
            'success', ('ok', 'rev-one'))
2275
2081
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2276
2082
        self.assertEqual((True, 'rev-one'), result)
2277
 
        self.assertFinished(client)
 
2083
        client.finished_test()
2278
2084
 
2279
2085
    def test_nosuchrevision(self):
2280
2086
        # 'nosuchrevision' is returned when the known-revid is not found in the
2286
2092
        self.assertRaises(
2287
2093
            errors.NoSuchRevision,
2288
2094
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2289
 
        self.assertFinished(client)
2290
 
 
2291
 
    def test_branch_fallback_locking(self):
2292
 
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
2293
 
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
2294
 
        will be invoked, which will fail if the repo is unlocked.
2295
 
        """
2296
 
        self.setup_smart_server_with_call_log()
2297
 
        tree = self.make_branch_and_memory_tree('.')
2298
 
        tree.lock_write()
2299
 
        tree.add('')
2300
 
        rev1 = tree.commit('First')
2301
 
        rev2 = tree.commit('Second')
2302
 
        tree.unlock()
2303
 
        branch = tree.branch
2304
 
        self.assertFalse(branch.is_locked())
2305
 
        self.reset_smart_call_log()
2306
 
        verb = 'Repository.get_rev_id_for_revno'
2307
 
        self.disable_verb(verb)
2308
 
        self.assertEqual(rev1, branch.get_rev_id(1))
2309
 
        self.assertLength(1, [call for call in self.hpss_calls if
2310
 
                              call.call.method == verb])
 
2095
        client.finished_test()
2311
2096
 
2312
2097
 
2313
2098
class TestRepositoryIsShared(TestRemoteRepository):
2341
2126
        transport_path = 'quack'
2342
2127
        repo, client = self.setup_fake_client_and_repository(transport_path)
2343
2128
        client.add_success_response('ok', 'a token')
2344
 
        token = repo.lock_write().repository_token
 
2129
        result = repo.lock_write()
2345
2130
        self.assertEqual(
2346
2131
            [('call', 'Repository.lock_write', ('quack/', ''))],
2347
2132
            client._calls)
2348
 
        self.assertEqual('a token', token)
 
2133
        self.assertEqual('a token', result)
2349
2134
 
2350
2135
    def test_lock_write_already_locked(self):
2351
2136
        transport_path = 'quack'
2430
2215
        self.assertEqual([], client._calls)
2431
2216
 
2432
2217
 
2433
 
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2434
 
    """Base class for Repository.insert_stream and .insert_stream_1.19
2435
 
    tests.
2436
 
    """
2437
 
    
2438
 
    def checkInsertEmptyStream(self, repo, client):
2439
 
        """Insert an empty stream, checking the result.
2440
 
 
2441
 
        This checks that there are no resume_tokens or missing_keys, and that
2442
 
        the client is finished.
2443
 
        """
2444
 
        sink = repo._get_sink()
2445
 
        fmt = repository.RepositoryFormat.get_default_format()
2446
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2447
 
        self.assertEqual([], resume_tokens)
2448
 
        self.assertEqual(set(), missing_keys)
2449
 
        self.assertFinished(client)
2450
 
 
2451
 
 
2452
 
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
2453
 
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
2454
 
    not available.
2455
 
 
2456
 
    This test case is very similar to TestRepositoryInsertStream_1_19.
2457
 
    """
2458
 
 
2459
 
    def setUp(self):
2460
 
        TestRemoteRepository.setUp(self)
2461
 
        self.disable_verb('Repository.insert_stream_1.19')
2462
 
 
2463
 
    def test_unlocked_repo(self):
2464
 
        transport_path = 'quack'
2465
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2466
 
        client.add_expected_call(
2467
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2468
 
            'unknown', ('Repository.insert_stream_1.19',))
2469
 
        client.add_expected_call(
2470
 
            'Repository.insert_stream', ('quack/', ''),
2471
 
            'success', ('ok',))
2472
 
        client.add_expected_call(
2473
 
            'Repository.insert_stream', ('quack/', ''),
2474
 
            'success', ('ok',))
2475
 
        self.checkInsertEmptyStream(repo, client)
2476
 
 
2477
 
    def test_locked_repo_with_no_lock_token(self):
2478
 
        transport_path = 'quack'
2479
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2480
 
        client.add_expected_call(
2481
 
            'Repository.lock_write', ('quack/', ''),
2482
 
            'success', ('ok', ''))
2483
 
        client.add_expected_call(
2484
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2485
 
            'unknown', ('Repository.insert_stream_1.19',))
2486
 
        client.add_expected_call(
2487
 
            'Repository.insert_stream', ('quack/', ''),
2488
 
            'success', ('ok',))
2489
 
        client.add_expected_call(
2490
 
            'Repository.insert_stream', ('quack/', ''),
2491
 
            'success', ('ok',))
2492
 
        repo.lock_write()
2493
 
        self.checkInsertEmptyStream(repo, client)
2494
 
 
2495
 
    def test_locked_repo_with_lock_token(self):
2496
 
        transport_path = 'quack'
2497
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2498
 
        client.add_expected_call(
2499
 
            'Repository.lock_write', ('quack/', ''),
2500
 
            'success', ('ok', 'a token'))
2501
 
        client.add_expected_call(
2502
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2503
 
            'unknown', ('Repository.insert_stream_1.19',))
2504
 
        client.add_expected_call(
2505
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2506
 
            'success', ('ok',))
2507
 
        client.add_expected_call(
2508
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2509
 
            'success', ('ok',))
2510
 
        repo.lock_write()
2511
 
        self.checkInsertEmptyStream(repo, client)
2512
 
 
2513
 
    def test_stream_with_inventory_deltas(self):
2514
 
        """'inventory-deltas' substreams cannot be sent to the
2515
 
        Repository.insert_stream verb, because not all servers that implement
2516
 
        that verb will accept them.  So when one is encountered the RemoteSink
2517
 
        immediately stops using that verb and falls back to VFS insert_stream.
2518
 
        """
2519
 
        transport_path = 'quack'
2520
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2521
 
        client.add_expected_call(
2522
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2523
 
            'unknown', ('Repository.insert_stream_1.19',))
2524
 
        client.add_expected_call(
2525
 
            'Repository.insert_stream', ('quack/', ''),
2526
 
            'success', ('ok',))
2527
 
        client.add_expected_call(
2528
 
            'Repository.insert_stream', ('quack/', ''),
2529
 
            'success', ('ok',))
2530
 
        # Create a fake real repository for insert_stream to fall back on, so
2531
 
        # that we can directly see the records the RemoteSink passes to the
2532
 
        # real sink.
2533
 
        class FakeRealSink:
2534
 
            def __init__(self):
2535
 
                self.records = []
2536
 
            def insert_stream(self, stream, src_format, resume_tokens):
2537
 
                for substream_kind, substream in stream:
2538
 
                    self.records.append(
2539
 
                        (substream_kind, [record.key for record in substream]))
2540
 
                return ['fake tokens'], ['fake missing keys']
2541
 
        fake_real_sink = FakeRealSink()
2542
 
        class FakeRealRepository:
2543
 
            def _get_sink(self):
2544
 
                return fake_real_sink
2545
 
            def is_in_write_group(self):
2546
 
                return False
2547
 
            def refresh_data(self):
2548
 
                return True
2549
 
        repo._real_repository = FakeRealRepository()
2550
 
        sink = repo._get_sink()
2551
 
        fmt = repository.RepositoryFormat.get_default_format()
2552
 
        stream = self.make_stream_with_inv_deltas(fmt)
2553
 
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2554
 
        # Every record from the first inventory delta should have been sent to
2555
 
        # the VFS sink.
2556
 
        expected_records = [
2557
 
            ('inventory-deltas', [('rev2',), ('rev3',)]),
2558
 
            ('texts', [('some-rev', 'some-file')])]
2559
 
        self.assertEqual(expected_records, fake_real_sink.records)
2560
 
        # The return values from the real sink's insert_stream are propagated
2561
 
        # back to the original caller.
2562
 
        self.assertEqual(['fake tokens'], resume_tokens)
2563
 
        self.assertEqual(['fake missing keys'], missing_keys)
2564
 
        self.assertFinished(client)
2565
 
 
2566
 
    def make_stream_with_inv_deltas(self, fmt):
2567
 
        """Make a simple stream with an inventory delta followed by more
2568
 
        records and more substreams to test that all records and substreams
2569
 
        from that point on are used.
2570
 
 
2571
 
        This sends, in order:
2572
 
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
2573
 
             inventory-deltas.
2574
 
           * texts substream: (some-rev, some-file)
2575
 
        """
2576
 
        # Define a stream using generators so that it isn't rewindable.
2577
 
        inv = inventory.Inventory(revision_id='rev1')
2578
 
        inv.root.revision = 'rev1'
2579
 
        def stream_with_inv_delta():
2580
 
            yield ('inventories', inventories_substream())
2581
 
            yield ('inventory-deltas', inventory_delta_substream())
2582
 
            yield ('texts', [
2583
 
                versionedfile.FulltextContentFactory(
2584
 
                    ('some-rev', 'some-file'), (), None, 'content')])
2585
 
        def inventories_substream():
2586
 
            # An empty inventory fulltext.  This will be streamed normally.
2587
 
            text = fmt._serializer.write_inventory_to_string(inv)
2588
 
            yield versionedfile.FulltextContentFactory(
2589
 
                ('rev1',), (), None, text)
2590
 
        def inventory_delta_substream():
2591
 
            # An inventory delta.  This can't be streamed via this verb, so it
2592
 
            # will trigger a fallback to VFS insert_stream.
2593
 
            entry = inv.make_entry(
2594
 
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
2595
 
            entry.revision = 'ghost'
2596
 
            delta = [(None, 'newdir', 'newdir-id', entry)]
2597
 
            serializer = inventory_delta.InventoryDeltaSerializer(
2598
 
                versioned_root=True, tree_references=False)
2599
 
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
2600
 
            yield versionedfile.ChunkedContentFactory(
2601
 
                ('rev2',), (('rev1',)), None, lines)
2602
 
            # Another delta.
2603
 
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
2604
 
            yield versionedfile.ChunkedContentFactory(
2605
 
                ('rev3',), (('rev1',)), None, lines)
2606
 
        return stream_with_inv_delta()
2607
 
 
2608
 
 
2609
 
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
2610
 
 
2611
 
    def test_unlocked_repo(self):
2612
 
        transport_path = 'quack'
2613
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2614
 
        client.add_expected_call(
2615
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2616
 
            'success', ('ok',))
2617
 
        client.add_expected_call(
2618
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2619
 
            'success', ('ok',))
2620
 
        self.checkInsertEmptyStream(repo, client)
2621
 
 
2622
 
    def test_locked_repo_with_no_lock_token(self):
2623
 
        transport_path = 'quack'
2624
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2625
 
        client.add_expected_call(
2626
 
            'Repository.lock_write', ('quack/', ''),
2627
 
            'success', ('ok', ''))
2628
 
        client.add_expected_call(
2629
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2630
 
            'success', ('ok',))
2631
 
        client.add_expected_call(
2632
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2633
 
            'success', ('ok',))
2634
 
        repo.lock_write()
2635
 
        self.checkInsertEmptyStream(repo, client)
2636
 
 
2637
 
    def test_locked_repo_with_lock_token(self):
2638
 
        transport_path = 'quack'
2639
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2640
 
        client.add_expected_call(
2641
 
            'Repository.lock_write', ('quack/', ''),
2642
 
            'success', ('ok', 'a token'))
2643
 
        client.add_expected_call(
2644
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2645
 
            'success', ('ok',))
2646
 
        client.add_expected_call(
2647
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2648
 
            'success', ('ok',))
2649
 
        repo.lock_write()
2650
 
        self.checkInsertEmptyStream(repo, client)
 
2218
class TestRepositoryInsertStream(TestRemoteRepository):
 
2219
 
 
2220
    def test_unlocked_repo(self):
 
2221
        transport_path = 'quack'
 
2222
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2223
        client.add_expected_call(
 
2224
            'Repository.insert_stream', ('quack/', ''),
 
2225
            'success', ('ok',))
 
2226
        client.add_expected_call(
 
2227
            'Repository.insert_stream', ('quack/', ''),
 
2228
            'success', ('ok',))
 
2229
        sink = repo._get_sink()
 
2230
        fmt = repository.RepositoryFormat.get_default_format()
 
2231
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2232
        self.assertEqual([], resume_tokens)
 
2233
        self.assertEqual(set(), missing_keys)
 
2234
        client.finished_test()
 
2235
 
 
2236
    def test_locked_repo_with_no_lock_token(self):
 
2237
        transport_path = 'quack'
 
2238
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2239
        client.add_expected_call(
 
2240
            'Repository.lock_write', ('quack/', ''),
 
2241
            'success', ('ok', ''))
 
2242
        client.add_expected_call(
 
2243
            'Repository.insert_stream', ('quack/', ''),
 
2244
            'success', ('ok',))
 
2245
        client.add_expected_call(
 
2246
            'Repository.insert_stream', ('quack/', ''),
 
2247
            'success', ('ok',))
 
2248
        repo.lock_write()
 
2249
        sink = repo._get_sink()
 
2250
        fmt = repository.RepositoryFormat.get_default_format()
 
2251
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2252
        self.assertEqual([], resume_tokens)
 
2253
        self.assertEqual(set(), missing_keys)
 
2254
        client.finished_test()
 
2255
 
 
2256
    def test_locked_repo_with_lock_token(self):
 
2257
        transport_path = 'quack'
 
2258
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2259
        client.add_expected_call(
 
2260
            'Repository.lock_write', ('quack/', ''),
 
2261
            'success', ('ok', 'a token'))
 
2262
        client.add_expected_call(
 
2263
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2264
            'success', ('ok',))
 
2265
        client.add_expected_call(
 
2266
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2267
            'success', ('ok',))
 
2268
        repo.lock_write()
 
2269
        sink = repo._get_sink()
 
2270
        fmt = repository.RepositoryFormat.get_default_format()
 
2271
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2272
        self.assertEqual([], resume_tokens)
 
2273
        self.assertEqual(set(), missing_keys)
 
2274
        client.finished_test()
2651
2275
 
2652
2276
 
2653
2277
class TestRepositoryTarball(TestRemoteRepository):
2689
2313
    """RemoteRepository.copy_content_into optimizations"""
2690
2314
 
2691
2315
    def test_copy_content_remote_to_local(self):
2692
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2316
        self.transport_server = server.SmartTCPServer_for_testing
2693
2317
        src_repo = self.make_repository('repo1')
2694
2318
        src_repo = repository.Repository.open(self.get_url('repo1'))
2695
2319
        # At the moment the tarball-based copy_content_into can't write back
2738
2362
        client.add_expected_call(
2739
2363
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
2740
2364
        repo.autopack()
2741
 
        self.assertFinished(client)
 
2365
        client.finished_test()
2742
2366
 
2743
2367
    def test_ok_with_real_repo(self):
2744
2368
        """When the server returns 'ok' and there is a _real_repository, then
2843
2467
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2844
2468
        self.assertEqual(expected_error, translated_error)
2845
2469
 
2846
 
    def test_nobranch_one_arg(self):
2847
 
        bzrdir = self.make_bzrdir('')
2848
 
        translated_error = self.translateTuple(
2849
 
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
2850
 
        expected_error = errors.NotBranchError(
2851
 
            path=bzrdir.root_transport.base,
2852
 
            detail='extra detail')
2853
 
        self.assertEqual(expected_error, translated_error)
2854
 
 
2855
2470
    def test_LockContention(self):
2856
2471
        translated_error = self.translateTuple(('LockContention',))
2857
2472
        expected_error = errors.LockContention('(remote lock)')
2897
2512
        expected_error = errors.ReadError(path)
2898
2513
        self.assertEqual(expected_error, translated_error)
2899
2514
 
2900
 
    def test_IncompatibleRepositories(self):
2901
 
        translated_error = self.translateTuple(('IncompatibleRepositories',
2902
 
            "repo1", "repo2", "details here"))
2903
 
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2904
 
            "details here")
2905
 
        self.assertEqual(expected_error, translated_error)
2906
 
 
2907
2515
    def test_PermissionDenied_no_args(self):
2908
2516
        path = 'a path'
2909
2517
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2970
2578
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2971
2579
        # been muttered to the log file for developer to look at.
2972
2580
        self.assertContainsRe(
2973
 
            self.get_log(),
 
2581
            self._get_log(keep_log_file=True),
2974
2582
            "Missing key 'branch' in context")
2975
2583
 
2976
2584
    def test_path_missing(self):
2984
2592
        self.assertEqual(server_error, translated_error)
2985
2593
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2986
2594
        # been muttered to the log file for developer to look at.
2987
 
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
 
2595
        self.assertContainsRe(
 
2596
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
2988
2597
 
2989
2598
 
2990
2599
class TestStacking(tests.TestCaseWithTransport):
3008
2617
        stacked_branch = self.make_branch('stacked', format='1.9')
3009
2618
        stacked_branch.set_stacked_on_url('../base')
3010
2619
        # start a server looking at this
3011
 
        smart_server = test_server.SmartTCPServer_for_testing()
3012
 
        self.start_server(smart_server)
 
2620
        smart_server = server.SmartTCPServer_for_testing()
 
2621
        smart_server.setUp()
 
2622
        self.addCleanup(smart_server.tearDown)
3013
2623
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
3014
2624
        # can get its branch and repository
3015
2625
        remote_branch = remote_bzrdir.open_branch()
3037
2647
        tree1.commit('rev1', rev_id='rev1')
3038
2648
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
3039
2649
            ).open_workingtree()
3040
 
        local_tree = tree2.branch.create_checkout('local')
3041
 
        local_tree.commit('local changes make me feel good.')
 
2650
        tree2.commit('local changes make me feel good.')
3042
2651
        branch2 = Branch.open(self.get_url('tree2'))
3043
2652
        branch2.lock_read()
3044
2653
        self.addCleanup(branch2.unlock)
3066
2675
                    result.append(content.key[-1])
3067
2676
        return result
3068
2677
 
3069
 
    def get_ordered_revs(self, format, order, branch_factory=None):
 
2678
    def get_ordered_revs(self, format, order):
3070
2679
        """Get a list of the revisions in a stream to format format.
3071
2680
 
3072
2681
        :param format: The format of the target.
3073
2682
        :param order: the order that target should have requested.
3074
 
        :param branch_factory: A callable to create a trunk and stacked branch
3075
 
            to fetch from. If none, self.prepare_stacked_remote_branch is used.
3076
2683
        :result: The revision ids in the stream, in the order seen,
3077
2684
            the topological order of revisions in the source.
3078
2685
        """
3080
2687
        target_repository_format = unordered_format.repository_format
3081
2688
        # Cross check
3082
2689
        self.assertEqual(order, target_repository_format._fetch_order)
3083
 
        if branch_factory is None:
3084
 
            branch_factory = self.prepare_stacked_remote_branch
3085
 
        _, stacked = branch_factory()
 
2690
        trunk, stacked = self.prepare_stacked_remote_branch()
3086
2691
        source = stacked.repository._get_source(target_repository_format)
3087
2692
        tip = stacked.last_revision()
3088
2693
        revs = stacked.repository.get_ancestry(tip)
3107
2712
        # from the server, then one from the backing branch.
3108
2713
        self.assertLength(2, self.hpss_calls)
3109
2714
 
3110
 
    def test_stacked_on_stacked_get_stream_unordered(self):
3111
 
        # Repository._get_source.get_stream() from a stacked repository which
3112
 
        # is itself stacked yields the full data from all three sources.
3113
 
        def make_stacked_stacked():
3114
 
            _, stacked = self.prepare_stacked_remote_branch()
3115
 
            tree = stacked.bzrdir.sprout('tree3', stacked=True
3116
 
                ).open_workingtree()
3117
 
            local_tree = tree.branch.create_checkout('local-tree3')
3118
 
            local_tree.commit('more local changes are better')
3119
 
            branch = Branch.open(self.get_url('tree3'))
3120
 
            branch.lock_read()
3121
 
            self.addCleanup(branch.unlock)
3122
 
            return None, branch
3123
 
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
3124
 
            branch_factory=make_stacked_stacked)
3125
 
        self.assertEqual(set(expected_revs), set(rev_ord))
3126
 
        # Getting unordered results should have made a streaming data request
3127
 
        # from the server, and one from each backing repo
3128
 
        self.assertLength(3, self.hpss_calls)
3129
 
 
3130
2715
    def test_stacked_get_stream_topological(self):
3131
2716
        # Repository._get_source.get_stream() from a stacked repository with
3132
2717
        # topological sorting yields the full data from both stacked and
3133
2718
        # stacked upon sources in topological order.
3134
2719
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
3135
2720
        self.assertEqual(expected_revs, rev_ord)
3136
 
        # Getting topological sort requires VFS calls still - one of which is
3137
 
        # pushing up from the bound branch.
3138
 
        self.assertLength(13, self.hpss_calls)
 
2721
        # Getting topological sort requires VFS calls still
 
2722
        self.assertLength(12, self.hpss_calls)
3139
2723
 
3140
2724
    def test_stacked_get_stream_groupcompress(self):
3141
2725
        # Repository._get_source.get_stream() from a stacked repository with
3170
2754
        super(TestRemoteBranchEffort, self).setUp()
3171
2755
        # Create a smart server that publishes whatever the backing VFS server
3172
2756
        # does.
3173
 
        self.smart_server = test_server.SmartTCPServer_for_testing()
3174
 
        self.start_server(self.smart_server, self.get_server())
 
2757
        self.smart_server = server.SmartTCPServer_for_testing()
 
2758
        self.smart_server.setUp(self.get_server())
 
2759
        self.addCleanup(self.smart_server.tearDown)
3175
2760
        # Log all HPSS calls into self.hpss_calls.
3176
2761
        _SmartClient.hooks.install_named_hook(
3177
2762
            'call', self.capture_hpss_call, None)