~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Ian Clatworthy
  • Date: 2009-04-03 02:29:30 UTC
  • mto: This revision was merged to the branch mainline in revision 4259.
  • Revision ID: ian.clatworthy@canonical.com-20090403022930-epud0dn5421fp0a0
chk_map code from brisbane-core

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
    config,
32
32
    errors,
33
33
    graph,
34
 
    inventory,
35
 
    inventory_delta,
36
34
    pack,
37
35
    remote,
38
36
    repository,
40
38
    tests,
41
39
    treebuilder,
42
40
    urlutils,
43
 
    versionedfile,
44
41
    )
45
42
from bzrlib.branch import Branch
46
43
from bzrlib.bzrdir import BzrDir, BzrDirFormat
52
49
    RemoteRepository,
53
50
    RemoteRepositoryFormat,
54
51
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
 
52
from bzrlib.repofmt import pack_repo
56
53
from bzrlib.revision import NULL_REVISION
57
54
from bzrlib.smart import server, medium
58
55
from bzrlib.smart.client import _SmartClient
61
58
    condition_isinstance,
62
59
    split_suite_by_condition,
63
60
    multiply_tests,
64
 
    KnownFailure,
65
61
    )
66
62
from bzrlib.transport import get_transport, http
67
63
from bzrlib.transport.memory import MemoryTransport
157
153
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
158
154
        self.assertTrue(r._format.supports_external_lookups)
159
155
 
160
 
    def test_remote_branch_set_append_revisions_only(self):
161
 
        # Make a format 1.9 branch, which supports append_revisions_only
162
 
        branch = self.make_branch('branch', format='1.9')
163
 
        config = branch.get_config()
164
 
        branch.set_append_revisions_only(True)
165
 
        self.assertEqual(
166
 
            'True', config.get_user_option('append_revisions_only'))
167
 
        branch.set_append_revisions_only(False)
168
 
        self.assertEqual(
169
 
            'False', config.get_user_option('append_revisions_only'))
170
 
 
171
 
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
172
 
        branch = self.make_branch('branch', format='knit')
173
 
        config = branch.get_config()
174
 
        self.assertRaises(
175
 
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
176
 
 
177
156
 
178
157
class FakeProtocol(object):
179
158
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
280
259
        self.expecting_body = True
281
260
        return result[1], FakeProtocol(result[2], self)
282
261
 
283
 
    def call_with_body_bytes(self, method, args, body):
284
 
        self._check_call(method, args)
285
 
        self._calls.append(('call_with_body_bytes', method, args, body))
286
 
        result = self._get_next_response()
287
 
        return result[1], FakeProtocol(result[2], self)
288
 
 
289
262
    def call_with_body_bytes_expecting_body(self, method, args, body):
290
263
        self._check_call(method, args)
291
264
        self._calls.append(('call_with_body_bytes_expecting_body', method,
341
314
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
342
315
        return reference_bzrdir_format.repository_format
343
316
 
344
 
    def assertFinished(self, fake_client):
345
 
        """Assert that all of a FakeClient's expected calls have occurred."""
346
 
        fake_client.finished_test()
 
317
    def disable_verb(self, verb):
 
318
        """Disable a verb for one test."""
 
319
        request_handlers = smart.request.request_handlers
 
320
        orig_method = request_handlers.get(verb)
 
321
        request_handlers.remove(verb)
 
322
        def restoreVerb():
 
323
            request_handlers.register(verb, orig_method)
 
324
        self.addCleanup(restoreVerb)
347
325
 
348
326
 
349
327
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
450
428
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
451
429
        self.assertEqual(expected._repository_format, result._repository_format)
452
430
        self.assertEqual(expected._branch_format, result._branch_format)
453
 
        self.assertFinished(client)
 
431
        client.finished_test()
454
432
 
455
433
    def test_current_server(self):
456
434
        transport = self.get_transport('.')
471
449
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
472
450
        self.assertEqual(None, result._repository_format)
473
451
        self.assertEqual(None, result._branch_format)
474
 
        self.assertFinished(client)
 
452
        client.finished_test()
475
453
 
476
454
 
477
455
class TestBzrDirOpenBranch(TestRemote):
510
488
        result = bzrdir.open_branch()
511
489
        self.assertIsInstance(result, RemoteBranch)
512
490
        self.assertEqual(bzrdir, result.bzrdir)
513
 
        self.assertFinished(client)
 
491
        client.finished_test()
514
492
 
515
493
    def test_branch_missing(self):
516
494
        transport = MemoryTransport()
563
541
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
564
542
            _client=client)
565
543
        result = bzrdir.open_branch()
566
 
        self.assertFinished(client)
 
544
        client.finished_test()
567
545
 
568
546
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
569
547
        reference_format = self.get_repo_format()
667
645
        network_name = reference_format.network_name()
668
646
        client.add_expected_call(
669
647
            'BzrDir.create_repository', ('quack/',
670
 
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
671
 
                'False'),
672
 
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
 
648
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
 
649
            'success', ('ok', 'no', 'no', 'no', network_name))
673
650
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
674
651
            _client=client)
675
652
        repo = a_bzrdir.create_repository()
677
654
        self.assertIsInstance(repo, remote.RemoteRepository)
678
655
        # its format should have the settings from the response
679
656
        format = repo._format
680
 
        self.assertTrue(format.rich_root_data)
681
 
        self.assertTrue(format.supports_tree_reference)
682
 
        self.assertTrue(format.supports_external_lookups)
 
657
        self.assertFalse(format.rich_root_data)
 
658
        self.assertFalse(format.supports_tree_reference)
 
659
        self.assertFalse(format.supports_external_lookups)
683
660
        self.assertEqual(network_name, format.network_name())
684
661
 
685
662
 
764
741
        self.assertEqual(network_name, repo._format.network_name())
765
742
 
766
743
 
767
 
class TestBzrDirFormatInitializeEx(TestRemote):
768
 
 
769
 
    def test_success(self):
770
 
        """Simple test for typical successful call."""
771
 
        fmt = bzrdir.RemoteBzrDirFormat()
772
 
        default_format_name = BzrDirFormat.get_default_format().network_name()
773
 
        transport = self.get_transport()
774
 
        client = FakeClient(transport.base)
775
 
        client.add_expected_call(
776
 
            'BzrDirFormat.initialize_ex_1.16',
777
 
                (default_format_name, 'path', 'False', 'False', 'False', '',
778
 
                 '', '', '', 'False'),
779
 
            'success',
780
 
                ('.', 'no', 'no', 'yes', 'repo fmt', 'repo bzrdir fmt',
781
 
                 'bzrdir fmt', 'False', '', '', 'repo lock token'))
782
 
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
783
 
        # it's currently hard to test that without supplying a real remote
784
 
        # transport connected to a real server.
785
 
        result = fmt._initialize_on_transport_ex_rpc(client, 'path',
786
 
            transport, False, False, False, None, None, None, None, False)
787
 
        self.assertFinished(client)
788
 
 
789
 
    def test_error(self):
790
 
        """Error responses are translated, e.g. 'PermissionDenied' raises the
791
 
        corresponding error from the client.
792
 
        """
793
 
        fmt = bzrdir.RemoteBzrDirFormat()
794
 
        default_format_name = BzrDirFormat.get_default_format().network_name()
795
 
        transport = self.get_transport()
796
 
        client = FakeClient(transport.base)
797
 
        client.add_expected_call(
798
 
            'BzrDirFormat.initialize_ex_1.16',
799
 
                (default_format_name, 'path', 'False', 'False', 'False', '',
800
 
                 '', '', '', 'False'),
801
 
            'error',
802
 
                ('PermissionDenied', 'path', 'extra info'))
803
 
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
804
 
        # it's currently hard to test that without supplying a real remote
805
 
        # transport connected to a real server.
806
 
        err = self.assertRaises(errors.PermissionDenied,
807
 
            fmt._initialize_on_transport_ex_rpc, client, 'path', transport,
808
 
            False, False, False, None, None, None, None, False)
809
 
        self.assertEqual('path', err.path)
810
 
        self.assertEqual(': extra info', err.extra)
811
 
        self.assertFinished(client)
812
 
 
813
 
    def test_error_from_real_server(self):
814
 
        """Integration test for error translation."""
815
 
        transport = self.make_smart_server('foo')
816
 
        transport = transport.clone('no-such-path')
817
 
        fmt = bzrdir.RemoteBzrDirFormat()
818
 
        err = self.assertRaises(errors.NoSuchFile,
819
 
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
820
 
 
821
 
 
822
744
class OldSmartClient(object):
823
745
    """A fake smart client for test_old_version that just returns a version one
824
746
    response to the 'hello' (query version) command.
847
769
        return OldSmartClient()
848
770
 
849
771
 
850
 
class RemoteBzrDirTestCase(TestRemote):
851
 
 
852
 
    def make_remote_bzrdir(self, transport, client):
853
 
        """Make a RemotebzrDir using 'client' as the _client."""
854
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
855
 
            _client=client)
856
 
 
857
 
 
858
 
class RemoteBranchTestCase(RemoteBzrDirTestCase):
859
 
 
860
 
    def lock_remote_branch(self, branch):
861
 
        """Trick a RemoteBranch into thinking it is locked."""
862
 
        branch._lock_mode = 'w'
863
 
        branch._lock_count = 2
864
 
        branch._lock_token = 'branch token'
865
 
        branch._repo_lock_token = 'repo token'
866
 
        branch.repository._lock_mode = 'w'
867
 
        branch.repository._lock_count = 2
868
 
        branch.repository._lock_token = 'repo token'
 
772
class RemoteBranchTestCase(TestRemote):
869
773
 
870
774
    def make_remote_branch(self, transport, client):
871
775
        """Make a RemoteBranch using 'client' as its _SmartClient.
876
780
        # we do not want bzrdir to make any remote calls, so use False as its
877
781
        # _client.  If it tries to make a remote call, this will fail
878
782
        # immediately.
879
 
        bzrdir = self.make_remote_bzrdir(transport, False)
 
783
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
784
            _client=False)
880
785
        repo = RemoteRepository(bzrdir, None, _client=client)
881
786
        branch_format = self.get_branch_format()
882
787
        format = RemoteBranchFormat(network_name=branch_format.network_name())
899
804
        transport = transport.clone('quack')
900
805
        branch = self.make_remote_branch(transport, client)
901
806
        result = branch.get_parent()
902
 
        self.assertFinished(client)
 
807
        client.finished_test()
903
808
        self.assertEqual(None, result)
904
809
 
905
810
    def test_parent_relative(self):
931
836
        branch = self.make_remote_branch(transport, client)
932
837
        result = branch.get_parent()
933
838
        self.assertEqual('http://foo/', result)
934
 
        self.assertFinished(client)
935
 
 
936
 
 
937
 
class TestBranchSetParentLocation(RemoteBranchTestCase):
938
 
 
939
 
    def test_no_parent(self):
940
 
        # We call the verb when setting parent to None
941
 
        transport = MemoryTransport()
942
 
        client = FakeClient(transport.base)
943
 
        client.add_expected_call(
944
 
            'Branch.get_stacked_on_url', ('quack/',),
945
 
            'error', ('NotStacked',))
946
 
        client.add_expected_call(
947
 
            'Branch.set_parent_location', ('quack/', 'b', 'r', ''),
948
 
            'success', ())
949
 
        transport.mkdir('quack')
950
 
        transport = transport.clone('quack')
951
 
        branch = self.make_remote_branch(transport, client)
952
 
        branch._lock_token = 'b'
953
 
        branch._repo_lock_token = 'r'
954
 
        branch._set_parent_location(None)
955
 
        self.assertFinished(client)
956
 
 
957
 
    def test_parent(self):
958
 
        transport = MemoryTransport()
959
 
        client = FakeClient(transport.base)
960
 
        client.add_expected_call(
961
 
            'Branch.get_stacked_on_url', ('kwaak/',),
962
 
            'error', ('NotStacked',))
963
 
        client.add_expected_call(
964
 
            'Branch.set_parent_location', ('kwaak/', 'b', 'r', 'foo'),
965
 
            'success', ())
966
 
        transport.mkdir('kwaak')
967
 
        transport = transport.clone('kwaak')
968
 
        branch = self.make_remote_branch(transport, client)
969
 
        branch._lock_token = 'b'
970
 
        branch._repo_lock_token = 'r'
971
 
        branch._set_parent_location('foo')
972
 
        self.assertFinished(client)
973
 
 
974
 
    def test_backwards_compat(self):
975
 
        self.setup_smart_server_with_call_log()
976
 
        branch = self.make_branch('.')
977
 
        self.reset_smart_call_log()
978
 
        verb = 'Branch.set_parent_location'
979
 
        self.disable_verb(verb)
980
 
        branch.set_parent('http://foo/')
981
 
        self.assertLength(12, self.hpss_calls)
982
839
 
983
840
 
984
841
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1007
864
        transport = transport.clone('quack')
1008
865
        branch = self.make_remote_branch(transport, client)
1009
866
        result = branch.tags.get_tag_dict()
1010
 
        self.assertFinished(client)
 
867
        client.finished_test()
1011
868
        self.assertEqual({}, result)
1012
869
 
1013
870
 
1014
 
class TestBranchSetTagsBytes(RemoteBranchTestCase):
1015
 
 
1016
 
    def test_trivial(self):
1017
 
        transport = MemoryTransport()
1018
 
        client = FakeClient(transport.base)
1019
 
        client.add_expected_call(
1020
 
            'Branch.get_stacked_on_url', ('quack/',),
1021
 
            'error', ('NotStacked',))
1022
 
        client.add_expected_call(
1023
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1024
 
            'success', ('',))
1025
 
        transport.mkdir('quack')
1026
 
        transport = transport.clone('quack')
1027
 
        branch = self.make_remote_branch(transport, client)
1028
 
        self.lock_remote_branch(branch)
1029
 
        branch._set_tags_bytes('tags bytes')
1030
 
        self.assertFinished(client)
1031
 
        self.assertEqual('tags bytes', client._calls[-1][-1])
1032
 
 
1033
 
    def test_backwards_compatible(self):
1034
 
        transport = MemoryTransport()
1035
 
        client = FakeClient(transport.base)
1036
 
        client.add_expected_call(
1037
 
            'Branch.get_stacked_on_url', ('quack/',),
1038
 
            'error', ('NotStacked',))
1039
 
        client.add_expected_call(
1040
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1041
 
            'unknown', ('Branch.set_tags_bytes',))
1042
 
        transport.mkdir('quack')
1043
 
        transport = transport.clone('quack')
1044
 
        branch = self.make_remote_branch(transport, client)
1045
 
        self.lock_remote_branch(branch)
1046
 
        class StubRealBranch(object):
1047
 
            def __init__(self):
1048
 
                self.calls = []
1049
 
            def _set_tags_bytes(self, bytes):
1050
 
                self.calls.append(('set_tags_bytes', bytes))
1051
 
        real_branch = StubRealBranch()
1052
 
        branch._real_branch = real_branch
1053
 
        branch._set_tags_bytes('tags bytes')
1054
 
        # Call a second time, to exercise the 'remote version already inferred'
1055
 
        # code path.
1056
 
        branch._set_tags_bytes('tags bytes')
1057
 
        self.assertFinished(client)
1058
 
        self.assertEqual(
1059
 
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1060
 
 
1061
 
 
1062
871
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1063
872
 
1064
873
    def test_empty_branch(self):
1075
884
        transport = transport.clone('quack')
1076
885
        branch = self.make_remote_branch(transport, client)
1077
886
        result = branch.last_revision_info()
1078
 
        self.assertFinished(client)
 
887
        client.finished_test()
1079
888
        self.assertEqual((0, NULL_REVISION), result)
1080
889
 
1081
890
    def test_non_empty_branch(self):
1156
965
        branch = bzrdir.open_branch()
1157
966
        result = branch.get_stacked_on_url()
1158
967
        self.assertEqual('../base', result)
1159
 
        self.assertFinished(client)
 
968
        client.finished_test()
1160
969
        # it's in the fallback list both for the RemoteRepository and its vfs
1161
970
        # repository
1162
971
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1189
998
        branch = bzrdir.open_branch()
1190
999
        result = branch.get_stacked_on_url()
1191
1000
        self.assertEqual('../base', result)
1192
 
        self.assertFinished(client)
 
1001
        client.finished_test()
1193
1002
        # it's in the fallback list both for the RemoteRepository.
1194
1003
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1195
1004
        # And we haven't had to construct a real repository.
1230
1039
        result = branch.set_revision_history([])
1231
1040
        branch.unlock()
1232
1041
        self.assertEqual(None, result)
1233
 
        self.assertFinished(client)
 
1042
        client.finished_test()
1234
1043
 
1235
1044
    def test_set_nonempty(self):
1236
1045
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1268
1077
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1269
1078
        branch.unlock()
1270
1079
        self.assertEqual(None, result)
1271
 
        self.assertFinished(client)
 
1080
        client.finished_test()
1272
1081
 
1273
1082
    def test_no_such_revision(self):
1274
1083
        transport = MemoryTransport()
1303
1112
        self.assertRaises(
1304
1113
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1305
1114
        branch.unlock()
1306
 
        self.assertFinished(client)
 
1115
        client.finished_test()
1307
1116
 
1308
1117
    def test_tip_change_rejected(self):
1309
1118
        """TipChangeRejected responses cause a TipChangeRejected exception to
1346
1155
        self.assertIsInstance(err.msg, unicode)
1347
1156
        self.assertEqual(rejection_msg_unicode, err.msg)
1348
1157
        branch.unlock()
1349
 
        self.assertFinished(client)
 
1158
        client.finished_test()
1350
1159
 
1351
1160
 
1352
1161
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
1406
1215
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1407
1216
        branch.unlock()
1408
1217
 
 
1218
    def lock_remote_branch(self, branch):
 
1219
        """Trick a RemoteBranch into thinking it is locked."""
 
1220
        branch._lock_mode = 'w'
 
1221
        branch._lock_count = 2
 
1222
        branch._lock_token = 'branch token'
 
1223
        branch._repo_lock_token = 'repo token'
 
1224
        branch.repository._lock_mode = 'w'
 
1225
        branch.repository._lock_count = 2
 
1226
        branch.repository._lock_token = 'repo token'
 
1227
 
1409
1228
    def test_backwards_compatibility(self):
1410
1229
        """If the server does not support the Branch.set_last_revision_info
1411
1230
        verb (which is new in 1.4), then the client falls back to VFS methods.
1452
1271
        self.assertEqual(
1453
1272
            [('set_last_revision_info', 1234, 'a-revision-id')],
1454
1273
            real_branch.calls)
1455
 
        self.assertFinished(client)
 
1274
        client.finished_test()
1456
1275
 
1457
1276
    def test_unexpected_error(self):
1458
1277
        # If the server sends an error the client doesn't understand, it gets
1513
1332
        self.assertEqual('rejection message', err.msg)
1514
1333
 
1515
1334
 
1516
 
class TestBranchGetSetConfig(RemoteBranchTestCase):
 
1335
class TestBranchControlGetBranchConf(RemoteBranchTestCase):
 
1336
    """Getting the branch configuration should use an abstract method not vfs.
 
1337
    """
1517
1338
 
1518
1339
    def test_get_branch_conf(self):
 
1340
        # We should see that branch.get_config() does a single rpc to get the
 
1341
        # remote configuration file, abstracting away where that is stored on
 
1342
        # the server.  However at the moment it always falls back to using the
 
1343
        # vfs, and this would need some changes in config.py.
 
1344
 
1519
1345
        # in an empty branch we decode the response properly
1520
1346
        client = FakeClient()
1521
1347
        client.add_expected_call(
1531
1357
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1532
1358
            client._calls)
1533
1359
 
1534
 
    def test_get_multi_line_branch_conf(self):
1535
 
        # Make sure that multiple-line branch.conf files are supported
1536
 
        #
1537
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1538
 
        client = FakeClient()
1539
 
        client.add_expected_call(
1540
 
            'Branch.get_stacked_on_url', ('memory:///',),
1541
 
            'error', ('NotStacked',),)
1542
 
        client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
1543
 
        transport = MemoryTransport()
1544
 
        branch = self.make_remote_branch(transport, client)
1545
 
        config = branch.get_config()
1546
 
        self.assertEqual(u'2', config.get_user_option('b'))
1547
 
 
1548
 
    def test_set_option(self):
1549
 
        client = FakeClient()
1550
 
        client.add_expected_call(
1551
 
            'Branch.get_stacked_on_url', ('memory:///',),
1552
 
            'error', ('NotStacked',),)
1553
 
        client.add_expected_call(
1554
 
            'Branch.lock_write', ('memory:///', '', ''),
1555
 
            'success', ('ok', 'branch token', 'repo token'))
1556
 
        client.add_expected_call(
1557
 
            'Branch.set_config_option', ('memory:///', 'branch token',
1558
 
            'repo token', 'foo', 'bar', ''),
1559
 
            'success', ())
1560
 
        client.add_expected_call(
1561
 
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1562
 
            'success', ('ok',))
1563
 
        transport = MemoryTransport()
1564
 
        branch = self.make_remote_branch(transport, client)
1565
 
        branch.lock_write()
1566
 
        config = branch._get_config()
1567
 
        config.set_option('foo', 'bar')
1568
 
        branch.unlock()
1569
 
        self.assertFinished(client)
1570
 
 
1571
 
    def test_backwards_compat_set_option(self):
1572
 
        self.setup_smart_server_with_call_log()
1573
 
        branch = self.make_branch('.')
1574
 
        verb = 'Branch.set_config_option'
1575
 
        self.disable_verb(verb)
1576
 
        branch.lock_write()
1577
 
        self.addCleanup(branch.unlock)
1578
 
        self.reset_smart_call_log()
1579
 
        branch._get_config().set_option('value', 'name')
1580
 
        self.assertLength(10, self.hpss_calls)
1581
 
        self.assertEqual('value', branch._get_config().get_option('name'))
1582
 
 
1583
1360
 
1584
1361
class TestBranchLockWrite(RemoteBranchTestCase):
1585
1362
 
1596
1373
        transport = transport.clone('quack')
1597
1374
        branch = self.make_remote_branch(transport, client)
1598
1375
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
1599
 
        self.assertFinished(client)
1600
 
 
1601
 
 
1602
 
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1603
 
 
1604
 
    def test__get_config(self):
1605
 
        client = FakeClient()
1606
 
        client.add_success_response_with_body('default_stack_on = /\n', 'ok')
1607
 
        transport = MemoryTransport()
1608
 
        bzrdir = self.make_remote_bzrdir(transport, client)
1609
 
        config = bzrdir.get_config()
1610
 
        self.assertEqual('/', config.get_default_stack_on())
1611
 
        self.assertEqual(
1612
 
            [('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
1613
 
            client._calls)
1614
 
 
1615
 
    def test_set_option_uses_vfs(self):
1616
 
        self.setup_smart_server_with_call_log()
1617
 
        bzrdir = self.make_bzrdir('.')
1618
 
        self.reset_smart_call_log()
1619
 
        config = bzrdir.get_config()
1620
 
        config.set_default_stack_on('/')
1621
 
        self.assertLength(3, self.hpss_calls)
1622
 
 
1623
 
    def test_backwards_compat_get_option(self):
1624
 
        self.setup_smart_server_with_call_log()
1625
 
        bzrdir = self.make_bzrdir('.')
1626
 
        verb = 'BzrDir.get_config_file'
1627
 
        self.disable_verb(verb)
1628
 
        self.reset_smart_call_log()
1629
 
        self.assertEqual(None,
1630
 
            bzrdir._get_config().get_option('default_stack_on'))
1631
 
        self.assertLength(3, self.hpss_calls)
 
1376
        client.finished_test()
1632
1377
 
1633
1378
 
1634
1379
class TestTransportIsReadonly(tests.TestCase):
1730
1475
class TestRepositoryFormat(TestRemoteRepository):
1731
1476
 
1732
1477
    def test_fast_delta(self):
1733
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
1478
        true_name = pack_repo.RepositoryFormatPackDevelopment2().network_name()
1734
1479
        true_format = RemoteRepositoryFormat()
1735
1480
        true_format._network_name = true_name
1736
1481
        self.assertEqual(True, true_format.fast_deltas)
2089
1834
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
2090
1835
 
2091
1836
 
2092
 
class TestRepositoryGetRevIdForRevno(TestRemoteRepository):
2093
 
 
2094
 
    def test_ok(self):
2095
 
        repo, client = self.setup_fake_client_and_repository('quack')
2096
 
        client.add_expected_call(
2097
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2098
 
            'success', ('ok', 'rev-five'))
2099
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2100
 
        self.assertEqual((True, 'rev-five'), result)
2101
 
        self.assertFinished(client)
2102
 
 
2103
 
    def test_history_incomplete(self):
2104
 
        repo, client = self.setup_fake_client_and_repository('quack')
2105
 
        client.add_expected_call(
2106
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2107
 
            'success', ('history-incomplete', 10, 'rev-ten'))
2108
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2109
 
        self.assertEqual((False, (10, 'rev-ten')), result)
2110
 
        self.assertFinished(client)
2111
 
 
2112
 
    def test_history_incomplete_with_fallback(self):
2113
 
        """A 'history-incomplete' response causes the fallback repository to be
2114
 
        queried too, if one is set.
2115
 
        """
2116
 
        # Make a repo with a fallback repo, both using a FakeClient.
2117
 
        format = remote.response_tuple_to_repo_format(
2118
 
            ('yes', 'no', 'yes', 'fake-network-name'))
2119
 
        repo, client = self.setup_fake_client_and_repository('quack')
2120
 
        repo._format = format
2121
 
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2122
 
            'fallback')
2123
 
        fallback_repo._client = client
2124
 
        repo.add_fallback_repository(fallback_repo)
2125
 
        # First the client should ask the primary repo
2126
 
        client.add_expected_call(
2127
 
            'Repository.get_rev_id_for_revno', ('quack/', 1, (42, 'rev-foo')),
2128
 
            'success', ('history-incomplete', 2, 'rev-two'))
2129
 
        # Then it should ask the fallback, using revno/revid from the
2130
 
        # history-incomplete response as the known revno/revid.
2131
 
        client.add_expected_call(
2132
 
            'Repository.get_rev_id_for_revno',('fallback/', 1, (2, 'rev-two')),
2133
 
            'success', ('ok', 'rev-one'))
2134
 
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2135
 
        self.assertEqual((True, 'rev-one'), result)
2136
 
        self.assertFinished(client)
2137
 
 
2138
 
    def test_nosuchrevision(self):
2139
 
        # 'nosuchrevision' is returned when the known-revid is not found in the
2140
 
        # remote repo.  The client translates that response to NoSuchRevision.
2141
 
        repo, client = self.setup_fake_client_and_repository('quack')
2142
 
        client.add_expected_call(
2143
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2144
 
            'error', ('nosuchrevision', 'rev-foo'))
2145
 
        self.assertRaises(
2146
 
            errors.NoSuchRevision,
2147
 
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2148
 
        self.assertFinished(client)
2149
 
 
2150
 
    def test_branch_fallback_locking(self):
2151
 
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
2152
 
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
2153
 
        will be invoked, which will fail if the repo is unlocked.
2154
 
        """
2155
 
        self.setup_smart_server_with_call_log()
2156
 
        tree = self.make_branch_and_memory_tree('.')
2157
 
        tree.lock_write()
2158
 
        rev1 = tree.commit('First')
2159
 
        rev2 = tree.commit('Second')
2160
 
        tree.unlock()
2161
 
        branch = tree.branch
2162
 
        self.assertFalse(branch.is_locked())
2163
 
        self.reset_smart_call_log()
2164
 
        verb = 'Repository.get_rev_id_for_revno'
2165
 
        self.disable_verb(verb)
2166
 
        self.assertEqual(rev1, branch.get_rev_id(1))
2167
 
        self.assertLength(1, [call for call in self.hpss_calls if
2168
 
                              call.call.method == verb])
2169
 
 
2170
 
 
2171
1837
class TestRepositoryIsShared(TestRemoteRepository):
2172
1838
 
2173
1839
    def test_is_shared(self):
2288
1954
        self.assertEqual([], client._calls)
2289
1955
 
2290
1956
 
2291
 
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2292
 
    """Base class for Repository.insert_stream and .insert_stream_1.19
2293
 
    tests.
2294
 
    """
2295
 
    
2296
 
    def checkInsertEmptyStream(self, repo, client):
2297
 
        """Insert an empty stream, checking the result.
2298
 
 
2299
 
        This checks that there are no resume_tokens or missing_keys, and that
2300
 
        the client is finished.
2301
 
        """
2302
 
        sink = repo._get_sink()
2303
 
        fmt = repository.RepositoryFormat.get_default_format()
2304
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2305
 
        self.assertEqual([], resume_tokens)
2306
 
        self.assertEqual(set(), missing_keys)
2307
 
        self.assertFinished(client)
2308
 
 
2309
 
 
2310
 
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
2311
 
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
2312
 
    not available.
2313
 
 
2314
 
    This test case is very similar to TestRepositoryInsertStream_1_19.
2315
 
    """
2316
 
 
2317
 
    def setUp(self):
2318
 
        TestRemoteRepository.setUp(self)
2319
 
        self.disable_verb('Repository.insert_stream_1.19')
2320
 
 
2321
 
    def test_unlocked_repo(self):
2322
 
        transport_path = 'quack'
2323
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2324
 
        client.add_expected_call(
2325
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2326
 
            'unknown', ('Repository.insert_stream_1.19',))
2327
 
        client.add_expected_call(
2328
 
            'Repository.insert_stream', ('quack/', ''),
2329
 
            'success', ('ok',))
2330
 
        client.add_expected_call(
2331
 
            'Repository.insert_stream', ('quack/', ''),
2332
 
            'success', ('ok',))
2333
 
        self.checkInsertEmptyStream(repo, client)
2334
 
 
2335
 
    def test_locked_repo_with_no_lock_token(self):
2336
 
        transport_path = 'quack'
2337
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2338
 
        client.add_expected_call(
2339
 
            'Repository.lock_write', ('quack/', ''),
2340
 
            'success', ('ok', ''))
2341
 
        client.add_expected_call(
2342
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2343
 
            'unknown', ('Repository.insert_stream_1.19',))
2344
 
        client.add_expected_call(
2345
 
            'Repository.insert_stream', ('quack/', ''),
2346
 
            'success', ('ok',))
2347
 
        client.add_expected_call(
2348
 
            'Repository.insert_stream', ('quack/', ''),
2349
 
            'success', ('ok',))
2350
 
        repo.lock_write()
2351
 
        self.checkInsertEmptyStream(repo, client)
2352
 
 
2353
 
    def test_locked_repo_with_lock_token(self):
2354
 
        transport_path = 'quack'
2355
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2356
 
        client.add_expected_call(
2357
 
            'Repository.lock_write', ('quack/', ''),
2358
 
            'success', ('ok', 'a token'))
2359
 
        client.add_expected_call(
2360
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2361
 
            'unknown', ('Repository.insert_stream_1.19',))
2362
 
        client.add_expected_call(
2363
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2364
 
            'success', ('ok',))
2365
 
        client.add_expected_call(
2366
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2367
 
            'success', ('ok',))
2368
 
        repo.lock_write()
2369
 
        self.checkInsertEmptyStream(repo, client)
2370
 
 
2371
 
    def test_stream_with_inventory_deltas(self):
2372
 
        """'inventory-deltas' substreams cannot be sent to the
2373
 
        Repository.insert_stream verb, because not all servers that implement
2374
 
        that verb will accept them.  So when one is encountered the RemoteSink
2375
 
        immediately stops using that verb and falls back to VFS insert_stream.
2376
 
        """
2377
 
        transport_path = 'quack'
2378
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2379
 
        client.add_expected_call(
2380
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2381
 
            'unknown', ('Repository.insert_stream_1.19',))
2382
 
        client.add_expected_call(
2383
 
            'Repository.insert_stream', ('quack/', ''),
2384
 
            'success', ('ok',))
2385
 
        client.add_expected_call(
2386
 
            'Repository.insert_stream', ('quack/', ''),
2387
 
            'success', ('ok',))
2388
 
        # Create a fake real repository for insert_stream to fall back on, so
2389
 
        # that we can directly see the records the RemoteSink passes to the
2390
 
        # real sink.
2391
 
        class FakeRealSink:
2392
 
            def __init__(self):
2393
 
                self.records = []
2394
 
            def insert_stream(self, stream, src_format, resume_tokens):
2395
 
                for substream_kind, substream in stream:
2396
 
                    self.records.append(
2397
 
                        (substream_kind, [record.key for record in substream]))
2398
 
                return ['fake tokens'], ['fake missing keys']
2399
 
        fake_real_sink = FakeRealSink()
2400
 
        class FakeRealRepository:
2401
 
            def _get_sink(self):
2402
 
                return fake_real_sink
2403
 
            def is_in_write_group(self):
2404
 
                return False
2405
 
            def refresh_data(self):
2406
 
                return True
2407
 
        repo._real_repository = FakeRealRepository()
2408
 
        sink = repo._get_sink()
2409
 
        fmt = repository.RepositoryFormat.get_default_format()
2410
 
        stream = self.make_stream_with_inv_deltas(fmt)
2411
 
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2412
 
        # Every record from the first inventory delta should have been sent to
2413
 
        # the VFS sink.
2414
 
        expected_records = [
2415
 
            ('inventory-deltas', [('rev2',), ('rev3',)]),
2416
 
            ('texts', [('some-rev', 'some-file')])]
2417
 
        self.assertEqual(expected_records, fake_real_sink.records)
2418
 
        # The return values from the real sink's insert_stream are propagated
2419
 
        # back to the original caller.
2420
 
        self.assertEqual(['fake tokens'], resume_tokens)
2421
 
        self.assertEqual(['fake missing keys'], missing_keys)
2422
 
        self.assertFinished(client)
2423
 
 
2424
 
    def make_stream_with_inv_deltas(self, fmt):
2425
 
        """Make a simple stream with an inventory delta followed by more
2426
 
        records and more substreams to test that all records and substreams
2427
 
        from that point on are used.
2428
 
 
2429
 
        This sends, in order:
2430
 
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
2431
 
             inventory-deltas.
2432
 
           * texts substream: (some-rev, some-file)
2433
 
        """
2434
 
        # Define a stream using generators so that it isn't rewindable.
2435
 
        inv = inventory.Inventory(revision_id='rev1')
2436
 
        inv.root.revision = 'rev1'
2437
 
        def stream_with_inv_delta():
2438
 
            yield ('inventories', inventories_substream())
2439
 
            yield ('inventory-deltas', inventory_delta_substream())
2440
 
            yield ('texts', [
2441
 
                versionedfile.FulltextContentFactory(
2442
 
                    ('some-rev', 'some-file'), (), None, 'content')])
2443
 
        def inventories_substream():
2444
 
            # An empty inventory fulltext.  This will be streamed normally.
2445
 
            text = fmt._serializer.write_inventory_to_string(inv)
2446
 
            yield versionedfile.FulltextContentFactory(
2447
 
                ('rev1',), (), None, text)
2448
 
        def inventory_delta_substream():
2449
 
            # An inventory delta.  This can't be streamed via this verb, so it
2450
 
            # will trigger a fallback to VFS insert_stream.
2451
 
            entry = inv.make_entry(
2452
 
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
2453
 
            entry.revision = 'ghost'
2454
 
            delta = [(None, 'newdir', 'newdir-id', entry)]
2455
 
            serializer = inventory_delta.InventoryDeltaSerializer(
2456
 
                versioned_root=True, tree_references=False)
2457
 
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
2458
 
            yield versionedfile.ChunkedContentFactory(
2459
 
                ('rev2',), (('rev1',)), None, lines)
2460
 
            # Another delta.
2461
 
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
2462
 
            yield versionedfile.ChunkedContentFactory(
2463
 
                ('rev3',), (('rev1',)), None, lines)
2464
 
        return stream_with_inv_delta()
2465
 
 
2466
 
 
2467
 
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
2468
 
 
2469
 
    def test_unlocked_repo(self):
2470
 
        transport_path = 'quack'
2471
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2472
 
        client.add_expected_call(
2473
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2474
 
            'success', ('ok',))
2475
 
        client.add_expected_call(
2476
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2477
 
            'success', ('ok',))
2478
 
        self.checkInsertEmptyStream(repo, client)
2479
 
 
2480
 
    def test_locked_repo_with_no_lock_token(self):
2481
 
        transport_path = 'quack'
2482
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2483
 
        client.add_expected_call(
2484
 
            'Repository.lock_write', ('quack/', ''),
2485
 
            'success', ('ok', ''))
2486
 
        client.add_expected_call(
2487
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2488
 
            'success', ('ok',))
2489
 
        client.add_expected_call(
2490
 
            'Repository.insert_stream_1.19', ('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
 
            'success', ('ok',))
2504
 
        client.add_expected_call(
2505
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2506
 
            'success', ('ok',))
2507
 
        repo.lock_write()
2508
 
        self.checkInsertEmptyStream(repo, client)
 
1957
class TestRepositoryInsertStream(TestRemoteRepository):
 
1958
 
 
1959
    def test_unlocked_repo(self):
 
1960
        transport_path = 'quack'
 
1961
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1962
        client.add_expected_call(
 
1963
            'Repository.insert_stream', ('quack/', ''),
 
1964
            'success', ('ok',))
 
1965
        client.add_expected_call(
 
1966
            'Repository.insert_stream', ('quack/', ''),
 
1967
            'success', ('ok',))
 
1968
        sink = repo._get_sink()
 
1969
        fmt = repository.RepositoryFormat.get_default_format()
 
1970
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
1971
        self.assertEqual([], resume_tokens)
 
1972
        self.assertEqual(set(), missing_keys)
 
1973
        client.finished_test()
 
1974
 
 
1975
    def test_locked_repo_with_no_lock_token(self):
 
1976
        transport_path = 'quack'
 
1977
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1978
        client.add_expected_call(
 
1979
            'Repository.lock_write', ('quack/', ''),
 
1980
            'success', ('ok', ''))
 
1981
        client.add_expected_call(
 
1982
            'Repository.insert_stream', ('quack/', ''),
 
1983
            'success', ('ok',))
 
1984
        client.add_expected_call(
 
1985
            'Repository.insert_stream', ('quack/', ''),
 
1986
            'success', ('ok',))
 
1987
        repo.lock_write()
 
1988
        sink = repo._get_sink()
 
1989
        fmt = repository.RepositoryFormat.get_default_format()
 
1990
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
1991
        self.assertEqual([], resume_tokens)
 
1992
        self.assertEqual(set(), missing_keys)
 
1993
        client.finished_test()
 
1994
 
 
1995
    def test_locked_repo_with_lock_token(self):
 
1996
        transport_path = 'quack'
 
1997
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1998
        client.add_expected_call(
 
1999
            'Repository.lock_write', ('quack/', ''),
 
2000
            'success', ('ok', 'a token'))
 
2001
        client.add_expected_call(
 
2002
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2003
            'success', ('ok',))
 
2004
        client.add_expected_call(
 
2005
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2006
            'success', ('ok',))
 
2007
        repo.lock_write()
 
2008
        sink = repo._get_sink()
 
2009
        fmt = repository.RepositoryFormat.get_default_format()
 
2010
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2011
        self.assertEqual([], resume_tokens)
 
2012
        self.assertEqual(set(), missing_keys)
 
2013
        client.finished_test()
2509
2014
 
2510
2015
 
2511
2016
class TestRepositoryTarball(TestRemoteRepository):
2596
2101
        client.add_expected_call(
2597
2102
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
2598
2103
        repo.autopack()
2599
 
        self.assertFinished(client)
 
2104
        client.finished_test()
2600
2105
 
2601
2106
    def test_ok_with_real_repo(self):
2602
2107
        """When the server returns 'ok' and there is a _real_repository, then
2746
2251
        expected_error = errors.ReadError(path)
2747
2252
        self.assertEqual(expected_error, translated_error)
2748
2253
 
2749
 
    def test_IncompatibleRepositories(self):
2750
 
        translated_error = self.translateTuple(('IncompatibleRepositories',
2751
 
            "repo1", "repo2", "details here"))
2752
 
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2753
 
            "details here")
2754
 
        self.assertEqual(expected_error, translated_error)
2755
 
 
2756
2254
    def test_PermissionDenied_no_args(self):
2757
2255
        path = 'a path'
2758
2256
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2869
2367
        try:
2870
2368
            # it should have an appropriate fallback repository, which should also
2871
2369
            # be a RemoteRepository
2872
 
            self.assertLength(1, remote_repo._fallback_repositories)
 
2370
            self.assertEquals(len(remote_repo._fallback_repositories), 1)
2873
2371
            self.assertIsInstance(remote_repo._fallback_repositories[0],
2874
2372
                RemoteRepository)
2875
2373
            # and it has the revision committed to the underlying repository;
2888
2386
        tree1.commit('rev1', rev_id='rev1')
2889
2387
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2890
2388
            ).open_workingtree()
2891
 
        local_tree = tree2.branch.create_checkout('local')
2892
 
        local_tree.commit('local changes make me feel good.')
 
2389
        tree2.commit('local changes make me feel good.')
2893
2390
        branch2 = Branch.open(self.get_url('tree2'))
2894
2391
        branch2.lock_read()
2895
2392
        self.addCleanup(branch2.unlock)
2917
2414
                    result.append(content.key[-1])
2918
2415
        return result
2919
2416
 
2920
 
    def get_ordered_revs(self, format, order, branch_factory=None):
 
2417
    def get_ordered_revs(self, format, order):
2921
2418
        """Get a list of the revisions in a stream to format format.
2922
2419
 
2923
2420
        :param format: The format of the target.
2924
2421
        :param order: the order that target should have requested.
2925
 
        :param branch_factory: A callable to create a trunk and stacked branch
2926
 
            to fetch from. If none, self.prepare_stacked_remote_branch is used.
2927
2422
        :result: The revision ids in the stream, in the order seen,
2928
2423
            the topological order of revisions in the source.
2929
2424
        """
2931
2426
        target_repository_format = unordered_format.repository_format
2932
2427
        # Cross check
2933
2428
        self.assertEqual(order, target_repository_format._fetch_order)
2934
 
        if branch_factory is None:
2935
 
            branch_factory = self.prepare_stacked_remote_branch
2936
 
        _, stacked = branch_factory()
 
2429
        trunk, stacked = self.prepare_stacked_remote_branch()
2937
2430
        source = stacked.repository._get_source(target_repository_format)
2938
2431
        tip = stacked.last_revision()
2939
2432
        revs = stacked.repository.get_ancestry(tip)
2958
2451
        # from the server, then one from the backing branch.
2959
2452
        self.assertLength(2, self.hpss_calls)
2960
2453
 
2961
 
    def test_stacked_on_stacked_get_stream_unordered(self):
2962
 
        # Repository._get_source.get_stream() from a stacked repository which
2963
 
        # is itself stacked yields the full data from all three sources.
2964
 
        def make_stacked_stacked():
2965
 
            _, stacked = self.prepare_stacked_remote_branch()
2966
 
            tree = stacked.bzrdir.sprout('tree3', stacked=True
2967
 
                ).open_workingtree()
2968
 
            local_tree = tree.branch.create_checkout('local-tree3')
2969
 
            local_tree.commit('more local changes are better')
2970
 
            branch = Branch.open(self.get_url('tree3'))
2971
 
            branch.lock_read()
2972
 
            return None, branch
2973
 
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
2974
 
            branch_factory=make_stacked_stacked)
2975
 
        self.assertEqual(set(expected_revs), set(rev_ord))
2976
 
        # Getting unordered results should have made a streaming data request
2977
 
        # from the server, and one from each backing repo
2978
 
        self.assertLength(3, self.hpss_calls)
2979
 
 
2980
2454
    def test_stacked_get_stream_topological(self):
2981
2455
        # Repository._get_source.get_stream() from a stacked repository with
2982
2456
        # topological sorting yields the full data from both stacked and
2983
2457
        # stacked upon sources in topological order.
2984
2458
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
2985
2459
        self.assertEqual(expected_revs, rev_ord)
2986
 
        # Getting topological sort requires VFS calls still - one of which is
2987
 
        # pushing up from the bound branch.
2988
 
        self.assertLength(13, self.hpss_calls)
 
2460
        # Getting topological sort requires VFS calls still
 
2461
        self.assertLength(12, self.hpss_calls)
2989
2462
 
2990
2463
    def test_stacked_get_stream_groupcompress(self):
2991
2464
        # Repository._get_source.get_stream() from a stacked repository with
2998
2471
        # from the backing branch, and one from the stacked on branch.
2999
2472
        self.assertLength(2, self.hpss_calls)
3000
2473
 
3001
 
    def test_stacked_pull_more_than_stacking_has_bug_360791(self):
3002
 
        # When pulling some fixed amount of content that is more than the
3003
 
        # source has (because some is coming from a fallback branch, no error
3004
 
        # should be received. This was reported as bug 360791.
3005
 
        # Need three branches: a trunk, a stacked branch, and a preexisting
3006
 
        # branch pulling content from stacked and trunk.
3007
 
        self.setup_smart_server_with_call_log()
3008
 
        trunk = self.make_branch_and_tree('trunk', format="1.9-rich-root")
3009
 
        r1 = trunk.commit('start')
3010
 
        stacked_branch = trunk.branch.create_clone_on_transport(
3011
 
            self.get_transport('stacked'), stacked_on=trunk.branch.base)
3012
 
        local = self.make_branch('local', format='1.9-rich-root')
3013
 
        local.repository.fetch(stacked_branch.repository,
3014
 
            stacked_branch.last_revision())
3015
 
 
3016
2474
 
3017
2475
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
3018
2476