/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: Vincent Ladeuil
  • Date: 2011-11-24 15:48:29 UTC
  • mfrom: (6289 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6337.
  • Revision ID: v.ladeuil+lp@free.fr-20111124154829-avowjpsxdl8yp2vz
merge trunk resolving conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 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
30
30
    branch,
31
31
    bzrdir,
32
32
    config,
 
33
    controldir,
33
34
    errors,
34
 
    graph,
 
35
    graph as _mod_graph,
35
36
    inventory,
36
37
    inventory_delta,
37
 
    pack,
38
38
    remote,
39
39
    repository,
40
40
    tests,
 
41
    transport,
41
42
    treebuilder,
42
 
    urlutils,
43
43
    versionedfile,
44
44
    )
45
45
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
46
from bzrlib.bzrdir import (
 
47
    BzrDir,
 
48
    BzrDirFormat,
 
49
    RemoteBzrProber,
 
50
    )
47
51
from bzrlib.remote import (
48
52
    RemoteBranch,
49
53
    RemoteBranchFormat,
52
56
    RemoteRepository,
53
57
    RemoteRepositoryFormat,
54
58
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
 
59
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
56
60
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import medium
 
61
from bzrlib.smart import medium, request
58
62
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
63
from bzrlib.smart.repository import (
 
64
    SmartServerRepositoryGetParentMap,
 
65
    SmartServerRepositoryGetStream_1_19,
 
66
    )
 
67
from bzrlib.symbol_versioning import deprecated_in
60
68
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
69
    test_server,
65
70
    )
66
 
from bzrlib.transport import get_transport
 
71
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
72
from bzrlib.transport.memory import MemoryTransport
68
73
from bzrlib.transport.remote import (
69
74
    RemoteTransport,
70
75
    RemoteSSHTransport,
71
76
    RemoteTCPTransport,
72
 
)
73
 
 
74
 
def load_tests(standard_tests, module, loader):
75
 
    to_adapt, result = split_suite_by_condition(
76
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
 
    smart_server_version_scenarios = [
 
77
    )
 
78
 
 
79
 
 
80
load_tests = load_tests_apply_scenarios
 
81
 
 
82
 
 
83
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
84
 
 
85
    scenarios = [
78
86
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
87
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
88
        ('HPSS-v3',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
82
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
83
 
 
84
 
 
85
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
89
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
90
 
86
91
 
87
92
    def setUp(self):
88
93
        super(BasicRemoteObjectTests, self).setUp()
89
94
        self.transport = self.get_transport()
90
95
        # make a branch that can be opened over the smart transport
91
96
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
97
        self.addCleanup(self.transport.disconnect)
96
98
 
97
99
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
100
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
101
        self.assertIsInstance(b, BzrDir)
100
102
 
101
103
    def test_open_remote_branch(self):
102
104
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
105
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
106
        branch = b.open_branch()
105
107
        self.assertIsInstance(branch, Branch)
106
108
 
114
116
 
115
117
    def test_remote_branch_revision_history(self):
116
118
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
 
119
        self.assertEqual([],
 
120
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
121
        r1 = self.local_wt.commit('1st commit')
119
122
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
 
123
        self.assertEqual([r1, r2],
 
124
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
121
125
 
122
126
    def test_find_correct_format(self):
123
127
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
128
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
129
        self.assertTrue(bzrdir.RemoteBzrProber
 
130
                        in controldir.ControlDirFormat._server_probers)
 
131
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
132
 
129
133
    def test_open_detected_smart_format(self):
130
134
        fmt = BzrDirFormat.find_format(self.transport)
359
363
        a given client_base and transport_base.
360
364
        """
361
365
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
366
        t = transport.get_transport(transport_base)
 
367
        result = client_medium.remote_path_from_transport(t)
364
368
        self.assertEqual(expected, result)
365
369
 
366
370
    def test_remote_path_from_transport(self):
377
381
        a given transport_base and relpath of that transport.  (Note that
378
382
        HttpTransportBase is a subclass of SmartClientMedium)
379
383
        """
380
 
        base_transport = get_transport(transport_base)
 
384
        base_transport = transport.get_transport(transport_base)
381
385
        client_medium = base_transport.get_smart_medium()
382
386
        cloned_transport = base_transport.clone(relpath)
383
387
        result = client_medium.remote_path_from_transport(cloned_transport)
450
454
        client.add_expected_call(
451
455
            'BzrDir.open_branchV3', ('quack/',),
452
456
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
457
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
458
            _client=client)
455
459
        result = a_bzrdir.cloning_metadir()
456
460
        # We should have got a control dir matching the referenced branch.
469
473
        client.add_expected_call(
470
474
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
475
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
476
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
477
            _client=client)
474
478
        result = a_bzrdir.cloning_metadir()
475
479
        # We should have got a reference control dir with default branch and
481
485
        self.assertFinished(client)
482
486
 
483
487
 
 
488
class TestBzrDirHasWorkingTree(TestRemote):
 
489
 
 
490
    def test_has_workingtree(self):
 
491
        transport = self.get_transport('quack')
 
492
        client = FakeClient(transport.base)
 
493
        client.add_expected_call(
 
494
            'BzrDir.has_workingtree', ('quack/',),
 
495
            'success', ('yes',)),
 
496
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
497
            _client=client)
 
498
        self.assertTrue(a_bzrdir.has_workingtree())
 
499
        self.assertFinished(client)
 
500
 
 
501
    def test_no_workingtree(self):
 
502
        transport = self.get_transport('quack')
 
503
        client = FakeClient(transport.base)
 
504
        client.add_expected_call(
 
505
            'BzrDir.has_workingtree', ('quack/',),
 
506
            'success', ('no',)),
 
507
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
508
            _client=client)
 
509
        self.assertFalse(a_bzrdir.has_workingtree())
 
510
        self.assertFinished(client)
 
511
 
 
512
 
 
513
class TestBzrDirDestroyRepository(TestRemote):
 
514
 
 
515
    def test_destroy_repository(self):
 
516
        transport = self.get_transport('quack')
 
517
        client = FakeClient(transport.base)
 
518
        client.add_expected_call(
 
519
            'BzrDir.destroy_repository', ('quack/',),
 
520
            'success', ('ok',)),
 
521
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
522
            _client=client)
 
523
        a_bzrdir.destroy_repository()
 
524
        self.assertFinished(client)
 
525
 
 
526
 
484
527
class TestBzrDirOpen(TestRemote):
485
528
 
486
529
    def make_fake_client_and_transport(self, path='quack'):
495
538
        client.add_expected_call(
496
539
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
540
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
541
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
542
        self.assertFinished(client)
500
543
 
501
544
    def test_present_without_workingtree(self):
502
545
        client, transport = self.make_fake_client_and_transport()
503
546
        client.add_expected_call(
504
547
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
548
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
549
            _client=client, _force_probe=True)
507
550
        self.assertIsInstance(bd, RemoteBzrDir)
508
551
        self.assertFalse(bd.has_workingtree())
513
556
        client, transport = self.make_fake_client_and_transport()
514
557
        client.add_expected_call(
515
558
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
559
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
560
            _client=client, _force_probe=True)
518
561
        self.assertIsInstance(bd, RemoteBzrDir)
519
562
        self.assertTrue(bd.has_workingtree())
526
569
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
570
        client.add_expected_call(
528
571
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
572
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
573
            _client=client, _force_probe=True)
531
574
        self.assertIsInstance(bd, RemoteBzrDir)
532
575
        self.assertFinished(client)
548
591
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
592
        client.add_expected_call(
550
593
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
594
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
595
            _client=client, _force_probe=True)
553
596
        self.assertIsInstance(bd, RemoteBzrDir)
554
597
        self.assertFinished(client)
585
628
        client.add_expected_call(
586
629
            'Branch.get_stacked_on_url', ('quack/',),
587
630
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
631
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
632
            _client=client)
590
633
        result = bzrdir.open_branch()
591
634
        self.assertIsInstance(result, RemoteBranch)
598
641
        transport = transport.clone('quack')
599
642
        client = FakeClient(transport.base)
600
643
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
644
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
645
            _client=client)
603
646
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
647
        self.assertEqual(
609
652
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
653
        # branch opening, not any other network requests.
611
654
        calls = []
612
 
        def open_branch():
 
655
        def open_branch(name=None):
613
656
            calls.append("Called")
614
657
            return "a-branch"
615
658
        transport = MemoryTransport()
616
659
        # no requests on the network - catches other api calls being made.
617
660
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
661
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
662
            _client=client)
620
663
        # patch the open_branch call to record that it was called.
621
664
        bzrdir.open_branch = open_branch
640
683
        client.add_expected_call(
641
684
            'Branch.get_stacked_on_url', ('~hello/',),
642
685
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
686
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
687
            _client=client)
645
688
        result = bzrdir.open_branch()
646
689
        self.assertFinished(client)
663
706
        client.add_success_response(
664
707
            'ok', '', rich_response, subtree_response, external_lookup,
665
708
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
709
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
710
            _client=client)
668
711
        result = bzrdir.open_repository()
669
712
        self.assertEqual(
686
729
        old.
687
730
        """
688
731
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
732
            RemoteBzrProber.probe_transport, OldServerTransport())
690
733
 
691
734
 
692
735
class TestBzrDirCreateBranch(TestRemote):
715
758
            'BzrDir.create_branch', ('quack/', network_name),
716
759
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
760
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
761
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
762
            _client=client)
720
763
        branch = a_bzrdir.create_branch()
721
764
        # We should have got a remote branch
724
767
        format = branch._format
725
768
        self.assertEqual(network_name, format.network_name())
726
769
 
 
770
    def test_already_open_repo_and_reused_medium(self):
 
771
        """Bug 726584: create_branch(..., repository=repo) should work
 
772
        regardless of what the smart medium's base URL is.
 
773
        """
 
774
        self.transport_server = test_server.SmartTCPServer_for_testing
 
775
        transport = self.get_transport('.')
 
776
        repo = self.make_repository('quack')
 
777
        # Client's medium rooted a transport root (not at the bzrdir)
 
778
        client = FakeClient(transport.base)
 
779
        transport = transport.clone('quack')
 
780
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
781
        reference_format = reference_bzrdir_format.get_branch_format()
 
782
        network_name = reference_format.network_name()
 
783
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
784
        reference_repo_name = reference_repo_fmt.network_name()
 
785
        client.add_expected_call(
 
786
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
787
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
788
            reference_repo_name))
 
789
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
790
            _client=client)
 
791
        branch = a_bzrdir.create_branch(repository=repo)
 
792
        # We should have got a remote branch
 
793
        self.assertIsInstance(branch, remote.RemoteBranch)
 
794
        # its format should have the settings from the response
 
795
        format = branch._format
 
796
        self.assertEqual(network_name, format.network_name())
 
797
 
727
798
 
728
799
class TestBzrDirCreateRepository(TestRemote):
729
800
 
750
821
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
822
                'False'),
752
823
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
824
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
825
            _client=client)
755
826
        repo = a_bzrdir.create_repository()
756
827
        # We should have got a remote repository
785
856
        client.add_success_response('stat', '0', '65535')
786
857
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
858
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
859
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
860
            _client=client)
790
861
        repo = bzrdir.open_repository()
791
862
        self.assertEqual(
818
889
        client.add_success_response('stat', '0', '65535')
819
890
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
891
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
892
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
893
            _client=client)
823
894
        repo = bzrdir.open_repository()
824
895
        self.assertEqual(
839
910
        transport = transport.clone('quack')
840
911
        client = FakeClient(transport.base)
841
912
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
913
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
914
            _client=client)
844
915
        repo = bzrdir.open_repository()
845
916
        self.assertEqual(
852
923
 
853
924
    def test_success(self):
854
925
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
926
        fmt = RemoteBzrDirFormat()
856
927
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
928
        transport = self.get_transport()
858
929
        client = FakeClient(transport.base)
874
945
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
946
        corresponding error from the client.
876
947
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
948
        fmt = RemoteBzrDirFormat()
878
949
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
950
        transport = self.get_transport()
880
951
        client = FakeClient(transport.base)
898
969
        """Integration test for error translation."""
899
970
        transport = self.make_smart_server('foo')
900
971
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
972
        fmt = RemoteBzrDirFormat()
902
973
        err = self.assertRaises(errors.NoSuchFile,
903
974
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
975
 
935
1006
 
936
1007
    def make_remote_bzrdir(self, transport, client):
937
1008
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1009
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1010
            _client=client)
940
1011
 
941
1012
 
1143
1214
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1215
 
1145
1216
 
 
1217
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1218
 
 
1219
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1220
        transport = MemoryTransport()
 
1221
        client = FakeClient(transport.base)
 
1222
        client.add_expected_call(
 
1223
            'Branch.get_stacked_on_url', ('quack/',),
 
1224
            'error', ('NotStacked',))
 
1225
        client.add_expected_call(
 
1226
            'Branch.last_revision_info', ('quack/',),
 
1227
            'success', ('ok', '1', 'rev-tip'))
 
1228
        client.add_expected_call(
 
1229
            'Branch.get_config_file', ('quack/',),
 
1230
            'success', ('ok',), '')
 
1231
        transport.mkdir('quack')
 
1232
        transport = transport.clone('quack')
 
1233
        branch = self.make_remote_branch(transport, client)
 
1234
        result = branch.heads_to_fetch()
 
1235
        self.assertFinished(client)
 
1236
        self.assertEqual((set(['rev-tip']), set()), result)
 
1237
 
 
1238
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1239
        transport = MemoryTransport()
 
1240
        client = FakeClient(transport.base)
 
1241
        client.add_expected_call(
 
1242
            'Branch.get_stacked_on_url', ('quack/',),
 
1243
            'error', ('NotStacked',))
 
1244
        client.add_expected_call(
 
1245
            'Branch.last_revision_info', ('quack/',),
 
1246
            'success', ('ok', '1', 'rev-tip'))
 
1247
        client.add_expected_call(
 
1248
            'Branch.get_config_file', ('quack/',),
 
1249
            'success', ('ok',), 'branch.fetch_tags = True')
 
1250
        # XXX: this will break if the default format's serialization of tags
 
1251
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1252
        client.add_expected_call(
 
1253
            'Branch.get_tags_bytes', ('quack/',),
 
1254
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1255
        transport.mkdir('quack')
 
1256
        transport = transport.clone('quack')
 
1257
        branch = self.make_remote_branch(transport, client)
 
1258
        result = branch.heads_to_fetch()
 
1259
        self.assertFinished(client)
 
1260
        self.assertEqual(
 
1261
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1262
 
 
1263
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1264
        transport = MemoryTransport()
 
1265
        client = FakeClient(transport.base)
 
1266
        client.add_expected_call(
 
1267
            'Branch.get_stacked_on_url', ('quack/',),
 
1268
            'error', ('NotStacked',))
 
1269
        client.add_expected_call(
 
1270
            'Branch.heads_to_fetch', ('quack/',),
 
1271
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1272
        transport.mkdir('quack')
 
1273
        transport = transport.clone('quack')
 
1274
        branch = self.make_remote_branch(transport, client)
 
1275
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1276
        result = branch.heads_to_fetch()
 
1277
        self.assertFinished(client)
 
1278
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1279
 
 
1280
    def make_branch_with_tags(self):
 
1281
        self.setup_smart_server_with_call_log()
 
1282
        # Make a branch with a single revision.
 
1283
        builder = self.make_branch_builder('foo')
 
1284
        builder.start_series()
 
1285
        builder.build_snapshot('tip', None, [
 
1286
            ('add', ('', 'root-id', 'directory', ''))])
 
1287
        builder.finish_series()
 
1288
        branch = builder.get_branch()
 
1289
        # Add two tags to that branch
 
1290
        branch.tags.set_tag('tag-1', 'rev-1')
 
1291
        branch.tags.set_tag('tag-2', 'rev-2')
 
1292
        return branch
 
1293
 
 
1294
    def test_backwards_compatible(self):
 
1295
        branch = self.make_branch_with_tags()
 
1296
        c = branch.get_config()
 
1297
        c.set_user_option('branch.fetch_tags', 'True')
 
1298
        self.addCleanup(branch.lock_read().unlock)
 
1299
        # Disable the heads_to_fetch verb
 
1300
        verb = 'Branch.heads_to_fetch'
 
1301
        self.disable_verb(verb)
 
1302
        self.reset_smart_call_log()
 
1303
        result = branch.heads_to_fetch()
 
1304
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1305
        self.assertEqual(
 
1306
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1307
             'Branch.get_tags_bytes'],
 
1308
            [call.call.method for call in self.hpss_calls])
 
1309
 
 
1310
    def test_backwards_compatible_no_tags(self):
 
1311
        branch = self.make_branch_with_tags()
 
1312
        c = branch.get_config()
 
1313
        c.set_user_option('branch.fetch_tags', 'False')
 
1314
        self.addCleanup(branch.lock_read().unlock)
 
1315
        # Disable the heads_to_fetch verb
 
1316
        verb = 'Branch.heads_to_fetch'
 
1317
        self.disable_verb(verb)
 
1318
        self.reset_smart_call_log()
 
1319
        result = branch.heads_to_fetch()
 
1320
        self.assertEqual((set(['tip']), set()), result)
 
1321
        self.assertEqual(
 
1322
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1323
            [call.call.method for call in self.hpss_calls])
 
1324
 
 
1325
 
1146
1326
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1327
 
1148
1328
    def test_empty_branch(self):
1203
1383
        client.add_expected_call(
1204
1384
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1385
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1386
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1387
            _client=client)
1208
1388
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1389
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1416
        # this will also do vfs access, but that goes direct to the transport
1237
1417
        # and isn't seen by the FakeClient.
1238
1418
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1419
            RemoteBzrDirFormat(), _client=client)
1240
1420
        branch = bzrdir.open_branch()
1241
1421
        result = branch.get_stacked_on_url()
1242
1422
        self.assertEqual('../base', result)
1269
1449
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1450
            'success', ('ok', '../base'))
1271
1451
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1452
            RemoteBzrDirFormat(), _client=client)
1273
1453
        branch = bzrdir.open_branch()
1274
1454
        result = branch.get_stacked_on_url()
1275
1455
        self.assertEqual('../base', result)
1283
1463
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1464
 
1285
1465
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1466
        # _set_last_revision_info('null:') is translated to calling
1287
1467
        # Branch.set_last_revision(path, '') on the wire.
1288
1468
        transport = MemoryTransport()
1289
1469
        transport.mkdir('branch')
1311
1491
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1312
1492
        branch._ensure_real = lambda: None
1313
1493
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1494
        result = branch._set_last_revision(NULL_REVISION)
1315
1495
        branch.unlock()
1316
1496
        self.assertEqual(None, result)
1317
1497
        self.assertFinished(client)
1318
1498
 
1319
1499
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1500
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1501
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1502
        transport = MemoryTransport()
1323
1503
        transport.mkdir('branch')
1349
1529
        branch._ensure_real = lambda: None
1350
1530
        # Lock the branch, reset the record of remote calls.
1351
1531
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1532
        result = branch._set_last_revision('rev-id2')
1353
1533
        branch.unlock()
1354
1534
        self.assertEqual(None, result)
1355
1535
        self.assertFinished(client)
1385
1565
        branch = self.make_remote_branch(transport, client)
1386
1566
        branch.lock_write()
1387
1567
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1568
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1569
        branch.unlock()
1390
1570
        self.assertFinished(client)
1391
1571
 
1422
1602
        branch._ensure_real = lambda: None
1423
1603
        branch.lock_write()
1424
1604
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1605
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1606
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1607
            errors.TipChangeRejected,
 
1608
            branch._set_last_revision, 'rev-id')
1428
1609
        # The UTF-8 message from the response has been decoded into a unicode
1429
1610
        # object.
1430
1611
        self.assertIsInstance(err.msg, unicode)
1618
1799
    def test_get_multi_line_branch_conf(self):
1619
1800
        # Make sure that multiple-line branch.conf files are supported
1620
1801
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1802
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1803
        client = FakeClient()
1623
1804
        client.add_expected_call(
1624
1805
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1833
        branch.unlock()
1653
1834
        self.assertFinished(client)
1654
1835
 
 
1836
    def test_set_option_with_dict(self):
 
1837
        client = FakeClient()
 
1838
        client.add_expected_call(
 
1839
            'Branch.get_stacked_on_url', ('memory:///',),
 
1840
            'error', ('NotStacked',),)
 
1841
        client.add_expected_call(
 
1842
            'Branch.lock_write', ('memory:///', '', ''),
 
1843
            'success', ('ok', 'branch token', 'repo token'))
 
1844
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1845
        client.add_expected_call(
 
1846
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1847
            'repo token', encoded_dict_value, 'foo', ''),
 
1848
            'success', ())
 
1849
        client.add_expected_call(
 
1850
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1851
            'success', ('ok',))
 
1852
        transport = MemoryTransport()
 
1853
        branch = self.make_remote_branch(transport, client)
 
1854
        branch.lock_write()
 
1855
        config = branch._get_config()
 
1856
        config.set_option(
 
1857
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1858
            'foo')
 
1859
        branch.unlock()
 
1860
        self.assertFinished(client)
 
1861
 
1655
1862
    def test_backwards_compat_set_option(self):
1656
1863
        self.setup_smart_server_with_call_log()
1657
1864
        branch = self.make_branch('.')
1664
1871
        self.assertLength(10, self.hpss_calls)
1665
1872
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
1873
 
 
1874
    def test_backwards_compat_set_option_with_dict(self):
 
1875
        self.setup_smart_server_with_call_log()
 
1876
        branch = self.make_branch('.')
 
1877
        verb = 'Branch.set_config_option_dict'
 
1878
        self.disable_verb(verb)
 
1879
        branch.lock_write()
 
1880
        self.addCleanup(branch.unlock)
 
1881
        self.reset_smart_call_log()
 
1882
        config = branch._get_config()
 
1883
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
1884
        config.set_option(value_dict, 'name')
 
1885
        self.assertLength(10, self.hpss_calls)
 
1886
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
1887
 
 
1888
 
 
1889
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
1890
 
 
1891
    def test_get_branch_conf(self):
 
1892
        # in an empty branch we decode the response properly
 
1893
        client = FakeClient()
 
1894
        client.add_expected_call(
 
1895
            'Branch.get_stacked_on_url', ('memory:///',),
 
1896
            'error', ('NotStacked',),)
 
1897
        client.add_success_response_with_body('# config file body', 'ok')
 
1898
        transport = MemoryTransport()
 
1899
        branch = self.make_remote_branch(transport, client)
 
1900
        config = branch.get_config_stack()
 
1901
        config.get("email")
 
1902
        config.get("log_format")
 
1903
        self.assertEqual(
 
1904
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
1905
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
1906
            client._calls)
 
1907
 
 
1908
    def test_set_branch_conf(self):
 
1909
        client = FakeClient()
 
1910
        client.add_expected_call(
 
1911
            'Branch.get_stacked_on_url', ('memory:///',),
 
1912
            'error', ('NotStacked',),)
 
1913
        client.add_expected_call(
 
1914
            'Branch.lock_write', ('memory:///', '', ''),
 
1915
            'success', ('ok', 'branch token', 'repo token'))
 
1916
        client.add_expected_call(
 
1917
            'Branch.get_config_file', ('memory:///', ),
 
1918
            'success', ('ok', ), "# line 1\n")
 
1919
        client.add_expected_call(
 
1920
            'Branch.put_config_file', ('memory:///', 'branch token',
 
1921
            'repo token'),
 
1922
            'success', ('ok',))
 
1923
        client.add_expected_call(
 
1924
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1925
            'success', ('ok',))
 
1926
        transport = MemoryTransport()
 
1927
        branch = self.make_remote_branch(transport, client)
 
1928
        branch.lock_write()
 
1929
        config = branch.get_config_stack()
 
1930
        config.set('email', 'The Dude <lebowski@example.com>')
 
1931
        branch.unlock()
 
1932
        self.assertFinished(client)
 
1933
        self.assertEqual(
 
1934
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
1935
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
1936
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
1937
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
1938
                 ('memory:///', 'branch token', 'repo token'),
 
1939
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
1940
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
1941
            client._calls)
 
1942
 
1667
1943
 
1668
1944
class TestBranchLockWrite(RemoteBranchTestCase):
1669
1945
 
1805
2081
        client = FakeClient(transport.base)
1806
2082
        transport = transport.clone(transport_path)
1807
2083
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2084
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2085
            _client=False)
1810
2086
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2087
        return repo, client
1819
2095
 
1820
2096
    def test_get_format_description(self):
1821
2097
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2098
        real_format = branch.format_registry.get_default()
1823
2099
        remote_format._network_name = real_format.network_name()
1824
2100
        self.assertEqual(remoted_description(real_format),
1825
2101
            remote_format.get_format_description())
1828
2104
class TestRepositoryFormat(TestRemoteRepository):
1829
2105
 
1830
2106
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2107
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2108
        true_format = RemoteRepositoryFormat()
1833
2109
        true_format._network_name = true_name
1834
2110
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2111
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2112
        false_format = RemoteRepositoryFormat()
1837
2113
        false_format._network_name = false_name
1838
2114
        self.assertEqual(False, false_format.fast_deltas)
1839
2115
 
1840
2116
    def test_get_format_description(self):
1841
2117
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2118
        real_format = repository.format_registry.get_default()
1843
2119
        remote_repo_format._network_name = real_format.network_name()
1844
2120
        self.assertEqual(remoted_description(real_format),
1845
2121
            remote_repo_format.get_format_description())
1968
2244
        parents = repo.get_parent_map([rev_id])
1969
2245
        self.assertEqual(
1970
2246
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2247
              'Repository.get_parent_map',
 
2248
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2249
             ('disconnect medium',),
1974
2250
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2251
              ('quack/', ''))],
2095
2371
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2372
        self.assertLength(0, self.hpss_calls)
2097
2373
 
 
2374
    def test_exposes_get_cached_parent_map(self):
 
2375
        """RemoteRepository exposes get_cached_parent_map from
 
2376
        _unstacked_provider
 
2377
        """
 
2378
        r1 = u'\u0e33'.encode('utf8')
 
2379
        r2 = u'\u0dab'.encode('utf8')
 
2380
        lines = [' '.join([r2, r1]), r1]
 
2381
        encoded_body = bz2.compress('\n'.join(lines))
 
2382
 
 
2383
        transport_path = 'quack'
 
2384
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2385
        client.add_success_response_with_body(encoded_body, 'ok')
 
2386
        repo.lock_read()
 
2387
        # get_cached_parent_map should *not* trigger an RPC
 
2388
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2389
        self.assertEqual([], client._calls)
 
2390
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2391
        self.assertEqual({r1: (NULL_REVISION,)},
 
2392
            repo.get_cached_parent_map([r1]))
 
2393
        self.assertEqual(
 
2394
            [('call_with_body_bytes_expecting_body',
 
2395
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2396
              '\n\n0')],
 
2397
            client._calls)
 
2398
        repo.unlock()
 
2399
 
2098
2400
 
2099
2401
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2402
 
2257
2559
        self.setup_smart_server_with_call_log()
2258
2560
        tree = self.make_branch_and_memory_tree('.')
2259
2561
        tree.lock_write()
 
2562
        tree.add('')
2260
2563
        rev1 = tree.commit('First')
2261
2564
        rev2 = tree.commit('Second')
2262
2565
        tree.unlock()
2270
2573
                              call.call.method == verb])
2271
2574
 
2272
2575
 
 
2576
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2577
 
 
2578
    def test_has_signature_for_revision_id(self):
 
2579
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2580
        transport_path = 'quack'
 
2581
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2582
        client.add_success_response('yes')
 
2583
        result = repo.has_signature_for_revision_id('A')
 
2584
        self.assertEqual(
 
2585
            [('call', 'Repository.has_signature_for_revision_id',
 
2586
              ('quack/', 'A'))],
 
2587
            client._calls)
 
2588
        self.assertEqual(True, result)
 
2589
 
 
2590
    def test_is_not_shared(self):
 
2591
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2592
        transport_path = 'qwack'
 
2593
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2594
        client.add_success_response('no')
 
2595
        result = repo.has_signature_for_revision_id('A')
 
2596
        self.assertEqual(
 
2597
            [('call', 'Repository.has_signature_for_revision_id',
 
2598
              ('qwack/', 'A'))],
 
2599
            client._calls)
 
2600
        self.assertEqual(False, result)
 
2601
 
 
2602
 
2273
2603
class TestRepositoryIsShared(TestRemoteRepository):
2274
2604
 
2275
2605
    def test_is_shared(self):
2295
2625
        self.assertEqual(False, result)
2296
2626
 
2297
2627
 
 
2628
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
2629
 
 
2630
    def test_make_working_trees(self):
 
2631
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
2632
        transport_path = 'quack'
 
2633
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2634
        client.add_success_response('yes')
 
2635
        result = repo.make_working_trees()
 
2636
        self.assertEqual(
 
2637
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
2638
            client._calls)
 
2639
        self.assertEqual(True, result)
 
2640
 
 
2641
    def test_no_working_trees(self):
 
2642
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
2643
        transport_path = 'qwack'
 
2644
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2645
        client.add_success_response('no')
 
2646
        result = repo.make_working_trees()
 
2647
        self.assertEqual(
 
2648
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
2649
            client._calls)
 
2650
        self.assertEqual(False, result)
 
2651
 
 
2652
 
2298
2653
class TestRepositoryLockWrite(TestRemoteRepository):
2299
2654
 
2300
2655
    def test_lock_write(self):
2301
2656
        transport_path = 'quack'
2302
2657
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
2658
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
2659
        token = repo.lock_write().repository_token
2305
2660
        self.assertEqual(
2306
2661
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
2662
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
2663
        self.assertEqual('a token', token)
2309
2664
 
2310
2665
    def test_lock_write_already_locked(self):
2311
2666
        transport_path = 'quack'
2402
2757
        the client is finished.
2403
2758
        """
2404
2759
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2760
        fmt = repository.format_registry.get_default()
2406
2761
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
2762
        self.assertEqual([], resume_tokens)
2408
2763
        self.assertEqual(set(), missing_keys)
2508
2863
                return True
2509
2864
        repo._real_repository = FakeRealRepository()
2510
2865
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
2866
        fmt = repository.format_registry.get_default()
2512
2867
        stream = self.make_stream_with_inv_deltas(fmt)
2513
2868
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
2869
        # Every record from the first inventory delta should have been sent to
2734
3089
             ('pack collection autopack',)],
2735
3090
            client._calls)
2736
3091
 
 
3092
    def test_oom_error_reporting(self):
 
3093
        """An out-of-memory condition on the server is reported clearly"""
 
3094
        transport_path = 'quack'
 
3095
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3096
        client.add_expected_call(
 
3097
            'PackRepository.autopack', ('quack/',),
 
3098
            'error', ('MemoryError',))
 
3099
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3100
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3101
 
2737
3102
 
2738
3103
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3104
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3177
            detail='extra detail')
2813
3178
        self.assertEqual(expected_error, translated_error)
2814
3179
 
 
3180
    def test_norepository(self):
 
3181
        bzrdir = self.make_bzrdir('')
 
3182
        translated_error = self.translateTuple(('norepository',),
 
3183
            bzrdir=bzrdir)
 
3184
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3185
        self.assertEqual(expected_error, translated_error)
 
3186
 
2815
3187
    def test_LockContention(self):
2816
3188
        translated_error = self.translateTuple(('LockContention',))
2817
3189
        expected_error = errors.LockContention('(remote lock)')
2845
3217
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3218
        self.assertEqual(expected_error, translated_error)
2847
3219
 
 
3220
    def test_NotStacked(self):
 
3221
        branch = self.make_branch('')
 
3222
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3223
        expected_error = errors.NotStacked(branch)
 
3224
        self.assertEqual(expected_error, translated_error)
 
3225
 
2848
3226
    def test_ReadError_no_args(self):
2849
3227
        path = 'a path'
2850
3228
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3244
 
2867
3245
    def test_PermissionDenied_no_args(self):
2868
3246
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3247
        translated_error = self.translateTuple(('PermissionDenied',),
 
3248
            path=path)
2870
3249
        expected_error = errors.PermissionDenied(path)
2871
3250
        self.assertEqual(expected_error, translated_error)
2872
3251
 
2895
3274
        expected_error = errors.PermissionDenied(path, extra)
2896
3275
        self.assertEqual(expected_error, translated_error)
2897
3276
 
 
3277
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3278
 
 
3279
    def test_NoSuchFile_context_path(self):
 
3280
        local_path = "local path"
 
3281
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3282
            path=local_path)
 
3283
        expected_error = errors.ReadError(local_path)
 
3284
        self.assertEqual(expected_error, translated_error)
 
3285
 
 
3286
    def test_NoSuchFile_without_context(self):
 
3287
        remote_path = "remote path"
 
3288
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3289
        expected_error = errors.ReadError(remote_path)
 
3290
        self.assertEqual(expected_error, translated_error)
 
3291
 
 
3292
    def test_ReadOnlyError(self):
 
3293
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3294
        expected_error = errors.TransportNotPossible("readonly transport")
 
3295
        self.assertEqual(expected_error, translated_error)
 
3296
 
 
3297
    def test_MemoryError(self):
 
3298
        translated_error = self.translateTuple(('MemoryError',))
 
3299
        self.assertStartsWith(str(translated_error),
 
3300
            "remote server out of memory")
 
3301
 
 
3302
    def test_generic_IndexError_no_classname(self):
 
3303
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3304
        translated_error = self.translateErrorFromSmartServer(err)
 
3305
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3306
        self.assertEqual(expected_error, translated_error)
 
3307
 
 
3308
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3309
 
 
3310
    def test_generic_KeyError(self):
 
3311
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3312
        translated_error = self.translateErrorFromSmartServer(err)
 
3313
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3314
        self.assertEqual(expected_error, translated_error)
 
3315
 
2898
3316
 
2899
3317
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3318
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3463
        _, stacked = branch_factory()
3046
3464
        source = stacked.repository._get_source(target_repository_format)
3047
3465
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3466
        stacked.repository._ensure_real()
 
3467
        graph = stacked.repository.get_graph()
 
3468
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3469
                if r != NULL_REVISION]
 
3470
        revs.reverse()
 
3471
        search = _mod_graph.PendingAncestryResult([tip], stacked.repository)
3050
3472
        self.reset_smart_call_log()
3051
3473
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3474
        # We trust that if a revision is in the stream the rest of the new
3055
3475
        # content for it is too, as per our main fetch tests; here we are
3056
3476
        # checking that the revisions are actually included at all, and their
3095
3515
        self.assertEqual(expected_revs, rev_ord)
3096
3516
        # Getting topological sort requires VFS calls still - one of which is
3097
3517
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
3518
        self.assertLength(14, self.hpss_calls)
3099
3519
 
3100
3520
    def test_stacked_get_stream_groupcompress(self):
3101
3521
        # Repository._get_source.get_stream() from a stacked repository with
3142
3562
 
3143
3563
    def test_copy_content_into_avoids_revision_history(self):
3144
3564
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
3565
        builder = self.make_branch_builder('remote')
 
3566
        builder.build_commit(message="Commit.")
3147
3567
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
3568
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
3569
        local.repository.fetch(remote_branch.repository)
3150
3570
        self.hpss_calls = []
3151
3571
        remote_branch.copy_content_into(local)
3152
3572
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
3573
 
 
3574
    def test_fetch_everything_needs_just_one_call(self):
 
3575
        local = self.make_branch('local')
 
3576
        builder = self.make_branch_builder('remote')
 
3577
        builder.build_commit(message="Commit.")
 
3578
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3579
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3580
        self.hpss_calls = []
 
3581
        local.repository.fetch(
 
3582
            remote_branch.repository,
 
3583
            fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
 
3584
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
3585
 
 
3586
    def override_verb(self, verb_name, verb):
 
3587
        request_handlers = request.request_handlers
 
3588
        orig_verb = request_handlers.get(verb_name)
 
3589
        request_handlers.register(verb_name, verb, override_existing=True)
 
3590
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
3591
                override_existing=True)
 
3592
 
 
3593
    def test_fetch_everything_backwards_compat(self):
 
3594
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
3595
        
 
3596
        Pre-2.4 do not support 'everything' searches with the
 
3597
        Repository.get_stream_1.19 verb.
 
3598
        """
 
3599
        verb_log = []
 
3600
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
3601
            """A version of the Repository.get_stream_1.19 verb patched to
 
3602
            reject 'everything' searches the way 2.3 and earlier do.
 
3603
            """
 
3604
            def recreate_search(self, repository, search_bytes,
 
3605
                                discard_excess=False):
 
3606
                verb_log.append(search_bytes.split('\n', 1)[0])
 
3607
                if search_bytes == 'everything':
 
3608
                    return (None,
 
3609
                            request.FailedSmartServerResponse(('BadSearch',)))
 
3610
                return super(OldGetStreamVerb,
 
3611
                        self).recreate_search(repository, search_bytes,
 
3612
                            discard_excess=discard_excess)
 
3613
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
3614
        local = self.make_branch('local')
 
3615
        builder = self.make_branch_builder('remote')
 
3616
        builder.build_commit(message="Commit.")
 
3617
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
3618
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
3619
        self.hpss_calls = []
 
3620
        local.repository.fetch(
 
3621
            remote_branch.repository,
 
3622
            fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
 
3623
        # make sure the overridden verb was used
 
3624
        self.assertLength(1, verb_log)
 
3625
        # more than one HPSS call is needed, but because it's a VFS callback
 
3626
        # its hard to predict exactly how many.
 
3627
        self.assertTrue(len(self.hpss_calls) > 1)
 
3628
 
 
3629
 
 
3630
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
3631
    tests.TestCaseWithTransport):
 
3632
    """Ensure correct handling of bound_location modifications.
 
3633
 
 
3634
    This is tested against a smart server as http://pad.lv/786980 was about a
 
3635
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
3636
    happen in this context.
 
3637
    """
 
3638
 
 
3639
    def setUp(self):
 
3640
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
3641
        self.transport_server = test_server.SmartTCPServer_for_testing
 
3642
 
 
3643
    def make_master_and_checkout(self, master_name, checkout_name):
 
3644
        # Create the master branch and its associated checkout
 
3645
        self.master = self.make_branch_and_tree(master_name)
 
3646
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
3647
        # Modify the master branch so there is something to update
 
3648
        self.master.commit('add stuff')
 
3649
        self.last_revid = self.master.commit('even more stuff')
 
3650
        self.bound_location = self.checkout.branch.get_bound_location()
 
3651
 
 
3652
    def assertUpdateSucceeds(self, new_location):
 
3653
        self.checkout.branch.set_bound_location(new_location)
 
3654
        self.checkout.update()
 
3655
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
3656
 
 
3657
    def test_without_final_slash(self):
 
3658
        self.make_master_and_checkout('master', 'checkout')
 
3659
        # For unclear reasons some users have a bound_location without a final
 
3660
        # '/', simulate that by forcing such a value
 
3661
        self.assertEndsWith(self.bound_location, '/')
 
3662
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
3663
 
 
3664
    def test_plus_sign(self):
 
3665
        self.make_master_and_checkout('+master', 'checkout')
 
3666
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
3667
 
 
3668
    def test_tilda(self):
 
3669
        # Embed ~ in the middle of the path just to avoid any $HOME
 
3670
        # interpretation
 
3671
        self.make_master_and_checkout('mas~ter', 'checkout')
 
3672
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))