/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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,
30
31
    bzrdir,
31
32
    config,
32
33
    errors,
33
34
    graph,
 
35
    inventory,
 
36
    inventory_delta,
34
37
    pack,
35
38
    remote,
36
39
    repository,
37
 
    smart,
38
40
    tests,
39
41
    treebuilder,
40
42
    urlutils,
 
43
    versionedfile,
41
44
    )
42
45
from bzrlib.branch import Branch
43
46
from bzrlib.bzrdir import BzrDir, BzrDirFormat
51
54
    )
52
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
53
56
from bzrlib.revision import NULL_REVISION
54
 
from bzrlib.smart import server, medium
 
57
from bzrlib.smart import medium
55
58
from bzrlib.smart.client import _SmartClient
56
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
57
60
from bzrlib.tests import (
58
61
    condition_isinstance,
59
62
    split_suite_by_condition,
60
63
    multiply_tests,
61
 
    KnownFailure,
 
64
    test_server,
62
65
    )
63
 
from bzrlib.transport import get_transport, http
 
66
from bzrlib.transport import get_transport
64
67
from bzrlib.transport.memory import MemoryTransport
65
68
from bzrlib.transport.remote import (
66
69
    RemoteTransport,
73
76
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
74
77
    smart_server_version_scenarios = [
75
78
        ('HPSS-v2',
76
 
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
 
79
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
77
80
        ('HPSS-v3',
78
 
            {'transport_server': server.SmartTCPServer_for_testing})]
 
81
         {'transport_server': test_server.SmartTCPServer_for_testing})]
79
82
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
80
83
 
81
84
 
132
135
        b = BzrDir.open_from_transport(self.transport).open_branch()
133
136
        self.assertStartsWith(str(b), 'RemoteBranch(')
134
137
 
 
138
    def test_remote_bzrdir_repr(self):
 
139
        b = BzrDir.open_from_transport(self.transport)
 
140
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
 
141
 
135
142
    def test_remote_branch_format_supports_stacking(self):
136
143
        t = self.transport
137
144
        self.make_branch('unstackable', format='pack-0.92')
277
284
        self.expecting_body = True
278
285
        return result[1], FakeProtocol(result[2], self)
279
286
 
 
287
    def call_with_body_bytes(self, method, args, body):
 
288
        self._check_call(method, args)
 
289
        self._calls.append(('call_with_body_bytes', method, args, body))
 
290
        result = self._get_next_response()
 
291
        return result[1], FakeProtocol(result[2], self)
 
292
 
280
293
    def call_with_body_bytes_expecting_body(self, method, args, body):
281
294
        self._check_call(method, args)
282
295
        self._calls.append(('call_with_body_bytes_expecting_body', method,
332
345
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
333
346
        return reference_bzrdir_format.repository_format
334
347
 
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)
 
348
    def assertFinished(self, fake_client):
 
349
        """Assert that all of a FakeClient's expected calls have occurred."""
 
350
        fake_client.finished_test()
343
351
 
344
352
 
345
353
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
410
418
        # Calling _remember_remote_is_before again with a lower value works.
411
419
        client_medium._remember_remote_is_before((1, 5))
412
420
        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))
 
421
        # If you call _remember_remote_is_before with a higher value it logs a
 
422
        # warning, and continues to remember the lower value.
 
423
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
 
424
        client_medium._remember_remote_is_before((1, 9))
 
425
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
 
426
        self.assertTrue(client_medium._is_remote_before((1, 5)))
416
427
 
417
428
 
418
429
class TestBzrDirCloningMetaDir(TestRemote):
437
448
            'BzrDir.cloning_metadir', ('quack/', 'False'),
438
449
            'error', ('BranchReference',)),
439
450
        client.add_expected_call(
440
 
            'BzrDir.open_branchV2', ('quack/',),
 
451
            'BzrDir.open_branchV3', ('quack/',),
441
452
            'success', ('ref', self.get_url('referenced'))),
442
453
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
443
454
            _client=client)
446
457
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
447
458
        self.assertEqual(expected._repository_format, result._repository_format)
448
459
        self.assertEqual(expected._branch_format, result._branch_format)
449
 
        client.finished_test()
 
460
        self.assertFinished(client)
450
461
 
451
462
    def test_current_server(self):
452
463
        transport = self.get_transport('.')
467
478
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
468
479
        self.assertEqual(None, result._repository_format)
469
480
        self.assertEqual(None, result._branch_format)
470
 
        client.finished_test()
 
481
        self.assertFinished(client)
 
482
 
 
483
 
 
484
class TestBzrDirOpen(TestRemote):
 
485
 
 
486
    def make_fake_client_and_transport(self, path='quack'):
 
487
        transport = MemoryTransport()
 
488
        transport.mkdir(path)
 
489
        transport = transport.clone(path)
 
490
        client = FakeClient(transport.base)
 
491
        return client, transport
 
492
 
 
493
    def test_absent(self):
 
494
        client, transport = self.make_fake_client_and_transport()
 
495
        client.add_expected_call(
 
496
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
 
497
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
 
498
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
499
        self.assertFinished(client)
 
500
 
 
501
    def test_present_without_workingtree(self):
 
502
        client, transport = self.make_fake_client_and_transport()
 
503
        client.add_expected_call(
 
504
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
 
505
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
506
            _client=client, _force_probe=True)
 
507
        self.assertIsInstance(bd, RemoteBzrDir)
 
508
        self.assertFalse(bd.has_workingtree())
 
509
        self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
 
510
        self.assertFinished(client)
 
511
 
 
512
    def test_present_with_workingtree(self):
 
513
        client, transport = self.make_fake_client_and_transport()
 
514
        client.add_expected_call(
 
515
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
 
516
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
517
            _client=client, _force_probe=True)
 
518
        self.assertIsInstance(bd, RemoteBzrDir)
 
519
        self.assertTrue(bd.has_workingtree())
 
520
        self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
 
521
        self.assertFinished(client)
 
522
 
 
523
    def test_backwards_compat(self):
 
524
        client, transport = self.make_fake_client_and_transport()
 
525
        client.add_expected_call(
 
526
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
527
        client.add_expected_call(
 
528
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
529
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
530
            _client=client, _force_probe=True)
 
531
        self.assertIsInstance(bd, RemoteBzrDir)
 
532
        self.assertFinished(client)
 
533
 
 
534
    def test_backwards_compat_hpss_v2(self):
 
535
        client, transport = self.make_fake_client_and_transport()
 
536
        # Monkey-patch fake client to simulate real-world behaviour with v2
 
537
        # server: upon first RPC call detect the protocol version, and because
 
538
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
 
539
        # continuing with the RPC.
 
540
        orig_check_call = client._check_call
 
541
        def check_call(method, args):
 
542
            client._medium._protocol_version = 2
 
543
            client._medium._remember_remote_is_before((1, 6))
 
544
            client._check_call = orig_check_call
 
545
            client._check_call(method, args)
 
546
        client._check_call = check_call
 
547
        client.add_expected_call(
 
548
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
549
        client.add_expected_call(
 
550
            'BzrDir.open', ('quack/',), 'success', ('yes',))
 
551
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
552
            _client=client, _force_probe=True)
 
553
        self.assertIsInstance(bd, RemoteBzrDir)
 
554
        self.assertFinished(client)
471
555
 
472
556
 
473
557
class TestBzrDirOpenBranch(TestRemote):
477
561
        self.make_branch('.')
478
562
        a_dir = BzrDir.open(self.get_url('.'))
479
563
        self.reset_smart_call_log()
480
 
        verb = 'BzrDir.open_branchV2'
 
564
        verb = 'BzrDir.open_branchV3'
481
565
        self.disable_verb(verb)
482
566
        format = a_dir.open_branch()
483
567
        call_count = len([call for call in self.hpss_calls if
493
577
        transport = transport.clone('quack')
494
578
        client = FakeClient(transport.base)
495
579
        client.add_expected_call(
496
 
            'BzrDir.open_branchV2', ('quack/',),
 
580
            'BzrDir.open_branchV3', ('quack/',),
497
581
            'success', ('branch', branch_network_name))
498
582
        client.add_expected_call(
499
583
            'BzrDir.find_repositoryV3', ('quack/',),
506
590
        result = bzrdir.open_branch()
507
591
        self.assertIsInstance(result, RemoteBranch)
508
592
        self.assertEqual(bzrdir, result.bzrdir)
509
 
        client.finished_test()
 
593
        self.assertFinished(client)
510
594
 
511
595
    def test_branch_missing(self):
512
596
        transport = MemoryTransport()
518
602
            _client=client)
519
603
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
520
604
        self.assertEqual(
521
 
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
 
605
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
522
606
            client._calls)
523
607
 
524
608
    def test__get_tree_branch(self):
548
632
        network_name = reference_format.network_name()
549
633
        branch_network_name = self.get_branch_format().network_name()
550
634
        client.add_expected_call(
551
 
            'BzrDir.open_branchV2', ('~hello/',),
 
635
            'BzrDir.open_branchV3', ('~hello/',),
552
636
            'success', ('branch', branch_network_name))
553
637
        client.add_expected_call(
554
638
            'BzrDir.find_repositoryV3', ('~hello/',),
559
643
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
560
644
            _client=client)
561
645
        result = bzrdir.open_branch()
562
 
        client.finished_test()
 
646
        self.assertFinished(client)
563
647
 
564
648
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
565
649
        reference_format = self.get_repo_format()
663
747
        network_name = reference_format.network_name()
664
748
        client.add_expected_call(
665
749
            'BzrDir.create_repository', ('quack/',
666
 
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
667
 
            'success', ('ok', 'no', 'no', 'no', network_name))
 
750
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
751
                'False'),
 
752
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
668
753
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
669
754
            _client=client)
670
755
        repo = a_bzrdir.create_repository()
672
757
        self.assertIsInstance(repo, remote.RemoteRepository)
673
758
        # its format should have the settings from the response
674
759
        format = repo._format
675
 
        self.assertFalse(format.rich_root_data)
676
 
        self.assertFalse(format.supports_tree_reference)
677
 
        self.assertFalse(format.supports_external_lookups)
 
760
        self.assertTrue(format.rich_root_data)
 
761
        self.assertTrue(format.supports_tree_reference)
 
762
        self.assertTrue(format.supports_external_lookups)
678
763
        self.assertEqual(network_name, format.network_name())
679
764
 
680
765
 
684
769
        # fallback all the way to the first version.
685
770
        reference_format = self.get_repo_format()
686
771
        network_name = reference_format.network_name()
687
 
        client = FakeClient('bzr://example.com/')
 
772
        server_url = 'bzr://example.com/'
 
773
        self.permit_url(server_url)
 
774
        client = FakeClient(server_url)
688
775
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
689
776
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
690
777
        client.add_success_response('ok', '', 'no', 'no')
696
783
            reference_format.get_format_string(), 'ok')
697
784
        # PackRepository wants to do a stat
698
785
        client.add_success_response('stat', '0', '65535')
699
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
786
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
700
787
            _client=client)
701
788
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
702
789
            _client=client)
716
803
        # fallback to find_repositoryV2
717
804
        reference_format = self.get_repo_format()
718
805
        network_name = reference_format.network_name()
719
 
        client = FakeClient('bzr://example.com/')
 
806
        server_url = 'bzr://example.com/'
 
807
        self.permit_url(server_url)
 
808
        client = FakeClient(server_url)
720
809
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
721
810
        client.add_success_response('ok', '', 'no', 'no', 'no')
722
811
        # A real repository instance will be created to determine the network
727
816
            reference_format.get_format_string(), 'ok')
728
817
        # PackRepository wants to do a stat
729
818
        client.add_success_response('stat', '0', '65535')
730
 
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
 
819
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
731
820
            _client=client)
732
821
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
733
822
            _client=client)
779
868
        # transport connected to a real server.
780
869
        result = fmt._initialize_on_transport_ex_rpc(client, 'path',
781
870
            transport, False, False, False, None, None, None, None, False)
782
 
        client.finished_test()
 
871
        self.assertFinished(client)
783
872
 
784
873
    def test_error(self):
785
874
        """Error responses are translated, e.g. 'PermissionDenied' raises the
803
892
            False, False, False, None, None, None, None, False)
804
893
        self.assertEqual('path', err.path)
805
894
        self.assertEqual(': extra info', err.extra)
806
 
        client.finished_test()
 
895
        self.assertFinished(client)
807
896
 
808
897
    def test_error_from_real_server(self):
809
898
        """Integration test for error translation."""
852
941
 
853
942
class RemoteBranchTestCase(RemoteBzrDirTestCase):
854
943
 
 
944
    def lock_remote_branch(self, branch):
 
945
        """Trick a RemoteBranch into thinking it is locked."""
 
946
        branch._lock_mode = 'w'
 
947
        branch._lock_count = 2
 
948
        branch._lock_token = 'branch token'
 
949
        branch._repo_lock_token = 'repo token'
 
950
        branch.repository._lock_mode = 'w'
 
951
        branch.repository._lock_count = 2
 
952
        branch.repository._lock_token = 'repo token'
 
953
 
855
954
    def make_remote_branch(self, transport, client):
856
955
        """Make a RemoteBranch using 'client' as its _SmartClient.
857
956
 
884
983
        transport = transport.clone('quack')
885
984
        branch = self.make_remote_branch(transport, client)
886
985
        result = branch.get_parent()
887
 
        client.finished_test()
 
986
        self.assertFinished(client)
888
987
        self.assertEqual(None, result)
889
988
 
890
989
    def test_parent_relative(self):
916
1015
        branch = self.make_remote_branch(transport, client)
917
1016
        result = branch.get_parent()
918
1017
        self.assertEqual('http://foo/', result)
919
 
        client.finished_test()
 
1018
        self.assertFinished(client)
920
1019
 
921
1020
 
922
1021
class TestBranchSetParentLocation(RemoteBranchTestCase):
937
1036
        branch._lock_token = 'b'
938
1037
        branch._repo_lock_token = 'r'
939
1038
        branch._set_parent_location(None)
940
 
        client.finished_test()
 
1039
        self.assertFinished(client)
941
1040
 
942
1041
    def test_parent(self):
943
1042
        transport = MemoryTransport()
954
1053
        branch._lock_token = 'b'
955
1054
        branch._repo_lock_token = 'r'
956
1055
        branch._set_parent_location('foo')
957
 
        client.finished_test()
 
1056
        self.assertFinished(client)
958
1057
 
959
1058
    def test_backwards_compat(self):
960
1059
        self.setup_smart_server_with_call_log()
992
1091
        transport = transport.clone('quack')
993
1092
        branch = self.make_remote_branch(transport, client)
994
1093
        result = branch.tags.get_tag_dict()
995
 
        client.finished_test()
 
1094
        self.assertFinished(client)
996
1095
        self.assertEqual({}, result)
997
1096
 
998
1097
 
 
1098
class TestBranchSetTagsBytes(RemoteBranchTestCase):
 
1099
 
 
1100
    def test_trivial(self):
 
1101
        transport = MemoryTransport()
 
1102
        client = FakeClient(transport.base)
 
1103
        client.add_expected_call(
 
1104
            'Branch.get_stacked_on_url', ('quack/',),
 
1105
            'error', ('NotStacked',))
 
1106
        client.add_expected_call(
 
1107
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1108
            'success', ('',))
 
1109
        transport.mkdir('quack')
 
1110
        transport = transport.clone('quack')
 
1111
        branch = self.make_remote_branch(transport, client)
 
1112
        self.lock_remote_branch(branch)
 
1113
        branch._set_tags_bytes('tags bytes')
 
1114
        self.assertFinished(client)
 
1115
        self.assertEqual('tags bytes', client._calls[-1][-1])
 
1116
 
 
1117
    def test_backwards_compatible(self):
 
1118
        transport = MemoryTransport()
 
1119
        client = FakeClient(transport.base)
 
1120
        client.add_expected_call(
 
1121
            'Branch.get_stacked_on_url', ('quack/',),
 
1122
            'error', ('NotStacked',))
 
1123
        client.add_expected_call(
 
1124
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
 
1125
            'unknown', ('Branch.set_tags_bytes',))
 
1126
        transport.mkdir('quack')
 
1127
        transport = transport.clone('quack')
 
1128
        branch = self.make_remote_branch(transport, client)
 
1129
        self.lock_remote_branch(branch)
 
1130
        class StubRealBranch(object):
 
1131
            def __init__(self):
 
1132
                self.calls = []
 
1133
            def _set_tags_bytes(self, bytes):
 
1134
                self.calls.append(('set_tags_bytes', bytes))
 
1135
        real_branch = StubRealBranch()
 
1136
        branch._real_branch = real_branch
 
1137
        branch._set_tags_bytes('tags bytes')
 
1138
        # Call a second time, to exercise the 'remote version already inferred'
 
1139
        # code path.
 
1140
        branch._set_tags_bytes('tags bytes')
 
1141
        self.assertFinished(client)
 
1142
        self.assertEqual(
 
1143
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
 
1144
 
 
1145
 
999
1146
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1000
1147
 
1001
1148
    def test_empty_branch(self):
1012
1159
        transport = transport.clone('quack')
1013
1160
        branch = self.make_remote_branch(transport, client)
1014
1161
        result = branch.last_revision_info()
1015
 
        client.finished_test()
 
1162
        self.assertFinished(client)
1016
1163
        self.assertEqual((0, NULL_REVISION), result)
1017
1164
 
1018
1165
    def test_non_empty_branch(self):
1073
1220
        client = FakeClient(self.get_url())
1074
1221
        branch_network_name = self.get_branch_format().network_name()
1075
1222
        client.add_expected_call(
1076
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1223
            'BzrDir.open_branchV3', ('stacked/',),
1077
1224
            'success', ('branch', branch_network_name))
1078
1225
        client.add_expected_call(
1079
1226
            'BzrDir.find_repositoryV3', ('stacked/',),
1093
1240
        branch = bzrdir.open_branch()
1094
1241
        result = branch.get_stacked_on_url()
1095
1242
        self.assertEqual('../base', result)
1096
 
        client.finished_test()
 
1243
        self.assertFinished(client)
1097
1244
        # it's in the fallback list both for the RemoteRepository and its vfs
1098
1245
        # repository
1099
1246
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1101
1248
            len(branch.repository._real_repository._fallback_repositories))
1102
1249
 
1103
1250
    def test_get_stacked_on_real_branch(self):
1104
 
        base_branch = self.make_branch('base', format='1.6')
1105
 
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1251
        base_branch = self.make_branch('base')
 
1252
        stacked_branch = self.make_branch('stacked')
1106
1253
        stacked_branch.set_stacked_on_url('../base')
1107
1254
        reference_format = self.get_repo_format()
1108
1255
        network_name = reference_format.network_name()
1109
1256
        client = FakeClient(self.get_url())
1110
1257
        branch_network_name = self.get_branch_format().network_name()
1111
1258
        client.add_expected_call(
1112
 
            'BzrDir.open_branchV2', ('stacked/',),
 
1259
            'BzrDir.open_branchV3', ('stacked/',),
1113
1260
            'success', ('branch', branch_network_name))
1114
1261
        client.add_expected_call(
1115
1262
            'BzrDir.find_repositoryV3', ('stacked/',),
1116
 
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
 
1263
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1117
1264
        # called twice, once from constructor and then again by us
1118
1265
        client.add_expected_call(
1119
1266
            'Branch.get_stacked_on_url', ('stacked/',),
1126
1273
        branch = bzrdir.open_branch()
1127
1274
        result = branch.get_stacked_on_url()
1128
1275
        self.assertEqual('../base', result)
1129
 
        client.finished_test()
 
1276
        self.assertFinished(client)
1130
1277
        # it's in the fallback list both for the RemoteRepository.
1131
1278
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1132
1279
        # And we haven't had to construct a real repository.
1167
1314
        result = branch.set_revision_history([])
1168
1315
        branch.unlock()
1169
1316
        self.assertEqual(None, result)
1170
 
        client.finished_test()
 
1317
        self.assertFinished(client)
1171
1318
 
1172
1319
    def test_set_nonempty(self):
1173
1320
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1205
1352
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1206
1353
        branch.unlock()
1207
1354
        self.assertEqual(None, result)
1208
 
        client.finished_test()
 
1355
        self.assertFinished(client)
1209
1356
 
1210
1357
    def test_no_such_revision(self):
1211
1358
        transport = MemoryTransport()
1240
1387
        self.assertRaises(
1241
1388
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1242
1389
        branch.unlock()
1243
 
        client.finished_test()
 
1390
        self.assertFinished(client)
1244
1391
 
1245
1392
    def test_tip_change_rejected(self):
1246
1393
        """TipChangeRejected responses cause a TipChangeRejected exception to
1283
1430
        self.assertIsInstance(err.msg, unicode)
1284
1431
        self.assertEqual(rejection_msg_unicode, err.msg)
1285
1432
        branch.unlock()
1286
 
        client.finished_test()
 
1433
        self.assertFinished(client)
1287
1434
 
1288
1435
 
1289
1436
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
1343
1490
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1344
1491
        branch.unlock()
1345
1492
 
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
 
 
1356
1493
    def test_backwards_compatibility(self):
1357
1494
        """If the server does not support the Branch.set_last_revision_info
1358
1495
        verb (which is new in 1.4), then the client falls back to VFS methods.
1399
1536
        self.assertEqual(
1400
1537
            [('set_last_revision_info', 1234, 'a-revision-id')],
1401
1538
            real_branch.calls)
1402
 
        client.finished_test()
 
1539
        self.assertFinished(client)
1403
1540
 
1404
1541
    def test_unexpected_error(self):
1405
1542
        # If the server sends an error the client doesn't understand, it gets
1513
1650
        config = branch._get_config()
1514
1651
        config.set_option('foo', 'bar')
1515
1652
        branch.unlock()
1516
 
        client.finished_test()
 
1653
        self.assertFinished(client)
1517
1654
 
1518
1655
    def test_backwards_compat_set_option(self):
1519
1656
        self.setup_smart_server_with_call_log()
1543
1680
        transport = transport.clone('quack')
1544
1681
        branch = self.make_remote_branch(transport, client)
1545
1682
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
1546
 
        client.finished_test()
 
1683
        self.assertFinished(client)
1547
1684
 
1548
1685
 
1549
1686
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1674
1811
        return repo, client
1675
1812
 
1676
1813
 
 
1814
def remoted_description(format):
 
1815
    return 'Remote: ' + format.get_format_description()
 
1816
 
 
1817
 
 
1818
class TestBranchFormat(tests.TestCase):
 
1819
 
 
1820
    def test_get_format_description(self):
 
1821
        remote_format = RemoteBranchFormat()
 
1822
        real_format = branch.BranchFormat.get_default_format()
 
1823
        remote_format._network_name = real_format.network_name()
 
1824
        self.assertEqual(remoted_description(real_format),
 
1825
            remote_format.get_format_description())
 
1826
 
 
1827
 
1677
1828
class TestRepositoryFormat(TestRemoteRepository):
1678
1829
 
1679
1830
    def test_fast_delta(self):
1686
1837
        false_format._network_name = false_name
1687
1838
        self.assertEqual(False, false_format.fast_deltas)
1688
1839
 
 
1840
    def test_get_format_description(self):
 
1841
        remote_repo_format = RemoteRepositoryFormat()
 
1842
        real_format = repository.RepositoryFormat.get_default_format()
 
1843
        remote_repo_format._network_name = real_format.network_name()
 
1844
        self.assertEqual(remoted_description(real_format),
 
1845
            remote_repo_format.get_format_description())
 
1846
 
1689
1847
 
1690
1848
class TestRepositoryGatherStats(TestRemoteRepository):
1691
1849
 
1876
2034
        self.assertLength(1, self.hpss_calls)
1877
2035
 
1878
2036
    def disableExtraResults(self):
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)
 
2037
        self.overrideAttr(SmartServerRepositoryGetParentMap,
 
2038
                          'no_extra_results', True)
1884
2039
 
1885
2040
    def test_null_cached_missing_and_stop_key(self):
1886
2041
        self.setup_smart_server_with_call_log()
1945
2100
 
1946
2101
    def test_allows_new_revisions(self):
1947
2102
        """get_parent_map's results can be updated by commit."""
1948
 
        smart_server = server.SmartTCPServer_for_testing()
1949
 
        smart_server.setUp()
1950
 
        self.addCleanup(smart_server.tearDown)
 
2103
        smart_server = test_server.SmartTCPServer_for_testing()
 
2104
        self.start_server(smart_server)
1951
2105
        self.make_branch('branch')
1952
2106
        branch = Branch.open(smart_server.get_url() + '/branch')
1953
2107
        tree = branch.create_checkout('tree', lightweight=True)
2045
2199
            'success', ('ok', 'rev-five'))
2046
2200
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2047
2201
        self.assertEqual((True, 'rev-five'), result)
2048
 
        client.finished_test()
 
2202
        self.assertFinished(client)
2049
2203
 
2050
2204
    def test_history_incomplete(self):
2051
2205
        repo, client = self.setup_fake_client_and_repository('quack')
2054
2208
            'success', ('history-incomplete', 10, 'rev-ten'))
2055
2209
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2056
2210
        self.assertEqual((False, (10, 'rev-ten')), result)
2057
 
        client.finished_test()
 
2211
        self.assertFinished(client)
2058
2212
 
2059
2213
    def test_history_incomplete_with_fallback(self):
2060
2214
        """A 'history-incomplete' response causes the fallback repository to be
2062
2216
        """
2063
2217
        # Make a repo with a fallback repo, both using a FakeClient.
2064
2218
        format = remote.response_tuple_to_repo_format(
2065
 
            ('yes', 'no', 'yes', 'fake-network-name'))
 
2219
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2066
2220
        repo, client = self.setup_fake_client_and_repository('quack')
2067
2221
        repo._format = format
2068
2222
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2069
2223
            'fallback')
2070
2224
        fallback_repo._client = client
 
2225
        fallback_repo._format = format
2071
2226
        repo.add_fallback_repository(fallback_repo)
2072
2227
        # First the client should ask the primary repo
2073
2228
        client.add_expected_call(
2080
2235
            'success', ('ok', 'rev-one'))
2081
2236
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2082
2237
        self.assertEqual((True, 'rev-one'), result)
2083
 
        client.finished_test()
 
2238
        self.assertFinished(client)
2084
2239
 
2085
2240
    def test_nosuchrevision(self):
2086
2241
        # 'nosuchrevision' is returned when the known-revid is not found in the
2092
2247
        self.assertRaises(
2093
2248
            errors.NoSuchRevision,
2094
2249
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2095
 
        client.finished_test()
 
2250
        self.assertFinished(client)
 
2251
 
 
2252
    def test_branch_fallback_locking(self):
 
2253
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
 
2254
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
 
2255
        will be invoked, which will fail if the repo is unlocked.
 
2256
        """
 
2257
        self.setup_smart_server_with_call_log()
 
2258
        tree = self.make_branch_and_memory_tree('.')
 
2259
        tree.lock_write()
 
2260
        rev1 = tree.commit('First')
 
2261
        rev2 = tree.commit('Second')
 
2262
        tree.unlock()
 
2263
        branch = tree.branch
 
2264
        self.assertFalse(branch.is_locked())
 
2265
        self.reset_smart_call_log()
 
2266
        verb = 'Repository.get_rev_id_for_revno'
 
2267
        self.disable_verb(verb)
 
2268
        self.assertEqual(rev1, branch.get_rev_id(1))
 
2269
        self.assertLength(1, [call for call in self.hpss_calls if
 
2270
                              call.call.method == verb])
2096
2271
 
2097
2272
 
2098
2273
class TestRepositoryIsShared(TestRemoteRepository):
2215
2390
        self.assertEqual([], client._calls)
2216
2391
 
2217
2392
 
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()
 
2393
class TestRepositoryInsertStreamBase(TestRemoteRepository):
 
2394
    """Base class for Repository.insert_stream and .insert_stream_1.19
 
2395
    tests.
 
2396
    """
 
2397
    
 
2398
    def checkInsertEmptyStream(self, repo, client):
 
2399
        """Insert an empty stream, checking the result.
 
2400
 
 
2401
        This checks that there are no resume_tokens or missing_keys, and that
 
2402
        the client is finished.
 
2403
        """
 
2404
        sink = repo._get_sink()
 
2405
        fmt = repository.RepositoryFormat.get_default_format()
 
2406
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2407
        self.assertEqual([], resume_tokens)
 
2408
        self.assertEqual(set(), missing_keys)
 
2409
        self.assertFinished(client)
 
2410
 
 
2411
 
 
2412
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
 
2413
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
 
2414
    not available.
 
2415
 
 
2416
    This test case is very similar to TestRepositoryInsertStream_1_19.
 
2417
    """
 
2418
 
 
2419
    def setUp(self):
 
2420
        TestRemoteRepository.setUp(self)
 
2421
        self.disable_verb('Repository.insert_stream_1.19')
 
2422
 
 
2423
    def test_unlocked_repo(self):
 
2424
        transport_path = 'quack'
 
2425
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2426
        client.add_expected_call(
 
2427
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2428
            'unknown', ('Repository.insert_stream_1.19',))
 
2429
        client.add_expected_call(
 
2430
            'Repository.insert_stream', ('quack/', ''),
 
2431
            'success', ('ok',))
 
2432
        client.add_expected_call(
 
2433
            'Repository.insert_stream', ('quack/', ''),
 
2434
            'success', ('ok',))
 
2435
        self.checkInsertEmptyStream(repo, client)
 
2436
 
 
2437
    def test_locked_repo_with_no_lock_token(self):
 
2438
        transport_path = 'quack'
 
2439
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2440
        client.add_expected_call(
 
2441
            'Repository.lock_write', ('quack/', ''),
 
2442
            'success', ('ok', ''))
 
2443
        client.add_expected_call(
 
2444
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2445
            'unknown', ('Repository.insert_stream_1.19',))
 
2446
        client.add_expected_call(
 
2447
            'Repository.insert_stream', ('quack/', ''),
 
2448
            'success', ('ok',))
 
2449
        client.add_expected_call(
 
2450
            'Repository.insert_stream', ('quack/', ''),
 
2451
            'success', ('ok',))
 
2452
        repo.lock_write()
 
2453
        self.checkInsertEmptyStream(repo, client)
 
2454
 
 
2455
    def test_locked_repo_with_lock_token(self):
 
2456
        transport_path = 'quack'
 
2457
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2458
        client.add_expected_call(
 
2459
            'Repository.lock_write', ('quack/', ''),
 
2460
            'success', ('ok', 'a token'))
 
2461
        client.add_expected_call(
 
2462
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2463
            'unknown', ('Repository.insert_stream_1.19',))
 
2464
        client.add_expected_call(
 
2465
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2466
            'success', ('ok',))
 
2467
        client.add_expected_call(
 
2468
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2469
            'success', ('ok',))
 
2470
        repo.lock_write()
 
2471
        self.checkInsertEmptyStream(repo, client)
 
2472
 
 
2473
    def test_stream_with_inventory_deltas(self):
 
2474
        """'inventory-deltas' substreams cannot be sent to the
 
2475
        Repository.insert_stream verb, because not all servers that implement
 
2476
        that verb will accept them.  So when one is encountered the RemoteSink
 
2477
        immediately stops using that verb and falls back to VFS insert_stream.
 
2478
        """
 
2479
        transport_path = 'quack'
 
2480
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2481
        client.add_expected_call(
 
2482
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2483
            'unknown', ('Repository.insert_stream_1.19',))
 
2484
        client.add_expected_call(
 
2485
            'Repository.insert_stream', ('quack/', ''),
 
2486
            'success', ('ok',))
 
2487
        client.add_expected_call(
 
2488
            'Repository.insert_stream', ('quack/', ''),
 
2489
            'success', ('ok',))
 
2490
        # Create a fake real repository for insert_stream to fall back on, so
 
2491
        # that we can directly see the records the RemoteSink passes to the
 
2492
        # real sink.
 
2493
        class FakeRealSink:
 
2494
            def __init__(self):
 
2495
                self.records = []
 
2496
            def insert_stream(self, stream, src_format, resume_tokens):
 
2497
                for substream_kind, substream in stream:
 
2498
                    self.records.append(
 
2499
                        (substream_kind, [record.key for record in substream]))
 
2500
                return ['fake tokens'], ['fake missing keys']
 
2501
        fake_real_sink = FakeRealSink()
 
2502
        class FakeRealRepository:
 
2503
            def _get_sink(self):
 
2504
                return fake_real_sink
 
2505
            def is_in_write_group(self):
 
2506
                return False
 
2507
            def refresh_data(self):
 
2508
                return True
 
2509
        repo._real_repository = FakeRealRepository()
 
2510
        sink = repo._get_sink()
 
2511
        fmt = repository.RepositoryFormat.get_default_format()
 
2512
        stream = self.make_stream_with_inv_deltas(fmt)
 
2513
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
 
2514
        # Every record from the first inventory delta should have been sent to
 
2515
        # the VFS sink.
 
2516
        expected_records = [
 
2517
            ('inventory-deltas', [('rev2',), ('rev3',)]),
 
2518
            ('texts', [('some-rev', 'some-file')])]
 
2519
        self.assertEqual(expected_records, fake_real_sink.records)
 
2520
        # The return values from the real sink's insert_stream are propagated
 
2521
        # back to the original caller.
 
2522
        self.assertEqual(['fake tokens'], resume_tokens)
 
2523
        self.assertEqual(['fake missing keys'], missing_keys)
 
2524
        self.assertFinished(client)
 
2525
 
 
2526
    def make_stream_with_inv_deltas(self, fmt):
 
2527
        """Make a simple stream with an inventory delta followed by more
 
2528
        records and more substreams to test that all records and substreams
 
2529
        from that point on are used.
 
2530
 
 
2531
        This sends, in order:
 
2532
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
 
2533
             inventory-deltas.
 
2534
           * texts substream: (some-rev, some-file)
 
2535
        """
 
2536
        # Define a stream using generators so that it isn't rewindable.
 
2537
        inv = inventory.Inventory(revision_id='rev1')
 
2538
        inv.root.revision = 'rev1'
 
2539
        def stream_with_inv_delta():
 
2540
            yield ('inventories', inventories_substream())
 
2541
            yield ('inventory-deltas', inventory_delta_substream())
 
2542
            yield ('texts', [
 
2543
                versionedfile.FulltextContentFactory(
 
2544
                    ('some-rev', 'some-file'), (), None, 'content')])
 
2545
        def inventories_substream():
 
2546
            # An empty inventory fulltext.  This will be streamed normally.
 
2547
            text = fmt._serializer.write_inventory_to_string(inv)
 
2548
            yield versionedfile.FulltextContentFactory(
 
2549
                ('rev1',), (), None, text)
 
2550
        def inventory_delta_substream():
 
2551
            # An inventory delta.  This can't be streamed via this verb, so it
 
2552
            # will trigger a fallback to VFS insert_stream.
 
2553
            entry = inv.make_entry(
 
2554
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
 
2555
            entry.revision = 'ghost'
 
2556
            delta = [(None, 'newdir', 'newdir-id', entry)]
 
2557
            serializer = inventory_delta.InventoryDeltaSerializer(
 
2558
                versioned_root=True, tree_references=False)
 
2559
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
 
2560
            yield versionedfile.ChunkedContentFactory(
 
2561
                ('rev2',), (('rev1',)), None, lines)
 
2562
            # Another delta.
 
2563
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
 
2564
            yield versionedfile.ChunkedContentFactory(
 
2565
                ('rev3',), (('rev1',)), None, lines)
 
2566
        return stream_with_inv_delta()
 
2567
 
 
2568
 
 
2569
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
 
2570
 
 
2571
    def test_unlocked_repo(self):
 
2572
        transport_path = 'quack'
 
2573
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2574
        client.add_expected_call(
 
2575
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2576
            'success', ('ok',))
 
2577
        client.add_expected_call(
 
2578
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2579
            'success', ('ok',))
 
2580
        self.checkInsertEmptyStream(repo, client)
 
2581
 
 
2582
    def test_locked_repo_with_no_lock_token(self):
 
2583
        transport_path = 'quack'
 
2584
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2585
        client.add_expected_call(
 
2586
            'Repository.lock_write', ('quack/', ''),
 
2587
            'success', ('ok', ''))
 
2588
        client.add_expected_call(
 
2589
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2590
            'success', ('ok',))
 
2591
        client.add_expected_call(
 
2592
            'Repository.insert_stream_1.19', ('quack/', ''),
 
2593
            'success', ('ok',))
 
2594
        repo.lock_write()
 
2595
        self.checkInsertEmptyStream(repo, client)
 
2596
 
 
2597
    def test_locked_repo_with_lock_token(self):
 
2598
        transport_path = 'quack'
 
2599
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2600
        client.add_expected_call(
 
2601
            'Repository.lock_write', ('quack/', ''),
 
2602
            'success', ('ok', 'a token'))
 
2603
        client.add_expected_call(
 
2604
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2605
            'success', ('ok',))
 
2606
        client.add_expected_call(
 
2607
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
 
2608
            'success', ('ok',))
 
2609
        repo.lock_write()
 
2610
        self.checkInsertEmptyStream(repo, client)
2275
2611
 
2276
2612
 
2277
2613
class TestRepositoryTarball(TestRemoteRepository):
2313
2649
    """RemoteRepository.copy_content_into optimizations"""
2314
2650
 
2315
2651
    def test_copy_content_remote_to_local(self):
2316
 
        self.transport_server = server.SmartTCPServer_for_testing
 
2652
        self.transport_server = test_server.SmartTCPServer_for_testing
2317
2653
        src_repo = self.make_repository('repo1')
2318
2654
        src_repo = repository.Repository.open(self.get_url('repo1'))
2319
2655
        # At the moment the tarball-based copy_content_into can't write back
2362
2698
        client.add_expected_call(
2363
2699
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
2364
2700
        repo.autopack()
2365
 
        client.finished_test()
 
2701
        self.assertFinished(client)
2366
2702
 
2367
2703
    def test_ok_with_real_repo(self):
2368
2704
        """When the server returns 'ok' and there is a _real_repository, then
2467
2803
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2468
2804
        self.assertEqual(expected_error, translated_error)
2469
2805
 
 
2806
    def test_nobranch_one_arg(self):
 
2807
        bzrdir = self.make_bzrdir('')
 
2808
        translated_error = self.translateTuple(
 
2809
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
 
2810
        expected_error = errors.NotBranchError(
 
2811
            path=bzrdir.root_transport.base,
 
2812
            detail='extra detail')
 
2813
        self.assertEqual(expected_error, translated_error)
 
2814
 
2470
2815
    def test_LockContention(self):
2471
2816
        translated_error = self.translateTuple(('LockContention',))
2472
2817
        expected_error = errors.LockContention('(remote lock)')
2512
2857
        expected_error = errors.ReadError(path)
2513
2858
        self.assertEqual(expected_error, translated_error)
2514
2859
 
 
2860
    def test_IncompatibleRepositories(self):
 
2861
        translated_error = self.translateTuple(('IncompatibleRepositories',
 
2862
            "repo1", "repo2", "details here"))
 
2863
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
 
2864
            "details here")
 
2865
        self.assertEqual(expected_error, translated_error)
 
2866
 
2515
2867
    def test_PermissionDenied_no_args(self):
2516
2868
        path = 'a path'
2517
2869
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2578
2930
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2579
2931
        # been muttered to the log file for developer to look at.
2580
2932
        self.assertContainsRe(
2581
 
            self._get_log(keep_log_file=True),
 
2933
            self.get_log(),
2582
2934
            "Missing key 'branch' in context")
2583
2935
 
2584
2936
    def test_path_missing(self):
2592
2944
        self.assertEqual(server_error, translated_error)
2593
2945
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2594
2946
        # been muttered to the log file for developer to look at.
2595
 
        self.assertContainsRe(
2596
 
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
 
2947
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
2597
2948
 
2598
2949
 
2599
2950
class TestStacking(tests.TestCaseWithTransport):
2617
2968
        stacked_branch = self.make_branch('stacked', format='1.9')
2618
2969
        stacked_branch.set_stacked_on_url('../base')
2619
2970
        # start a server looking at this
2620
 
        smart_server = server.SmartTCPServer_for_testing()
2621
 
        smart_server.setUp()
2622
 
        self.addCleanup(smart_server.tearDown)
 
2971
        smart_server = test_server.SmartTCPServer_for_testing()
 
2972
        self.start_server(smart_server)
2623
2973
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
2624
2974
        # can get its branch and repository
2625
2975
        remote_branch = remote_bzrdir.open_branch()
2647
2997
        tree1.commit('rev1', rev_id='rev1')
2648
2998
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
2649
2999
            ).open_workingtree()
2650
 
        tree2.commit('local changes make me feel good.')
 
3000
        local_tree = tree2.branch.create_checkout('local')
 
3001
        local_tree.commit('local changes make me feel good.')
2651
3002
        branch2 = Branch.open(self.get_url('tree2'))
2652
3003
        branch2.lock_read()
2653
3004
        self.addCleanup(branch2.unlock)
2675
3026
                    result.append(content.key[-1])
2676
3027
        return result
2677
3028
 
2678
 
    def get_ordered_revs(self, format, order):
 
3029
    def get_ordered_revs(self, format, order, branch_factory=None):
2679
3030
        """Get a list of the revisions in a stream to format format.
2680
3031
 
2681
3032
        :param format: The format of the target.
2682
3033
        :param order: the order that target should have requested.
 
3034
        :param branch_factory: A callable to create a trunk and stacked branch
 
3035
            to fetch from. If none, self.prepare_stacked_remote_branch is used.
2683
3036
        :result: The revision ids in the stream, in the order seen,
2684
3037
            the topological order of revisions in the source.
2685
3038
        """
2687
3040
        target_repository_format = unordered_format.repository_format
2688
3041
        # Cross check
2689
3042
        self.assertEqual(order, target_repository_format._fetch_order)
2690
 
        trunk, stacked = self.prepare_stacked_remote_branch()
 
3043
        if branch_factory is None:
 
3044
            branch_factory = self.prepare_stacked_remote_branch
 
3045
        _, stacked = branch_factory()
2691
3046
        source = stacked.repository._get_source(target_repository_format)
2692
3047
        tip = stacked.last_revision()
2693
3048
        revs = stacked.repository.get_ancestry(tip)
2712
3067
        # from the server, then one from the backing branch.
2713
3068
        self.assertLength(2, self.hpss_calls)
2714
3069
 
 
3070
    def test_stacked_on_stacked_get_stream_unordered(self):
 
3071
        # Repository._get_source.get_stream() from a stacked repository which
 
3072
        # is itself stacked yields the full data from all three sources.
 
3073
        def make_stacked_stacked():
 
3074
            _, stacked = self.prepare_stacked_remote_branch()
 
3075
            tree = stacked.bzrdir.sprout('tree3', stacked=True
 
3076
                ).open_workingtree()
 
3077
            local_tree = tree.branch.create_checkout('local-tree3')
 
3078
            local_tree.commit('more local changes are better')
 
3079
            branch = Branch.open(self.get_url('tree3'))
 
3080
            branch.lock_read()
 
3081
            self.addCleanup(branch.unlock)
 
3082
            return None, branch
 
3083
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
 
3084
            branch_factory=make_stacked_stacked)
 
3085
        self.assertEqual(set(expected_revs), set(rev_ord))
 
3086
        # Getting unordered results should have made a streaming data request
 
3087
        # from the server, and one from each backing repo
 
3088
        self.assertLength(3, self.hpss_calls)
 
3089
 
2715
3090
    def test_stacked_get_stream_topological(self):
2716
3091
        # Repository._get_source.get_stream() from a stacked repository with
2717
3092
        # topological sorting yields the full data from both stacked and
2718
3093
        # stacked upon sources in topological order.
2719
3094
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
2720
3095
        self.assertEqual(expected_revs, rev_ord)
2721
 
        # Getting topological sort requires VFS calls still
2722
 
        self.assertLength(12, self.hpss_calls)
 
3096
        # Getting topological sort requires VFS calls still - one of which is
 
3097
        # pushing up from the bound branch.
 
3098
        self.assertLength(13, self.hpss_calls)
2723
3099
 
2724
3100
    def test_stacked_get_stream_groupcompress(self):
2725
3101
        # Repository._get_source.get_stream() from a stacked repository with
2754
3130
        super(TestRemoteBranchEffort, self).setUp()
2755
3131
        # Create a smart server that publishes whatever the backing VFS server
2756
3132
        # does.
2757
 
        self.smart_server = server.SmartTCPServer_for_testing()
2758
 
        self.smart_server.setUp(self.get_server())
2759
 
        self.addCleanup(self.smart_server.tearDown)
 
3133
        self.smart_server = test_server.SmartTCPServer_for_testing()
 
3134
        self.start_server(self.smart_server, self.get_server())
2760
3135
        # Log all HPSS calls into self.hpss_calls.
2761
3136
        _SmartClient.hooks.install_named_hook(
2762
3137
            'call', self.capture_hpss_call, None)