~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Jonathan Lange
  • Date: 2009-06-10 08:05:05 UTC
  • mto: This revision was merged to the branch mainline in revision 4433.
  • Revision ID: jml@canonical.com-20090610080505-lmch4q01z1q7deu2
MoreĀ unusedĀ imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
from cStringIO import StringIO
28
28
 
29
29
from bzrlib import (
30
 
    branch,
31
30
    bzrdir,
32
31
    config,
33
 
    controldir,
34
32
    errors,
35
33
    graph,
36
 
    inventory,
37
 
    inventory_delta,
 
34
    pack,
38
35
    remote,
39
36
    repository,
 
37
    smart,
40
38
    tests,
41
 
    transport,
42
39
    treebuilder,
43
 
    versionedfile,
 
40
    urlutils,
44
41
    )
45
42
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import (
47
 
    BzrDir,
48
 
    BzrDirFormat,
49
 
    RemoteBzrProber,
50
 
    )
 
43
from bzrlib.bzrdir import BzrDir, BzrDirFormat
51
44
from bzrlib.remote import (
52
45
    RemoteBranch,
53
46
    RemoteBranchFormat,
54
47
    RemoteBzrDir,
 
48
    RemoteBzrDirFormat,
55
49
    RemoteRepository,
56
50
    RemoteRepositoryFormat,
57
51
    )
58
52
from bzrlib.repofmt import groupcompress_repo, pack_repo
59
53
from bzrlib.revision import NULL_REVISION
60
 
from bzrlib.smart import medium
 
54
from bzrlib.smart import server, medium
61
55
from bzrlib.smart.client import _SmartClient
62
56
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
63
57
from bzrlib.tests import (
64
58
    condition_isinstance,
65
59
    split_suite_by_condition,
66
60
    multiply_tests,
67
 
    test_server,
68
61
    )
 
62
from bzrlib.transport import get_transport, http
69
63
from bzrlib.transport.memory import MemoryTransport
70
64
from bzrlib.transport.remote import (
71
65
    RemoteTransport,
78
72
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
79
73
    smart_server_version_scenarios = [
80
74
        ('HPSS-v2',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
75
            {'transport_server': server.SmartTCPServer_for_testing_v2_only}),
82
76
        ('HPSS-v3',
83
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
 
77
            {'transport_server': server.SmartTCPServer_for_testing})]
84
78
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
79
 
86
80
 
91
85
        self.transport = self.get_transport()
92
86
        # make a branch that can be opened over the smart transport
93
87
        self.local_wt = BzrDir.create_standalone_workingtree('.')
94
 
        self.addCleanup(self.transport.disconnect)
 
88
 
 
89
    def tearDown(self):
 
90
        self.transport.disconnect()
 
91
        tests.TestCaseWithTransport.tearDown(self)
95
92
 
96
93
    def test_create_remote_bzrdir(self):
97
94
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
121
118
    def test_find_correct_format(self):
122
119
        """Should open a RemoteBzrDir over a RemoteTransport"""
123
120
        fmt = BzrDirFormat.find_format(self.transport)
124
 
        self.assertTrue(bzrdir.RemoteBzrProber
125
 
                        in controldir.ControlDirFormat._server_probers)
 
121
        self.assertTrue(RemoteBzrDirFormat
 
122
                        in BzrDirFormat._control_server_formats)
126
123
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
127
124
 
128
125
    def test_open_detected_smart_format(self):
134
131
        b = BzrDir.open_from_transport(self.transport).open_branch()
135
132
        self.assertStartsWith(str(b), 'RemoteBranch(')
136
133
 
137
 
    def test_remote_bzrdir_repr(self):
138
 
        b = BzrDir.open_from_transport(self.transport)
139
 
        self.assertStartsWith(str(b), 'RemoteBzrDir(')
140
 
 
141
134
    def test_remote_branch_format_supports_stacking(self):
142
135
        t = self.transport
143
136
        self.make_branch('unstackable', format='pack-0.92')
160
153
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
161
154
        self.assertTrue(r._format.supports_external_lookups)
162
155
 
163
 
    def test_remote_branch_set_append_revisions_only(self):
164
 
        # Make a format 1.9 branch, which supports append_revisions_only
165
 
        branch = self.make_branch('branch', format='1.9')
166
 
        config = branch.get_config()
167
 
        branch.set_append_revisions_only(True)
168
 
        self.assertEqual(
169
 
            'True', config.get_user_option('append_revisions_only'))
170
 
        branch.set_append_revisions_only(False)
171
 
        self.assertEqual(
172
 
            'False', config.get_user_option('append_revisions_only'))
173
 
 
174
 
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
175
 
        branch = self.make_branch('branch', format='knit')
176
 
        config = branch.get_config()
177
 
        self.assertRaises(
178
 
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
179
 
 
180
156
 
181
157
class FakeProtocol(object):
182
158
    """Lookalike SmartClientRequestProtocolOne allowing body reading tests."""
283
259
        self.expecting_body = True
284
260
        return result[1], FakeProtocol(result[2], self)
285
261
 
286
 
    def call_with_body_bytes(self, method, args, body):
287
 
        self._check_call(method, args)
288
 
        self._calls.append(('call_with_body_bytes', method, args, body))
289
 
        result = self._get_next_response()
290
 
        return result[1], FakeProtocol(result[2], self)
291
 
 
292
262
    def call_with_body_bytes_expecting_body(self, method, args, body):
293
263
        self._check_call(method, args)
294
264
        self._calls.append(('call_with_body_bytes_expecting_body', method,
344
314
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
345
315
        return reference_bzrdir_format.repository_format
346
316
 
347
 
    def assertFinished(self, fake_client):
348
 
        """Assert that all of a FakeClient's expected calls have occurred."""
349
 
        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)
350
325
 
351
326
 
352
327
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
358
333
        a given client_base and transport_base.
359
334
        """
360
335
        client_medium = medium.SmartClientMedium(client_base)
361
 
        t = transport.get_transport(transport_base)
362
 
        result = client_medium.remote_path_from_transport(t)
 
336
        transport = get_transport(transport_base)
 
337
        result = client_medium.remote_path_from_transport(transport)
363
338
        self.assertEqual(expected, result)
364
339
 
365
340
    def test_remote_path_from_transport(self):
376
351
        a given transport_base and relpath of that transport.  (Note that
377
352
        HttpTransportBase is a subclass of SmartClientMedium)
378
353
        """
379
 
        base_transport = transport.get_transport(transport_base)
 
354
        base_transport = get_transport(transport_base)
380
355
        client_medium = base_transport.get_smart_medium()
381
356
        cloned_transport = base_transport.clone(relpath)
382
357
        result = client_medium.remote_path_from_transport(cloned_transport)
417
392
        # Calling _remember_remote_is_before again with a lower value works.
418
393
        client_medium._remember_remote_is_before((1, 5))
419
394
        self.assertTrue(client_medium._is_remote_before((1, 5)))
420
 
        # If you call _remember_remote_is_before with a higher value it logs a
421
 
        # warning, and continues to remember the lower value.
422
 
        self.assertNotContainsRe(self.get_log(), '_remember_remote_is_before')
423
 
        client_medium._remember_remote_is_before((1, 9))
424
 
        self.assertContainsRe(self.get_log(), '_remember_remote_is_before')
425
 
        self.assertTrue(client_medium._is_remote_before((1, 5)))
 
395
        # You cannot call _remember_remote_is_before with a larger value.
 
396
        self.assertRaises(
 
397
            AssertionError, client_medium._remember_remote_is_before, (1, 9))
426
398
 
427
399
 
428
400
class TestBzrDirCloningMetaDir(TestRemote):
447
419
            'BzrDir.cloning_metadir', ('quack/', 'False'),
448
420
            'error', ('BranchReference',)),
449
421
        client.add_expected_call(
450
 
            'BzrDir.open_branchV3', ('quack/',),
 
422
            'BzrDir.open_branchV2', ('quack/',),
451
423
            'success', ('ref', self.get_url('referenced'))),
452
424
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
453
425
            _client=client)
456
428
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
457
429
        self.assertEqual(expected._repository_format, result._repository_format)
458
430
        self.assertEqual(expected._branch_format, result._branch_format)
459
 
        self.assertFinished(client)
 
431
        client.finished_test()
460
432
 
461
433
    def test_current_server(self):
462
434
        transport = self.get_transport('.')
477
449
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
478
450
        self.assertEqual(None, result._repository_format)
479
451
        self.assertEqual(None, result._branch_format)
480
 
        self.assertFinished(client)
481
 
 
482
 
 
483
 
class TestBzrDirOpen(TestRemote):
484
 
 
485
 
    def make_fake_client_and_transport(self, path='quack'):
486
 
        transport = MemoryTransport()
487
 
        transport.mkdir(path)
488
 
        transport = transport.clone(path)
489
 
        client = FakeClient(transport.base)
490
 
        return client, transport
491
 
 
492
 
    def test_absent(self):
493
 
        client, transport = self.make_fake_client_and_transport()
494
 
        client.add_expected_call(
495
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
496
 
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
497
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
498
 
        self.assertFinished(client)
499
 
 
500
 
    def test_present_without_workingtree(self):
501
 
        client, transport = self.make_fake_client_and_transport()
502
 
        client.add_expected_call(
503
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
504
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
505
 
            _client=client, _force_probe=True)
506
 
        self.assertIsInstance(bd, RemoteBzrDir)
507
 
        self.assertFalse(bd.has_workingtree())
508
 
        self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
509
 
        self.assertFinished(client)
510
 
 
511
 
    def test_present_with_workingtree(self):
512
 
        client, transport = self.make_fake_client_and_transport()
513
 
        client.add_expected_call(
514
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
515
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
516
 
            _client=client, _force_probe=True)
517
 
        self.assertIsInstance(bd, RemoteBzrDir)
518
 
        self.assertTrue(bd.has_workingtree())
519
 
        self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
520
 
        self.assertFinished(client)
521
 
 
522
 
    def test_backwards_compat(self):
523
 
        client, transport = self.make_fake_client_and_transport()
524
 
        client.add_expected_call(
525
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
526
 
        client.add_expected_call(
527
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
528
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
529
 
            _client=client, _force_probe=True)
530
 
        self.assertIsInstance(bd, RemoteBzrDir)
531
 
        self.assertFinished(client)
532
 
 
533
 
    def test_backwards_compat_hpss_v2(self):
534
 
        client, transport = self.make_fake_client_and_transport()
535
 
        # Monkey-patch fake client to simulate real-world behaviour with v2
536
 
        # server: upon first RPC call detect the protocol version, and because
537
 
        # the version is 2 also do _remember_remote_is_before((1, 6)) before
538
 
        # continuing with the RPC.
539
 
        orig_check_call = client._check_call
540
 
        def check_call(method, args):
541
 
            client._medium._protocol_version = 2
542
 
            client._medium._remember_remote_is_before((1, 6))
543
 
            client._check_call = orig_check_call
544
 
            client._check_call(method, args)
545
 
        client._check_call = check_call
546
 
        client.add_expected_call(
547
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
548
 
        client.add_expected_call(
549
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
550
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
551
 
            _client=client, _force_probe=True)
552
 
        self.assertIsInstance(bd, RemoteBzrDir)
553
 
        self.assertFinished(client)
 
452
        client.finished_test()
554
453
 
555
454
 
556
455
class TestBzrDirOpenBranch(TestRemote):
560
459
        self.make_branch('.')
561
460
        a_dir = BzrDir.open(self.get_url('.'))
562
461
        self.reset_smart_call_log()
563
 
        verb = 'BzrDir.open_branchV3'
 
462
        verb = 'BzrDir.open_branchV2'
564
463
        self.disable_verb(verb)
565
464
        format = a_dir.open_branch()
566
465
        call_count = len([call for call in self.hpss_calls if
576
475
        transport = transport.clone('quack')
577
476
        client = FakeClient(transport.base)
578
477
        client.add_expected_call(
579
 
            'BzrDir.open_branchV3', ('quack/',),
 
478
            'BzrDir.open_branchV2', ('quack/',),
580
479
            'success', ('branch', branch_network_name))
581
480
        client.add_expected_call(
582
481
            'BzrDir.find_repositoryV3', ('quack/',),
589
488
        result = bzrdir.open_branch()
590
489
        self.assertIsInstance(result, RemoteBranch)
591
490
        self.assertEqual(bzrdir, result.bzrdir)
592
 
        self.assertFinished(client)
 
491
        client.finished_test()
593
492
 
594
493
    def test_branch_missing(self):
595
494
        transport = MemoryTransport()
601
500
            _client=client)
602
501
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
603
502
        self.assertEqual(
604
 
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
 
503
            [('call', 'BzrDir.open_branchV2', ('quack/',))],
605
504
            client._calls)
606
505
 
607
506
    def test__get_tree_branch(self):
608
507
        # _get_tree_branch is a form of open_branch, but it should only ask for
609
508
        # branch opening, not any other network requests.
610
509
        calls = []
611
 
        def open_branch(name=None):
 
510
        def open_branch():
612
511
            calls.append("Called")
613
512
            return "a-branch"
614
513
        transport = MemoryTransport()
631
530
        network_name = reference_format.network_name()
632
531
        branch_network_name = self.get_branch_format().network_name()
633
532
        client.add_expected_call(
634
 
            'BzrDir.open_branchV3', ('~hello/',),
 
533
            'BzrDir.open_branchV2', ('~hello/',),
635
534
            'success', ('branch', branch_network_name))
636
535
        client.add_expected_call(
637
536
            'BzrDir.find_repositoryV3', ('~hello/',),
642
541
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
643
542
            _client=client)
644
543
        result = bzrdir.open_branch()
645
 
        self.assertFinished(client)
 
544
        client.finished_test()
646
545
 
647
546
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
648
547
        reference_format = self.get_repo_format()
685
584
        old.
686
585
        """
687
586
        self.assertRaises(errors.NotBranchError,
688
 
            RemoteBzrProber.probe_transport, OldServerTransport())
 
587
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
689
588
 
690
589
 
691
590
class TestBzrDirCreateBranch(TestRemote):
746
645
        network_name = reference_format.network_name()
747
646
        client.add_expected_call(
748
647
            'BzrDir.create_repository', ('quack/',
749
 
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
750
 
                'False'),
751
 
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
 
648
                'Bazaar pack repository format 1 (needs bzr 0.92)\n', 'False'),
 
649
            'success', ('ok', 'no', 'no', 'no', network_name))
752
650
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
753
651
            _client=client)
754
652
        repo = a_bzrdir.create_repository()
756
654
        self.assertIsInstance(repo, remote.RemoteRepository)
757
655
        # its format should have the settings from the response
758
656
        format = repo._format
759
 
        self.assertTrue(format.rich_root_data)
760
 
        self.assertTrue(format.supports_tree_reference)
761
 
        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)
762
660
        self.assertEqual(network_name, format.network_name())
763
661
 
764
662
 
768
666
        # fallback all the way to the first version.
769
667
        reference_format = self.get_repo_format()
770
668
        network_name = reference_format.network_name()
771
 
        server_url = 'bzr://example.com/'
772
 
        self.permit_url(server_url)
773
 
        client = FakeClient(server_url)
 
669
        client = FakeClient('bzr://example.com/')
774
670
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
775
671
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
776
672
        client.add_success_response('ok', '', 'no', 'no')
782
678
            reference_format.get_format_string(), 'ok')
783
679
        # PackRepository wants to do a stat
784
680
        client.add_success_response('stat', '0', '65535')
785
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
681
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
786
682
            _client=client)
787
683
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
788
684
            _client=client)
802
698
        # fallback to find_repositoryV2
803
699
        reference_format = self.get_repo_format()
804
700
        network_name = reference_format.network_name()
805
 
        server_url = 'bzr://example.com/'
806
 
        self.permit_url(server_url)
807
 
        client = FakeClient(server_url)
 
701
        client = FakeClient('bzr://example.com/')
808
702
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
809
703
        client.add_success_response('ok', '', 'no', 'no', 'no')
810
704
        # A real repository instance will be created to determine the network
815
709
            reference_format.get_format_string(), 'ok')
816
710
        # PackRepository wants to do a stat
817
711
        client.add_success_response('stat', '0', '65535')
818
 
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
 
712
        remote_transport = RemoteTransport('bzr://example.com/quack/', medium=False,
819
713
            _client=client)
820
714
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
821
715
            _client=client)
856
750
        transport = self.get_transport()
857
751
        client = FakeClient(transport.base)
858
752
        client.add_expected_call(
859
 
            'BzrDirFormat.initialize_ex_1.16',
 
753
            'BzrDirFormat.initialize_ex',
860
754
                (default_format_name, 'path', 'False', 'False', 'False', '',
861
755
                 '', '', '', 'False'),
862
756
            'success',
867
761
        # transport connected to a real server.
868
762
        result = fmt._initialize_on_transport_ex_rpc(client, 'path',
869
763
            transport, False, False, False, None, None, None, None, False)
870
 
        self.assertFinished(client)
 
764
        client.finished_test()
871
765
 
872
766
    def test_error(self):
873
767
        """Error responses are translated, e.g. 'PermissionDenied' raises the
878
772
        transport = self.get_transport()
879
773
        client = FakeClient(transport.base)
880
774
        client.add_expected_call(
881
 
            'BzrDirFormat.initialize_ex_1.16',
 
775
            'BzrDirFormat.initialize_ex',
882
776
                (default_format_name, 'path', 'False', 'False', 'False', '',
883
777
                 '', '', '', 'False'),
884
778
            'error',
891
785
            False, False, False, None, None, None, None, False)
892
786
        self.assertEqual('path', err.path)
893
787
        self.assertEqual(': extra info', err.extra)
894
 
        self.assertFinished(client)
 
788
        client.finished_test()
895
789
 
896
790
    def test_error_from_real_server(self):
897
791
        """Integration test for error translation."""
940
834
 
941
835
class RemoteBranchTestCase(RemoteBzrDirTestCase):
942
836
 
943
 
    def lock_remote_branch(self, branch):
944
 
        """Trick a RemoteBranch into thinking it is locked."""
945
 
        branch._lock_mode = 'w'
946
 
        branch._lock_count = 2
947
 
        branch._lock_token = 'branch token'
948
 
        branch._repo_lock_token = 'repo token'
949
 
        branch.repository._lock_mode = 'w'
950
 
        branch.repository._lock_count = 2
951
 
        branch.repository._lock_token = 'repo token'
952
 
 
953
837
    def make_remote_branch(self, transport, client):
954
838
        """Make a RemoteBranch using 'client' as its _SmartClient.
955
839
 
982
866
        transport = transport.clone('quack')
983
867
        branch = self.make_remote_branch(transport, client)
984
868
        result = branch.get_parent()
985
 
        self.assertFinished(client)
 
869
        client.finished_test()
986
870
        self.assertEqual(None, result)
987
871
 
988
872
    def test_parent_relative(self):
1014
898
        branch = self.make_remote_branch(transport, client)
1015
899
        result = branch.get_parent()
1016
900
        self.assertEqual('http://foo/', result)
1017
 
        self.assertFinished(client)
 
901
        client.finished_test()
1018
902
 
1019
903
 
1020
904
class TestBranchSetParentLocation(RemoteBranchTestCase):
1035
919
        branch._lock_token = 'b'
1036
920
        branch._repo_lock_token = 'r'
1037
921
        branch._set_parent_location(None)
1038
 
        self.assertFinished(client)
 
922
        client.finished_test()
1039
923
 
1040
924
    def test_parent(self):
1041
925
        transport = MemoryTransport()
1052
936
        branch._lock_token = 'b'
1053
937
        branch._repo_lock_token = 'r'
1054
938
        branch._set_parent_location('foo')
1055
 
        self.assertFinished(client)
 
939
        client.finished_test()
1056
940
 
1057
941
    def test_backwards_compat(self):
1058
942
        self.setup_smart_server_with_call_log()
1090
974
        transport = transport.clone('quack')
1091
975
        branch = self.make_remote_branch(transport, client)
1092
976
        result = branch.tags.get_tag_dict()
1093
 
        self.assertFinished(client)
 
977
        client.finished_test()
1094
978
        self.assertEqual({}, result)
1095
979
 
1096
980
 
1097
 
class TestBranchSetTagsBytes(RemoteBranchTestCase):
1098
 
 
1099
 
    def test_trivial(self):
1100
 
        transport = MemoryTransport()
1101
 
        client = FakeClient(transport.base)
1102
 
        client.add_expected_call(
1103
 
            'Branch.get_stacked_on_url', ('quack/',),
1104
 
            'error', ('NotStacked',))
1105
 
        client.add_expected_call(
1106
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1107
 
            'success', ('',))
1108
 
        transport.mkdir('quack')
1109
 
        transport = transport.clone('quack')
1110
 
        branch = self.make_remote_branch(transport, client)
1111
 
        self.lock_remote_branch(branch)
1112
 
        branch._set_tags_bytes('tags bytes')
1113
 
        self.assertFinished(client)
1114
 
        self.assertEqual('tags bytes', client._calls[-1][-1])
1115
 
 
1116
 
    def test_backwards_compatible(self):
1117
 
        transport = MemoryTransport()
1118
 
        client = FakeClient(transport.base)
1119
 
        client.add_expected_call(
1120
 
            'Branch.get_stacked_on_url', ('quack/',),
1121
 
            'error', ('NotStacked',))
1122
 
        client.add_expected_call(
1123
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1124
 
            'unknown', ('Branch.set_tags_bytes',))
1125
 
        transport.mkdir('quack')
1126
 
        transport = transport.clone('quack')
1127
 
        branch = self.make_remote_branch(transport, client)
1128
 
        self.lock_remote_branch(branch)
1129
 
        class StubRealBranch(object):
1130
 
            def __init__(self):
1131
 
                self.calls = []
1132
 
            def _set_tags_bytes(self, bytes):
1133
 
                self.calls.append(('set_tags_bytes', bytes))
1134
 
        real_branch = StubRealBranch()
1135
 
        branch._real_branch = real_branch
1136
 
        branch._set_tags_bytes('tags bytes')
1137
 
        # Call a second time, to exercise the 'remote version already inferred'
1138
 
        # code path.
1139
 
        branch._set_tags_bytes('tags bytes')
1140
 
        self.assertFinished(client)
1141
 
        self.assertEqual(
1142
 
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1143
 
 
1144
 
 
1145
981
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1146
982
 
1147
983
    def test_empty_branch(self):
1158
994
        transport = transport.clone('quack')
1159
995
        branch = self.make_remote_branch(transport, client)
1160
996
        result = branch.last_revision_info()
1161
 
        self.assertFinished(client)
 
997
        client.finished_test()
1162
998
        self.assertEqual((0, NULL_REVISION), result)
1163
999
 
1164
1000
    def test_non_empty_branch(self):
1219
1055
        client = FakeClient(self.get_url())
1220
1056
        branch_network_name = self.get_branch_format().network_name()
1221
1057
        client.add_expected_call(
1222
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1058
            'BzrDir.open_branchV2', ('stacked/',),
1223
1059
            'success', ('branch', branch_network_name))
1224
1060
        client.add_expected_call(
1225
1061
            'BzrDir.find_repositoryV3', ('stacked/',),
1239
1075
        branch = bzrdir.open_branch()
1240
1076
        result = branch.get_stacked_on_url()
1241
1077
        self.assertEqual('../base', result)
1242
 
        self.assertFinished(client)
 
1078
        client.finished_test()
1243
1079
        # it's in the fallback list both for the RemoteRepository and its vfs
1244
1080
        # repository
1245
1081
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1247
1083
            len(branch.repository._real_repository._fallback_repositories))
1248
1084
 
1249
1085
    def test_get_stacked_on_real_branch(self):
1250
 
        base_branch = self.make_branch('base')
1251
 
        stacked_branch = self.make_branch('stacked')
 
1086
        base_branch = self.make_branch('base', format='1.6')
 
1087
        stacked_branch = self.make_branch('stacked', format='1.6')
1252
1088
        stacked_branch.set_stacked_on_url('../base')
1253
1089
        reference_format = self.get_repo_format()
1254
1090
        network_name = reference_format.network_name()
1255
1091
        client = FakeClient(self.get_url())
1256
1092
        branch_network_name = self.get_branch_format().network_name()
1257
1093
        client.add_expected_call(
1258
 
            'BzrDir.open_branchV3', ('stacked/',),
 
1094
            'BzrDir.open_branchV2', ('stacked/',),
1259
1095
            'success', ('branch', branch_network_name))
1260
1096
        client.add_expected_call(
1261
1097
            'BzrDir.find_repositoryV3', ('stacked/',),
1262
 
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
 
1098
            'success', ('ok', '', 'no', 'no', 'yes', network_name))
1263
1099
        # called twice, once from constructor and then again by us
1264
1100
        client.add_expected_call(
1265
1101
            'Branch.get_stacked_on_url', ('stacked/',),
1272
1108
        branch = bzrdir.open_branch()
1273
1109
        result = branch.get_stacked_on_url()
1274
1110
        self.assertEqual('../base', result)
1275
 
        self.assertFinished(client)
 
1111
        client.finished_test()
1276
1112
        # it's in the fallback list both for the RemoteRepository.
1277
1113
        self.assertEqual(1, len(branch.repository._fallback_repositories))
1278
1114
        # And we haven't had to construct a real repository.
1313
1149
        result = branch.set_revision_history([])
1314
1150
        branch.unlock()
1315
1151
        self.assertEqual(None, result)
1316
 
        self.assertFinished(client)
 
1152
        client.finished_test()
1317
1153
 
1318
1154
    def test_set_nonempty(self):
1319
1155
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1351
1187
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1352
1188
        branch.unlock()
1353
1189
        self.assertEqual(None, result)
1354
 
        self.assertFinished(client)
 
1190
        client.finished_test()
1355
1191
 
1356
1192
    def test_no_such_revision(self):
1357
1193
        transport = MemoryTransport()
1386
1222
        self.assertRaises(
1387
1223
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1388
1224
        branch.unlock()
1389
 
        self.assertFinished(client)
 
1225
        client.finished_test()
1390
1226
 
1391
1227
    def test_tip_change_rejected(self):
1392
1228
        """TipChangeRejected responses cause a TipChangeRejected exception to
1429
1265
        self.assertIsInstance(err.msg, unicode)
1430
1266
        self.assertEqual(rejection_msg_unicode, err.msg)
1431
1267
        branch.unlock()
1432
 
        self.assertFinished(client)
 
1268
        client.finished_test()
1433
1269
 
1434
1270
 
1435
1271
class TestBranchSetLastRevisionInfo(RemoteBranchTestCase):
1489
1325
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
1490
1326
        branch.unlock()
1491
1327
 
 
1328
    def lock_remote_branch(self, branch):
 
1329
        """Trick a RemoteBranch into thinking it is locked."""
 
1330
        branch._lock_mode = 'w'
 
1331
        branch._lock_count = 2
 
1332
        branch._lock_token = 'branch token'
 
1333
        branch._repo_lock_token = 'repo token'
 
1334
        branch.repository._lock_mode = 'w'
 
1335
        branch.repository._lock_count = 2
 
1336
        branch.repository._lock_token = 'repo token'
 
1337
 
1492
1338
    def test_backwards_compatibility(self):
1493
1339
        """If the server does not support the Branch.set_last_revision_info
1494
1340
        verb (which is new in 1.4), then the client falls back to VFS methods.
1535
1381
        self.assertEqual(
1536
1382
            [('set_last_revision_info', 1234, 'a-revision-id')],
1537
1383
            real_branch.calls)
1538
 
        self.assertFinished(client)
 
1384
        client.finished_test()
1539
1385
 
1540
1386
    def test_unexpected_error(self):
1541
1387
        # If the server sends an error the client doesn't understand, it gets
1617
1463
    def test_get_multi_line_branch_conf(self):
1618
1464
        # Make sure that multiple-line branch.conf files are supported
1619
1465
        #
1620
 
        # https://bugs.launchpad.net/bzr/+bug/354075
 
1466
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
1621
1467
        client = FakeClient()
1622
1468
        client.add_expected_call(
1623
1469
            'Branch.get_stacked_on_url', ('memory:///',),
1649
1495
        config = branch._get_config()
1650
1496
        config.set_option('foo', 'bar')
1651
1497
        branch.unlock()
1652
 
        self.assertFinished(client)
1653
 
 
1654
 
    def test_set_option_with_dict(self):
1655
 
        client = FakeClient()
1656
 
        client.add_expected_call(
1657
 
            'Branch.get_stacked_on_url', ('memory:///',),
1658
 
            'error', ('NotStacked',),)
1659
 
        client.add_expected_call(
1660
 
            'Branch.lock_write', ('memory:///', '', ''),
1661
 
            'success', ('ok', 'branch token', 'repo token'))
1662
 
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1663
 
        client.add_expected_call(
1664
 
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
1665
 
            'repo token', encoded_dict_value, 'foo', ''),
1666
 
            'success', ())
1667
 
        client.add_expected_call(
1668
 
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1669
 
            'success', ('ok',))
1670
 
        transport = MemoryTransport()
1671
 
        branch = self.make_remote_branch(transport, client)
1672
 
        branch.lock_write()
1673
 
        config = branch._get_config()
1674
 
        config.set_option(
1675
 
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1676
 
            'foo')
1677
 
        branch.unlock()
1678
 
        self.assertFinished(client)
 
1498
        client.finished_test()
1679
1499
 
1680
1500
    def test_backwards_compat_set_option(self):
1681
1501
        self.setup_smart_server_with_call_log()
1689
1509
        self.assertLength(10, self.hpss_calls)
1690
1510
        self.assertEqual('value', branch._get_config().get_option('name'))
1691
1511
 
1692
 
    def test_backwards_compat_set_option_with_dict(self):
1693
 
        self.setup_smart_server_with_call_log()
1694
 
        branch = self.make_branch('.')
1695
 
        verb = 'Branch.set_config_option_dict'
1696
 
        self.disable_verb(verb)
1697
 
        branch.lock_write()
1698
 
        self.addCleanup(branch.unlock)
1699
 
        self.reset_smart_call_log()
1700
 
        config = branch._get_config()
1701
 
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1702
 
        config.set_option(value_dict, 'name')
1703
 
        self.assertLength(10, self.hpss_calls)
1704
 
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
1705
 
 
1706
1512
 
1707
1513
class TestBranchLockWrite(RemoteBranchTestCase):
1708
1514
 
1719
1525
        transport = transport.clone('quack')
1720
1526
        branch = self.make_remote_branch(transport, client)
1721
1527
        self.assertRaises(errors.UnlockableTransport, branch.lock_write)
1722
 
        self.assertFinished(client)
 
1528
        client.finished_test()
1723
1529
 
1724
1530
 
1725
1531
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1850
1656
        return repo, client
1851
1657
 
1852
1658
 
1853
 
def remoted_description(format):
1854
 
    return 'Remote: ' + format.get_format_description()
1855
 
 
1856
 
 
1857
 
class TestBranchFormat(tests.TestCase):
1858
 
 
1859
 
    def test_get_format_description(self):
1860
 
        remote_format = RemoteBranchFormat()
1861
 
        real_format = branch.BranchFormat.get_default_format()
1862
 
        remote_format._network_name = real_format.network_name()
1863
 
        self.assertEqual(remoted_description(real_format),
1864
 
            remote_format.get_format_description())
1865
 
 
1866
 
 
1867
1659
class TestRepositoryFormat(TestRemoteRepository):
1868
1660
 
1869
1661
    def test_fast_delta(self):
1876
1668
        false_format._network_name = false_name
1877
1669
        self.assertEqual(False, false_format.fast_deltas)
1878
1670
 
1879
 
    def test_get_format_description(self):
1880
 
        remote_repo_format = RemoteRepositoryFormat()
1881
 
        real_format = repository.RepositoryFormat.get_default_format()
1882
 
        remote_repo_format._network_name = real_format.network_name()
1883
 
        self.assertEqual(remoted_description(real_format),
1884
 
            remote_repo_format.get_format_description())
1885
 
 
1886
1671
 
1887
1672
class TestRepositoryGatherStats(TestRemoteRepository):
1888
1673
 
2073
1858
        self.assertLength(1, self.hpss_calls)
2074
1859
 
2075
1860
    def disableExtraResults(self):
2076
 
        self.overrideAttr(SmartServerRepositoryGetParentMap,
2077
 
                          'no_extra_results', True)
 
1861
        old_flag = SmartServerRepositoryGetParentMap.no_extra_results
 
1862
        SmartServerRepositoryGetParentMap.no_extra_results = True
 
1863
        def reset_values():
 
1864
            SmartServerRepositoryGetParentMap.no_extra_results = old_flag
 
1865
        self.addCleanup(reset_values)
2078
1866
 
2079
1867
    def test_null_cached_missing_and_stop_key(self):
2080
1868
        self.setup_smart_server_with_call_log()
2139
1927
 
2140
1928
    def test_allows_new_revisions(self):
2141
1929
        """get_parent_map's results can be updated by commit."""
2142
 
        smart_server = test_server.SmartTCPServer_for_testing()
2143
 
        self.start_server(smart_server)
 
1930
        smart_server = server.SmartTCPServer_for_testing()
 
1931
        smart_server.setUp()
 
1932
        self.addCleanup(smart_server.tearDown)
2144
1933
        self.make_branch('branch')
2145
1934
        branch = Branch.open(smart_server.get_url() + '/branch')
2146
1935
        tree = branch.create_checkout('tree', lightweight=True)
2229
2018
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
2230
2019
 
2231
2020
 
2232
 
class TestRepositoryGetRevIdForRevno(TestRemoteRepository):
2233
 
 
2234
 
    def test_ok(self):
2235
 
        repo, client = self.setup_fake_client_and_repository('quack')
2236
 
        client.add_expected_call(
2237
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2238
 
            'success', ('ok', 'rev-five'))
2239
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2240
 
        self.assertEqual((True, 'rev-five'), result)
2241
 
        self.assertFinished(client)
2242
 
 
2243
 
    def test_history_incomplete(self):
2244
 
        repo, client = self.setup_fake_client_and_repository('quack')
2245
 
        client.add_expected_call(
2246
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2247
 
            'success', ('history-incomplete', 10, 'rev-ten'))
2248
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2249
 
        self.assertEqual((False, (10, 'rev-ten')), result)
2250
 
        self.assertFinished(client)
2251
 
 
2252
 
    def test_history_incomplete_with_fallback(self):
2253
 
        """A 'history-incomplete' response causes the fallback repository to be
2254
 
        queried too, if one is set.
2255
 
        """
2256
 
        # Make a repo with a fallback repo, both using a FakeClient.
2257
 
        format = remote.response_tuple_to_repo_format(
2258
 
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
2259
 
        repo, client = self.setup_fake_client_and_repository('quack')
2260
 
        repo._format = format
2261
 
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2262
 
            'fallback')
2263
 
        fallback_repo._client = client
2264
 
        fallback_repo._format = format
2265
 
        repo.add_fallback_repository(fallback_repo)
2266
 
        # First the client should ask the primary repo
2267
 
        client.add_expected_call(
2268
 
            'Repository.get_rev_id_for_revno', ('quack/', 1, (42, 'rev-foo')),
2269
 
            'success', ('history-incomplete', 2, 'rev-two'))
2270
 
        # Then it should ask the fallback, using revno/revid from the
2271
 
        # history-incomplete response as the known revno/revid.
2272
 
        client.add_expected_call(
2273
 
            'Repository.get_rev_id_for_revno',('fallback/', 1, (2, 'rev-two')),
2274
 
            'success', ('ok', 'rev-one'))
2275
 
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2276
 
        self.assertEqual((True, 'rev-one'), result)
2277
 
        self.assertFinished(client)
2278
 
 
2279
 
    def test_nosuchrevision(self):
2280
 
        # 'nosuchrevision' is returned when the known-revid is not found in the
2281
 
        # remote repo.  The client translates that response to NoSuchRevision.
2282
 
        repo, client = self.setup_fake_client_and_repository('quack')
2283
 
        client.add_expected_call(
2284
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2285
 
            'error', ('nosuchrevision', 'rev-foo'))
2286
 
        self.assertRaises(
2287
 
            errors.NoSuchRevision,
2288
 
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
2289
 
        self.assertFinished(client)
2290
 
 
2291
 
    def test_branch_fallback_locking(self):
2292
 
        """RemoteBranch.get_rev_id takes a read lock, and tries to call the
2293
 
        get_rev_id_for_revno verb.  If the verb is unknown the VFS fallback
2294
 
        will be invoked, which will fail if the repo is unlocked.
2295
 
        """
2296
 
        self.setup_smart_server_with_call_log()
2297
 
        tree = self.make_branch_and_memory_tree('.')
2298
 
        tree.lock_write()
2299
 
        tree.add('')
2300
 
        rev1 = tree.commit('First')
2301
 
        rev2 = tree.commit('Second')
2302
 
        tree.unlock()
2303
 
        branch = tree.branch
2304
 
        self.assertFalse(branch.is_locked())
2305
 
        self.reset_smart_call_log()
2306
 
        verb = 'Repository.get_rev_id_for_revno'
2307
 
        self.disable_verb(verb)
2308
 
        self.assertEqual(rev1, branch.get_rev_id(1))
2309
 
        self.assertLength(1, [call for call in self.hpss_calls if
2310
 
                              call.call.method == verb])
2311
 
 
2312
 
 
2313
2021
class TestRepositoryIsShared(TestRemoteRepository):
2314
2022
 
2315
2023
    def test_is_shared(self):
2341
2049
        transport_path = 'quack'
2342
2050
        repo, client = self.setup_fake_client_and_repository(transport_path)
2343
2051
        client.add_success_response('ok', 'a token')
2344
 
        token = repo.lock_write().repository_token
 
2052
        result = repo.lock_write()
2345
2053
        self.assertEqual(
2346
2054
            [('call', 'Repository.lock_write', ('quack/', ''))],
2347
2055
            client._calls)
2348
 
        self.assertEqual('a token', token)
 
2056
        self.assertEqual('a token', result)
2349
2057
 
2350
2058
    def test_lock_write_already_locked(self):
2351
2059
        transport_path = 'quack'
2430
2138
        self.assertEqual([], client._calls)
2431
2139
 
2432
2140
 
2433
 
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2434
 
    """Base class for Repository.insert_stream and .insert_stream_1.19
2435
 
    tests.
2436
 
    """
2437
 
    
2438
 
    def checkInsertEmptyStream(self, repo, client):
2439
 
        """Insert an empty stream, checking the result.
2440
 
 
2441
 
        This checks that there are no resume_tokens or missing_keys, and that
2442
 
        the client is finished.
2443
 
        """
2444
 
        sink = repo._get_sink()
2445
 
        fmt = repository.RepositoryFormat.get_default_format()
2446
 
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2447
 
        self.assertEqual([], resume_tokens)
2448
 
        self.assertEqual(set(), missing_keys)
2449
 
        self.assertFinished(client)
2450
 
 
2451
 
 
2452
 
class TestRepositoryInsertStream(TestRepositoryInsertStreamBase):
2453
 
    """Tests for using Repository.insert_stream verb when the _1.19 variant is
2454
 
    not available.
2455
 
 
2456
 
    This test case is very similar to TestRepositoryInsertStream_1_19.
2457
 
    """
2458
 
 
2459
 
    def setUp(self):
2460
 
        TestRemoteRepository.setUp(self)
2461
 
        self.disable_verb('Repository.insert_stream_1.19')
2462
 
 
2463
 
    def test_unlocked_repo(self):
2464
 
        transport_path = 'quack'
2465
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2466
 
        client.add_expected_call(
2467
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2468
 
            'unknown', ('Repository.insert_stream_1.19',))
2469
 
        client.add_expected_call(
2470
 
            'Repository.insert_stream', ('quack/', ''),
2471
 
            'success', ('ok',))
2472
 
        client.add_expected_call(
2473
 
            'Repository.insert_stream', ('quack/', ''),
2474
 
            'success', ('ok',))
2475
 
        self.checkInsertEmptyStream(repo, client)
2476
 
 
2477
 
    def test_locked_repo_with_no_lock_token(self):
2478
 
        transport_path = 'quack'
2479
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2480
 
        client.add_expected_call(
2481
 
            'Repository.lock_write', ('quack/', ''),
2482
 
            'success', ('ok', ''))
2483
 
        client.add_expected_call(
2484
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2485
 
            'unknown', ('Repository.insert_stream_1.19',))
2486
 
        client.add_expected_call(
2487
 
            'Repository.insert_stream', ('quack/', ''),
2488
 
            'success', ('ok',))
2489
 
        client.add_expected_call(
2490
 
            'Repository.insert_stream', ('quack/', ''),
2491
 
            'success', ('ok',))
2492
 
        repo.lock_write()
2493
 
        self.checkInsertEmptyStream(repo, client)
2494
 
 
2495
 
    def test_locked_repo_with_lock_token(self):
2496
 
        transport_path = 'quack'
2497
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2498
 
        client.add_expected_call(
2499
 
            'Repository.lock_write', ('quack/', ''),
2500
 
            'success', ('ok', 'a token'))
2501
 
        client.add_expected_call(
2502
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2503
 
            'unknown', ('Repository.insert_stream_1.19',))
2504
 
        client.add_expected_call(
2505
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2506
 
            'success', ('ok',))
2507
 
        client.add_expected_call(
2508
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2509
 
            'success', ('ok',))
2510
 
        repo.lock_write()
2511
 
        self.checkInsertEmptyStream(repo, client)
2512
 
 
2513
 
    def test_stream_with_inventory_deltas(self):
2514
 
        """'inventory-deltas' substreams cannot be sent to the
2515
 
        Repository.insert_stream verb, because not all servers that implement
2516
 
        that verb will accept them.  So when one is encountered the RemoteSink
2517
 
        immediately stops using that verb and falls back to VFS insert_stream.
2518
 
        """
2519
 
        transport_path = 'quack'
2520
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2521
 
        client.add_expected_call(
2522
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2523
 
            'unknown', ('Repository.insert_stream_1.19',))
2524
 
        client.add_expected_call(
2525
 
            'Repository.insert_stream', ('quack/', ''),
2526
 
            'success', ('ok',))
2527
 
        client.add_expected_call(
2528
 
            'Repository.insert_stream', ('quack/', ''),
2529
 
            'success', ('ok',))
2530
 
        # Create a fake real repository for insert_stream to fall back on, so
2531
 
        # that we can directly see the records the RemoteSink passes to the
2532
 
        # real sink.
2533
 
        class FakeRealSink:
2534
 
            def __init__(self):
2535
 
                self.records = []
2536
 
            def insert_stream(self, stream, src_format, resume_tokens):
2537
 
                for substream_kind, substream in stream:
2538
 
                    self.records.append(
2539
 
                        (substream_kind, [record.key for record in substream]))
2540
 
                return ['fake tokens'], ['fake missing keys']
2541
 
        fake_real_sink = FakeRealSink()
2542
 
        class FakeRealRepository:
2543
 
            def _get_sink(self):
2544
 
                return fake_real_sink
2545
 
            def is_in_write_group(self):
2546
 
                return False
2547
 
            def refresh_data(self):
2548
 
                return True
2549
 
        repo._real_repository = FakeRealRepository()
2550
 
        sink = repo._get_sink()
2551
 
        fmt = repository.RepositoryFormat.get_default_format()
2552
 
        stream = self.make_stream_with_inv_deltas(fmt)
2553
 
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2554
 
        # Every record from the first inventory delta should have been sent to
2555
 
        # the VFS sink.
2556
 
        expected_records = [
2557
 
            ('inventory-deltas', [('rev2',), ('rev3',)]),
2558
 
            ('texts', [('some-rev', 'some-file')])]
2559
 
        self.assertEqual(expected_records, fake_real_sink.records)
2560
 
        # The return values from the real sink's insert_stream are propagated
2561
 
        # back to the original caller.
2562
 
        self.assertEqual(['fake tokens'], resume_tokens)
2563
 
        self.assertEqual(['fake missing keys'], missing_keys)
2564
 
        self.assertFinished(client)
2565
 
 
2566
 
    def make_stream_with_inv_deltas(self, fmt):
2567
 
        """Make a simple stream with an inventory delta followed by more
2568
 
        records and more substreams to test that all records and substreams
2569
 
        from that point on are used.
2570
 
 
2571
 
        This sends, in order:
2572
 
           * inventories substream: rev1, rev2, rev3.  rev2 and rev3 are
2573
 
             inventory-deltas.
2574
 
           * texts substream: (some-rev, some-file)
2575
 
        """
2576
 
        # Define a stream using generators so that it isn't rewindable.
2577
 
        inv = inventory.Inventory(revision_id='rev1')
2578
 
        inv.root.revision = 'rev1'
2579
 
        def stream_with_inv_delta():
2580
 
            yield ('inventories', inventories_substream())
2581
 
            yield ('inventory-deltas', inventory_delta_substream())
2582
 
            yield ('texts', [
2583
 
                versionedfile.FulltextContentFactory(
2584
 
                    ('some-rev', 'some-file'), (), None, 'content')])
2585
 
        def inventories_substream():
2586
 
            # An empty inventory fulltext.  This will be streamed normally.
2587
 
            text = fmt._serializer.write_inventory_to_string(inv)
2588
 
            yield versionedfile.FulltextContentFactory(
2589
 
                ('rev1',), (), None, text)
2590
 
        def inventory_delta_substream():
2591
 
            # An inventory delta.  This can't be streamed via this verb, so it
2592
 
            # will trigger a fallback to VFS insert_stream.
2593
 
            entry = inv.make_entry(
2594
 
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
2595
 
            entry.revision = 'ghost'
2596
 
            delta = [(None, 'newdir', 'newdir-id', entry)]
2597
 
            serializer = inventory_delta.InventoryDeltaSerializer(
2598
 
                versioned_root=True, tree_references=False)
2599
 
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
2600
 
            yield versionedfile.ChunkedContentFactory(
2601
 
                ('rev2',), (('rev1',)), None, lines)
2602
 
            # Another delta.
2603
 
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
2604
 
            yield versionedfile.ChunkedContentFactory(
2605
 
                ('rev3',), (('rev1',)), None, lines)
2606
 
        return stream_with_inv_delta()
2607
 
 
2608
 
 
2609
 
class TestRepositoryInsertStream_1_19(TestRepositoryInsertStreamBase):
2610
 
 
2611
 
    def test_unlocked_repo(self):
2612
 
        transport_path = 'quack'
2613
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2614
 
        client.add_expected_call(
2615
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2616
 
            'success', ('ok',))
2617
 
        client.add_expected_call(
2618
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2619
 
            'success', ('ok',))
2620
 
        self.checkInsertEmptyStream(repo, client)
2621
 
 
2622
 
    def test_locked_repo_with_no_lock_token(self):
2623
 
        transport_path = 'quack'
2624
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2625
 
        client.add_expected_call(
2626
 
            'Repository.lock_write', ('quack/', ''),
2627
 
            'success', ('ok', ''))
2628
 
        client.add_expected_call(
2629
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2630
 
            'success', ('ok',))
2631
 
        client.add_expected_call(
2632
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2633
 
            'success', ('ok',))
2634
 
        repo.lock_write()
2635
 
        self.checkInsertEmptyStream(repo, client)
2636
 
 
2637
 
    def test_locked_repo_with_lock_token(self):
2638
 
        transport_path = 'quack'
2639
 
        repo, client = self.setup_fake_client_and_repository(transport_path)
2640
 
        client.add_expected_call(
2641
 
            'Repository.lock_write', ('quack/', ''),
2642
 
            'success', ('ok', 'a token'))
2643
 
        client.add_expected_call(
2644
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2645
 
            'success', ('ok',))
2646
 
        client.add_expected_call(
2647
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2648
 
            'success', ('ok',))
2649
 
        repo.lock_write()
2650
 
        self.checkInsertEmptyStream(repo, client)
 
2141
class TestRepositoryInsertStream(TestRemoteRepository):
 
2142
 
 
2143
    def test_unlocked_repo(self):
 
2144
        transport_path = 'quack'
 
2145
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2146
        client.add_expected_call(
 
2147
            'Repository.insert_stream', ('quack/', ''),
 
2148
            'success', ('ok',))
 
2149
        client.add_expected_call(
 
2150
            'Repository.insert_stream', ('quack/', ''),
 
2151
            'success', ('ok',))
 
2152
        sink = repo._get_sink()
 
2153
        fmt = repository.RepositoryFormat.get_default_format()
 
2154
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2155
        self.assertEqual([], resume_tokens)
 
2156
        self.assertEqual(set(), missing_keys)
 
2157
        client.finished_test()
 
2158
 
 
2159
    def test_locked_repo_with_no_lock_token(self):
 
2160
        transport_path = 'quack'
 
2161
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2162
        client.add_expected_call(
 
2163
            'Repository.lock_write', ('quack/', ''),
 
2164
            'success', ('ok', ''))
 
2165
        client.add_expected_call(
 
2166
            'Repository.insert_stream', ('quack/', ''),
 
2167
            'success', ('ok',))
 
2168
        client.add_expected_call(
 
2169
            'Repository.insert_stream', ('quack/', ''),
 
2170
            'success', ('ok',))
 
2171
        repo.lock_write()
 
2172
        sink = repo._get_sink()
 
2173
        fmt = repository.RepositoryFormat.get_default_format()
 
2174
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2175
        self.assertEqual([], resume_tokens)
 
2176
        self.assertEqual(set(), missing_keys)
 
2177
        client.finished_test()
 
2178
 
 
2179
    def test_locked_repo_with_lock_token(self):
 
2180
        transport_path = 'quack'
 
2181
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2182
        client.add_expected_call(
 
2183
            'Repository.lock_write', ('quack/', ''),
 
2184
            'success', ('ok', 'a token'))
 
2185
        client.add_expected_call(
 
2186
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2187
            'success', ('ok',))
 
2188
        client.add_expected_call(
 
2189
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
 
2190
            'success', ('ok',))
 
2191
        repo.lock_write()
 
2192
        sink = repo._get_sink()
 
2193
        fmt = repository.RepositoryFormat.get_default_format()
 
2194
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
 
2195
        self.assertEqual([], resume_tokens)
 
2196
        self.assertEqual(set(), missing_keys)
 
2197
        client.finished_test()
2651
2198
 
2652
2199
 
2653
2200
class TestRepositoryTarball(TestRemoteRepository):
2689
2236
    """RemoteRepository.copy_content_into optimizations"""
2690
2237
 
2691
2238
    def test_copy_content_remote_to_local(self):
2692
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2239
        self.transport_server = server.SmartTCPServer_for_testing
2693
2240
        src_repo = self.make_repository('repo1')
2694
2241
        src_repo = repository.Repository.open(self.get_url('repo1'))
2695
2242
        # At the moment the tarball-based copy_content_into can't write back
2738
2285
        client.add_expected_call(
2739
2286
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
2740
2287
        repo.autopack()
2741
 
        self.assertFinished(client)
 
2288
        client.finished_test()
2742
2289
 
2743
2290
    def test_ok_with_real_repo(self):
2744
2291
        """When the server returns 'ok' and there is a _real_repository, then
2843
2390
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2844
2391
        self.assertEqual(expected_error, translated_error)
2845
2392
 
2846
 
    def test_nobranch_one_arg(self):
2847
 
        bzrdir = self.make_bzrdir('')
2848
 
        translated_error = self.translateTuple(
2849
 
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
2850
 
        expected_error = errors.NotBranchError(
2851
 
            path=bzrdir.root_transport.base,
2852
 
            detail='extra detail')
2853
 
        self.assertEqual(expected_error, translated_error)
2854
 
 
2855
2393
    def test_LockContention(self):
2856
2394
        translated_error = self.translateTuple(('LockContention',))
2857
2395
        expected_error = errors.LockContention('(remote lock)')
2897
2435
        expected_error = errors.ReadError(path)
2898
2436
        self.assertEqual(expected_error, translated_error)
2899
2437
 
2900
 
    def test_IncompatibleRepositories(self):
2901
 
        translated_error = self.translateTuple(('IncompatibleRepositories',
2902
 
            "repo1", "repo2", "details here"))
2903
 
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2904
 
            "details here")
2905
 
        self.assertEqual(expected_error, translated_error)
2906
 
 
2907
2438
    def test_PermissionDenied_no_args(self):
2908
2439
        path = 'a path'
2909
2440
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
2970
2501
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2971
2502
        # been muttered to the log file for developer to look at.
2972
2503
        self.assertContainsRe(
2973
 
            self.get_log(),
 
2504
            self._get_log(keep_log_file=True),
2974
2505
            "Missing key 'branch' in context")
2975
2506
 
2976
2507
    def test_path_missing(self):
2984
2515
        self.assertEqual(server_error, translated_error)
2985
2516
        # In addition to re-raising ErrorFromSmartServer, some debug info has
2986
2517
        # been muttered to the log file for developer to look at.
2987
 
        self.assertContainsRe(self.get_log(), "Missing key 'path' in context")
 
2518
        self.assertContainsRe(
 
2519
            self._get_log(keep_log_file=True), "Missing key 'path' in context")
2988
2520
 
2989
2521
 
2990
2522
class TestStacking(tests.TestCaseWithTransport):
3008
2540
        stacked_branch = self.make_branch('stacked', format='1.9')
3009
2541
        stacked_branch.set_stacked_on_url('../base')
3010
2542
        # start a server looking at this
3011
 
        smart_server = test_server.SmartTCPServer_for_testing()
3012
 
        self.start_server(smart_server)
 
2543
        smart_server = server.SmartTCPServer_for_testing()
 
2544
        smart_server.setUp()
 
2545
        self.addCleanup(smart_server.tearDown)
3013
2546
        remote_bzrdir = BzrDir.open(smart_server.get_url() + '/stacked')
3014
2547
        # can get its branch and repository
3015
2548
        remote_branch = remote_bzrdir.open_branch()
3037
2570
        tree1.commit('rev1', rev_id='rev1')
3038
2571
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
3039
2572
            ).open_workingtree()
3040
 
        local_tree = tree2.branch.create_checkout('local')
3041
 
        local_tree.commit('local changes make me feel good.')
 
2573
        tree2.commit('local changes make me feel good.')
3042
2574
        branch2 = Branch.open(self.get_url('tree2'))
3043
2575
        branch2.lock_read()
3044
2576
        self.addCleanup(branch2.unlock)
3066
2598
                    result.append(content.key[-1])
3067
2599
        return result
3068
2600
 
3069
 
    def get_ordered_revs(self, format, order, branch_factory=None):
 
2601
    def get_ordered_revs(self, format, order):
3070
2602
        """Get a list of the revisions in a stream to format format.
3071
2603
 
3072
2604
        :param format: The format of the target.
3073
2605
        :param order: the order that target should have requested.
3074
 
        :param branch_factory: A callable to create a trunk and stacked branch
3075
 
            to fetch from. If none, self.prepare_stacked_remote_branch is used.
3076
2606
        :result: The revision ids in the stream, in the order seen,
3077
2607
            the topological order of revisions in the source.
3078
2608
        """
3080
2610
        target_repository_format = unordered_format.repository_format
3081
2611
        # Cross check
3082
2612
        self.assertEqual(order, target_repository_format._fetch_order)
3083
 
        if branch_factory is None:
3084
 
            branch_factory = self.prepare_stacked_remote_branch
3085
 
        _, stacked = branch_factory()
 
2613
        trunk, stacked = self.prepare_stacked_remote_branch()
3086
2614
        source = stacked.repository._get_source(target_repository_format)
3087
2615
        tip = stacked.last_revision()
3088
2616
        revs = stacked.repository.get_ancestry(tip)
3107
2635
        # from the server, then one from the backing branch.
3108
2636
        self.assertLength(2, self.hpss_calls)
3109
2637
 
3110
 
    def test_stacked_on_stacked_get_stream_unordered(self):
3111
 
        # Repository._get_source.get_stream() from a stacked repository which
3112
 
        # is itself stacked yields the full data from all three sources.
3113
 
        def make_stacked_stacked():
3114
 
            _, stacked = self.prepare_stacked_remote_branch()
3115
 
            tree = stacked.bzrdir.sprout('tree3', stacked=True
3116
 
                ).open_workingtree()
3117
 
            local_tree = tree.branch.create_checkout('local-tree3')
3118
 
            local_tree.commit('more local changes are better')
3119
 
            branch = Branch.open(self.get_url('tree3'))
3120
 
            branch.lock_read()
3121
 
            self.addCleanup(branch.unlock)
3122
 
            return None, branch
3123
 
        rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
3124
 
            branch_factory=make_stacked_stacked)
3125
 
        self.assertEqual(set(expected_revs), set(rev_ord))
3126
 
        # Getting unordered results should have made a streaming data request
3127
 
        # from the server, and one from each backing repo
3128
 
        self.assertLength(3, self.hpss_calls)
3129
 
 
3130
2638
    def test_stacked_get_stream_topological(self):
3131
2639
        # Repository._get_source.get_stream() from a stacked repository with
3132
2640
        # topological sorting yields the full data from both stacked and
3133
2641
        # stacked upon sources in topological order.
3134
2642
        rev_ord, expected_revs = self.get_ordered_revs('knit', 'topological')
3135
2643
        self.assertEqual(expected_revs, rev_ord)
3136
 
        # Getting topological sort requires VFS calls still - one of which is
3137
 
        # pushing up from the bound branch.
3138
 
        self.assertLength(13, self.hpss_calls)
 
2644
        # Getting topological sort requires VFS calls still
 
2645
        self.assertLength(12, self.hpss_calls)
3139
2646
 
3140
2647
    def test_stacked_get_stream_groupcompress(self):
3141
2648
        # Repository._get_source.get_stream() from a stacked repository with
3170
2677
        super(TestRemoteBranchEffort, self).setUp()
3171
2678
        # Create a smart server that publishes whatever the backing VFS server
3172
2679
        # does.
3173
 
        self.smart_server = test_server.SmartTCPServer_for_testing()
3174
 
        self.start_server(self.smart_server, self.get_server())
 
2680
        self.smart_server = server.SmartTCPServer_for_testing()
 
2681
        self.smart_server.setUp(self.get_server())
 
2682
        self.addCleanup(self.smart_server.tearDown)
3175
2683
        # Log all HPSS calls into self.hpss_calls.
3176
2684
        _SmartClient.hooks.install_named_hook(
3177
2685
            'call', self.capture_hpss_call, None)