~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

Merge bzr.dev, update to use new hooks.

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
25
25
 
26
26
import bz2
27
27
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
30
from bzrlib import (
30
31
    branch,
32
33
    config,
33
34
    controldir,
34
35
    errors,
35
 
    graph,
 
36
    graph as _mod_graph,
36
37
    inventory,
37
38
    inventory_delta,
38
39
    remote,
41
42
    transport,
42
43
    treebuilder,
43
44
    versionedfile,
 
45
    vf_search,
44
46
    )
45
47
from bzrlib.branch import Branch
46
48
from bzrlib.bzrdir import (
48
50
    BzrDirFormat,
49
51
    RemoteBzrProber,
50
52
    )
 
53
from bzrlib.chk_serializer import chk_bencode_serializer
51
54
from bzrlib.remote import (
52
55
    RemoteBranch,
53
56
    RemoteBranchFormat,
54
57
    RemoteBzrDir,
 
58
    RemoteBzrDirFormat,
55
59
    RemoteRepository,
56
60
    RemoteRepositoryFormat,
57
61
    )
58
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
59
 
from bzrlib.revision import NULL_REVISION
60
 
from bzrlib.smart import medium
 
62
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
 
63
from bzrlib.revision import (
 
64
    NULL_REVISION,
 
65
    Revision,
 
66
    )
 
67
from bzrlib.smart import medium, request
61
68
from bzrlib.smart.client import _SmartClient
62
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
69
from bzrlib.smart.repository import (
 
70
    SmartServerRepositoryGetParentMap,
 
71
    SmartServerRepositoryGetStream_1_19,
 
72
    )
 
73
from bzrlib.symbol_versioning import deprecated_in
63
74
from bzrlib.tests import (
64
 
    condition_isinstance,
65
 
    split_suite_by_condition,
66
 
    multiply_tests,
67
75
    test_server,
68
76
    )
 
77
from bzrlib.tests.scenarios import load_tests_apply_scenarios
69
78
from bzrlib.transport.memory import MemoryTransport
70
79
from bzrlib.transport.remote import (
71
80
    RemoteTransport,
72
81
    RemoteSSHTransport,
73
82
    RemoteTCPTransport,
74
 
)
75
 
 
76
 
def load_tests(standard_tests, module, loader):
77
 
    to_adapt, result = split_suite_by_condition(
78
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
79
 
    smart_server_version_scenarios = [
 
83
    )
 
84
 
 
85
 
 
86
load_tests = load_tests_apply_scenarios
 
87
 
 
88
 
 
89
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
90
 
 
91
    scenarios = [
80
92
        ('HPSS-v2',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
93
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
82
94
        ('HPSS-v3',
83
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
84
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
 
 
86
 
 
87
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
95
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
96
 
88
97
 
89
98
    def setUp(self):
90
99
        super(BasicRemoteObjectTests, self).setUp()
94
103
        self.addCleanup(self.transport.disconnect)
95
104
 
96
105
    def test_create_remote_bzrdir(self):
97
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
106
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
98
107
        self.assertIsInstance(b, BzrDir)
99
108
 
100
109
    def test_open_remote_branch(self):
101
110
        # open a standalone branch in the working directory
102
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
111
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
103
112
        branch = b.open_branch()
104
113
        self.assertIsInstance(branch, Branch)
105
114
 
113
122
 
114
123
    def test_remote_branch_revision_history(self):
115
124
        b = BzrDir.open_from_transport(self.transport).open_branch()
116
 
        self.assertEqual([], b.revision_history())
 
125
        self.assertEqual([],
 
126
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
117
127
        r1 = self.local_wt.commit('1st commit')
118
128
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
119
 
        self.assertEqual([r1, r2], b.revision_history())
 
129
        self.assertEqual([r1, r2],
 
130
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
120
131
 
121
132
    def test_find_correct_format(self):
122
133
        """Should open a RemoteBzrDir over a RemoteTransport"""
123
134
        fmt = BzrDirFormat.find_format(self.transport)
124
135
        self.assertTrue(bzrdir.RemoteBzrProber
125
136
                        in controldir.ControlDirFormat._server_probers)
126
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
137
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
127
138
 
128
139
    def test_open_detected_smart_format(self):
129
140
        fmt = BzrDirFormat.find_format(self.transport)
449
460
        client.add_expected_call(
450
461
            'BzrDir.open_branchV3', ('quack/',),
451
462
            'success', ('ref', self.get_url('referenced'))),
452
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
463
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
453
464
            _client=client)
454
465
        result = a_bzrdir.cloning_metadir()
455
466
        # We should have got a control dir matching the referenced branch.
468
479
        client.add_expected_call(
469
480
            'BzrDir.cloning_metadir', ('quack/', 'False'),
470
481
            'success', (control_name, '', ('branch', ''))),
471
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
482
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
472
483
            _client=client)
473
484
        result = a_bzrdir.cloning_metadir()
474
485
        # We should have got a reference control dir with default branch and
479
490
        self.assertEqual(None, result._branch_format)
480
491
        self.assertFinished(client)
481
492
 
 
493
    def test_unknown(self):
 
494
        transport = self.get_transport('quack')
 
495
        referenced = self.make_branch('referenced')
 
496
        expected = referenced.bzrdir.cloning_metadir()
 
497
        client = FakeClient(transport.base)
 
498
        client.add_expected_call(
 
499
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
500
            'success', ('unknown', 'unknown', ('branch', ''))),
 
501
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
502
            _client=client)
 
503
        self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
 
504
 
 
505
 
 
506
class TestBzrDirDestroyBranch(TestRemote):
 
507
 
 
508
    def test_destroy_default(self):
 
509
        transport = self.get_transport('quack')
 
510
        referenced = self.make_branch('referenced')
 
511
        client = FakeClient(transport.base)
 
512
        client.add_expected_call(
 
513
            'BzrDir.destroy_branch', ('quack/', ),
 
514
            'success', ('ok',)),
 
515
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
516
            _client=client)
 
517
        a_bzrdir.destroy_branch()
 
518
        self.assertFinished(client)
 
519
 
 
520
    def test_destroy_named(self):
 
521
        transport = self.get_transport('quack')
 
522
        referenced = self.make_branch('referenced')
 
523
        client = FakeClient(transport.base)
 
524
        client.add_expected_call(
 
525
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
526
            'success', ('ok',)),
 
527
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
528
            _client=client)
 
529
        a_bzrdir.destroy_branch("foo")
 
530
        self.assertFinished(client)
 
531
 
 
532
 
 
533
class TestBzrDirHasWorkingTree(TestRemote):
 
534
 
 
535
    def test_has_workingtree(self):
 
536
        transport = self.get_transport('quack')
 
537
        client = FakeClient(transport.base)
 
538
        client.add_expected_call(
 
539
            'BzrDir.has_workingtree', ('quack/',),
 
540
            'success', ('yes',)),
 
541
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
542
            _client=client)
 
543
        self.assertTrue(a_bzrdir.has_workingtree())
 
544
        self.assertFinished(client)
 
545
 
 
546
    def test_no_workingtree(self):
 
547
        transport = self.get_transport('quack')
 
548
        client = FakeClient(transport.base)
 
549
        client.add_expected_call(
 
550
            'BzrDir.has_workingtree', ('quack/',),
 
551
            'success', ('no',)),
 
552
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
553
            _client=client)
 
554
        self.assertFalse(a_bzrdir.has_workingtree())
 
555
        self.assertFinished(client)
 
556
 
 
557
 
 
558
class TestBzrDirDestroyRepository(TestRemote):
 
559
 
 
560
    def test_destroy_repository(self):
 
561
        transport = self.get_transport('quack')
 
562
        client = FakeClient(transport.base)
 
563
        client.add_expected_call(
 
564
            'BzrDir.destroy_repository', ('quack/',),
 
565
            'success', ('ok',)),
 
566
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
567
            _client=client)
 
568
        a_bzrdir.destroy_repository()
 
569
        self.assertFinished(client)
 
570
 
482
571
 
483
572
class TestBzrDirOpen(TestRemote):
484
573
 
494
583
        client.add_expected_call(
495
584
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
496
585
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
497
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
586
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
498
587
        self.assertFinished(client)
499
588
 
500
589
    def test_present_without_workingtree(self):
501
590
        client, transport = self.make_fake_client_and_transport()
502
591
        client.add_expected_call(
503
592
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
504
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
593
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
505
594
            _client=client, _force_probe=True)
506
595
        self.assertIsInstance(bd, RemoteBzrDir)
507
596
        self.assertFalse(bd.has_workingtree())
512
601
        client, transport = self.make_fake_client_and_transport()
513
602
        client.add_expected_call(
514
603
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
515
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
604
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
516
605
            _client=client, _force_probe=True)
517
606
        self.assertIsInstance(bd, RemoteBzrDir)
518
607
        self.assertTrue(bd.has_workingtree())
525
614
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
526
615
        client.add_expected_call(
527
616
            'BzrDir.open', ('quack/',), 'success', ('yes',))
528
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
617
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
529
618
            _client=client, _force_probe=True)
530
619
        self.assertIsInstance(bd, RemoteBzrDir)
531
620
        self.assertFinished(client)
547
636
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
548
637
        client.add_expected_call(
549
638
            'BzrDir.open', ('quack/',), 'success', ('yes',))
550
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
639
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
551
640
            _client=client, _force_probe=True)
552
641
        self.assertIsInstance(bd, RemoteBzrDir)
553
642
        self.assertFinished(client)
584
673
        client.add_expected_call(
585
674
            'Branch.get_stacked_on_url', ('quack/',),
586
675
            'error', ('NotStacked',))
587
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
676
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
588
677
            _client=client)
589
678
        result = bzrdir.open_branch()
590
679
        self.assertIsInstance(result, RemoteBranch)
597
686
        transport = transport.clone('quack')
598
687
        client = FakeClient(transport.base)
599
688
        client.add_error_response('nobranch')
600
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
689
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
601
690
            _client=client)
602
691
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
603
692
        self.assertEqual(
608
697
        # _get_tree_branch is a form of open_branch, but it should only ask for
609
698
        # branch opening, not any other network requests.
610
699
        calls = []
611
 
        def open_branch(name=None):
 
700
        def open_branch(name=None, possible_transports=None):
612
701
            calls.append("Called")
613
702
            return "a-branch"
614
703
        transport = MemoryTransport()
615
704
        # no requests on the network - catches other api calls being made.
616
705
        client = FakeClient(transport.base)
617
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
706
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
618
707
            _client=client)
619
708
        # patch the open_branch call to record that it was called.
620
709
        bzrdir.open_branch = open_branch
639
728
        client.add_expected_call(
640
729
            'Branch.get_stacked_on_url', ('~hello/',),
641
730
            'error', ('NotStacked',))
642
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
731
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
643
732
            _client=client)
644
733
        result = bzrdir.open_branch()
645
734
        self.assertFinished(client)
662
751
        client.add_success_response(
663
752
            'ok', '', rich_response, subtree_response, external_lookup,
664
753
            network_name)
665
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
754
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
666
755
            _client=client)
667
756
        result = bzrdir.open_repository()
668
757
        self.assertEqual(
714
803
            'BzrDir.create_branch', ('quack/', network_name),
715
804
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
716
805
            reference_repo_name))
717
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
806
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
718
807
            _client=client)
719
808
        branch = a_bzrdir.create_branch()
720
809
        # We should have got a remote branch
723
812
        format = branch._format
724
813
        self.assertEqual(network_name, format.network_name())
725
814
 
 
815
    def test_already_open_repo_and_reused_medium(self):
 
816
        """Bug 726584: create_branch(..., repository=repo) should work
 
817
        regardless of what the smart medium's base URL is.
 
818
        """
 
819
        self.transport_server = test_server.SmartTCPServer_for_testing
 
820
        transport = self.get_transport('.')
 
821
        repo = self.make_repository('quack')
 
822
        # Client's medium rooted a transport root (not at the bzrdir)
 
823
        client = FakeClient(transport.base)
 
824
        transport = transport.clone('quack')
 
825
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
826
        reference_format = reference_bzrdir_format.get_branch_format()
 
827
        network_name = reference_format.network_name()
 
828
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
829
        reference_repo_name = reference_repo_fmt.network_name()
 
830
        client.add_expected_call(
 
831
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
832
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
833
            reference_repo_name))
 
834
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
835
            _client=client)
 
836
        branch = a_bzrdir.create_branch(repository=repo)
 
837
        # We should have got a remote branch
 
838
        self.assertIsInstance(branch, remote.RemoteBranch)
 
839
        # its format should have the settings from the response
 
840
        format = branch._format
 
841
        self.assertEqual(network_name, format.network_name())
 
842
 
726
843
 
727
844
class TestBzrDirCreateRepository(TestRemote):
728
845
 
749
866
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
750
867
                'False'),
751
868
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
752
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
869
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
753
870
            _client=client)
754
871
        repo = a_bzrdir.create_repository()
755
872
        # We should have got a remote repository
784
901
        client.add_success_response('stat', '0', '65535')
785
902
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
786
903
            _client=client)
787
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
904
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
788
905
            _client=client)
789
906
        repo = bzrdir.open_repository()
790
907
        self.assertEqual(
817
934
        client.add_success_response('stat', '0', '65535')
818
935
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
819
936
            _client=client)
820
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
937
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
821
938
            _client=client)
822
939
        repo = bzrdir.open_repository()
823
940
        self.assertEqual(
838
955
        transport = transport.clone('quack')
839
956
        client = FakeClient(transport.base)
840
957
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
841
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
958
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
842
959
            _client=client)
843
960
        repo = bzrdir.open_repository()
844
961
        self.assertEqual(
851
968
 
852
969
    def test_success(self):
853
970
        """Simple test for typical successful call."""
854
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
971
        fmt = RemoteBzrDirFormat()
855
972
        default_format_name = BzrDirFormat.get_default_format().network_name()
856
973
        transport = self.get_transport()
857
974
        client = FakeClient(transport.base)
873
990
        """Error responses are translated, e.g. 'PermissionDenied' raises the
874
991
        corresponding error from the client.
875
992
        """
876
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
993
        fmt = RemoteBzrDirFormat()
877
994
        default_format_name = BzrDirFormat.get_default_format().network_name()
878
995
        transport = self.get_transport()
879
996
        client = FakeClient(transport.base)
897
1014
        """Integration test for error translation."""
898
1015
        transport = self.make_smart_server('foo')
899
1016
        transport = transport.clone('no-such-path')
900
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1017
        fmt = RemoteBzrDirFormat()
901
1018
        err = self.assertRaises(errors.NoSuchFile,
902
1019
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
903
1020
 
934
1051
 
935
1052
    def make_remote_bzrdir(self, transport, client):
936
1053
        """Make a RemotebzrDir using 'client' as the _client."""
937
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1054
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
938
1055
            _client=client)
939
1056
 
940
1057
 
966
1083
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
967
1084
 
968
1085
 
 
1086
class TestBranchBreakLock(RemoteBranchTestCase):
 
1087
 
 
1088
    def test_break_lock(self):
 
1089
        transport_path = 'quack'
 
1090
        transport = MemoryTransport()
 
1091
        client = FakeClient(transport.base)
 
1092
        client.add_expected_call(
 
1093
            'Branch.get_stacked_on_url', ('quack/',),
 
1094
            'error', ('NotStacked',))
 
1095
        client.add_expected_call(
 
1096
            'Branch.break_lock', ('quack/',),
 
1097
            'success', ('ok',))
 
1098
        transport.mkdir('quack')
 
1099
        transport = transport.clone('quack')
 
1100
        branch = self.make_remote_branch(transport, client)
 
1101
        branch.break_lock()
 
1102
        self.assertFinished(client)
 
1103
 
 
1104
 
 
1105
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1106
 
 
1107
    def test_get_physical_lock_status_yes(self):
 
1108
        transport = MemoryTransport()
 
1109
        client = FakeClient(transport.base)
 
1110
        client.add_expected_call(
 
1111
            'Branch.get_stacked_on_url', ('quack/',),
 
1112
            'error', ('NotStacked',))
 
1113
        client.add_expected_call(
 
1114
            'Branch.get_physical_lock_status', ('quack/',),
 
1115
            'success', ('yes',))
 
1116
        transport.mkdir('quack')
 
1117
        transport = transport.clone('quack')
 
1118
        branch = self.make_remote_branch(transport, client)
 
1119
        result = branch.get_physical_lock_status()
 
1120
        self.assertFinished(client)
 
1121
        self.assertEqual(True, result)
 
1122
 
 
1123
    def test_get_physical_lock_status_no(self):
 
1124
        transport = MemoryTransport()
 
1125
        client = FakeClient(transport.base)
 
1126
        client.add_expected_call(
 
1127
            'Branch.get_stacked_on_url', ('quack/',),
 
1128
            'error', ('NotStacked',))
 
1129
        client.add_expected_call(
 
1130
            'Branch.get_physical_lock_status', ('quack/',),
 
1131
            'success', ('no',))
 
1132
        transport.mkdir('quack')
 
1133
        transport = transport.clone('quack')
 
1134
        branch = self.make_remote_branch(transport, client)
 
1135
        result = branch.get_physical_lock_status()
 
1136
        self.assertFinished(client)
 
1137
        self.assertEqual(False, result)
 
1138
 
 
1139
 
969
1140
class TestBranchGetParent(RemoteBranchTestCase):
970
1141
 
971
1142
    def test_no_parent(self):
1142
1313
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1143
1314
 
1144
1315
 
 
1316
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1317
 
 
1318
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1319
        transport = MemoryTransport()
 
1320
        client = FakeClient(transport.base)
 
1321
        client.add_expected_call(
 
1322
            'Branch.get_stacked_on_url', ('quack/',),
 
1323
            'error', ('NotStacked',))
 
1324
        client.add_expected_call(
 
1325
            'Branch.last_revision_info', ('quack/',),
 
1326
            'success', ('ok', '1', 'rev-tip'))
 
1327
        client.add_expected_call(
 
1328
            'Branch.get_config_file', ('quack/',),
 
1329
            'success', ('ok',), '')
 
1330
        transport.mkdir('quack')
 
1331
        transport = transport.clone('quack')
 
1332
        branch = self.make_remote_branch(transport, client)
 
1333
        result = branch.heads_to_fetch()
 
1334
        self.assertFinished(client)
 
1335
        self.assertEqual((set(['rev-tip']), set()), result)
 
1336
 
 
1337
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1338
        transport = MemoryTransport()
 
1339
        client = FakeClient(transport.base)
 
1340
        client.add_expected_call(
 
1341
            'Branch.get_stacked_on_url', ('quack/',),
 
1342
            'error', ('NotStacked',))
 
1343
        client.add_expected_call(
 
1344
            'Branch.last_revision_info', ('quack/',),
 
1345
            'success', ('ok', '1', 'rev-tip'))
 
1346
        client.add_expected_call(
 
1347
            'Branch.get_config_file', ('quack/',),
 
1348
            'success', ('ok',), 'branch.fetch_tags = True')
 
1349
        # XXX: this will break if the default format's serialization of tags
 
1350
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1351
        client.add_expected_call(
 
1352
            'Branch.get_tags_bytes', ('quack/',),
 
1353
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1354
        transport.mkdir('quack')
 
1355
        transport = transport.clone('quack')
 
1356
        branch = self.make_remote_branch(transport, client)
 
1357
        result = branch.heads_to_fetch()
 
1358
        self.assertFinished(client)
 
1359
        self.assertEqual(
 
1360
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1361
 
 
1362
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1363
        transport = MemoryTransport()
 
1364
        client = FakeClient(transport.base)
 
1365
        client.add_expected_call(
 
1366
            'Branch.get_stacked_on_url', ('quack/',),
 
1367
            'error', ('NotStacked',))
 
1368
        client.add_expected_call(
 
1369
            'Branch.heads_to_fetch', ('quack/',),
 
1370
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1371
        transport.mkdir('quack')
 
1372
        transport = transport.clone('quack')
 
1373
        branch = self.make_remote_branch(transport, client)
 
1374
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1375
        result = branch.heads_to_fetch()
 
1376
        self.assertFinished(client)
 
1377
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1378
 
 
1379
    def make_branch_with_tags(self):
 
1380
        self.setup_smart_server_with_call_log()
 
1381
        # Make a branch with a single revision.
 
1382
        builder = self.make_branch_builder('foo')
 
1383
        builder.start_series()
 
1384
        builder.build_snapshot('tip', None, [
 
1385
            ('add', ('', 'root-id', 'directory', ''))])
 
1386
        builder.finish_series()
 
1387
        branch = builder.get_branch()
 
1388
        # Add two tags to that branch
 
1389
        branch.tags.set_tag('tag-1', 'rev-1')
 
1390
        branch.tags.set_tag('tag-2', 'rev-2')
 
1391
        return branch
 
1392
 
 
1393
    def test_backwards_compatible(self):
 
1394
        branch = self.make_branch_with_tags()
 
1395
        c = branch.get_config()
 
1396
        c.set_user_option('branch.fetch_tags', 'True')
 
1397
        self.addCleanup(branch.lock_read().unlock)
 
1398
        # Disable the heads_to_fetch verb
 
1399
        verb = 'Branch.heads_to_fetch'
 
1400
        self.disable_verb(verb)
 
1401
        self.reset_smart_call_log()
 
1402
        result = branch.heads_to_fetch()
 
1403
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1404
        self.assertEqual(
 
1405
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1406
             'Branch.get_tags_bytes'],
 
1407
            [call.call.method for call in self.hpss_calls])
 
1408
 
 
1409
    def test_backwards_compatible_no_tags(self):
 
1410
        branch = self.make_branch_with_tags()
 
1411
        c = branch.get_config()
 
1412
        c.set_user_option('branch.fetch_tags', 'False')
 
1413
        self.addCleanup(branch.lock_read().unlock)
 
1414
        # Disable the heads_to_fetch verb
 
1415
        verb = 'Branch.heads_to_fetch'
 
1416
        self.disable_verb(verb)
 
1417
        self.reset_smart_call_log()
 
1418
        result = branch.heads_to_fetch()
 
1419
        self.assertEqual((set(['tip']), set()), result)
 
1420
        self.assertEqual(
 
1421
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1422
            [call.call.method for call in self.hpss_calls])
 
1423
 
 
1424
 
1145
1425
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1146
1426
 
1147
1427
    def test_empty_branch(self):
1202
1482
        client.add_expected_call(
1203
1483
            'Branch.get_stacked_on_url', ('stacked/',),
1204
1484
            'success', ('ok', vfs_url))
1205
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1485
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1206
1486
            _client=client)
1207
1487
        repo_fmt = remote.RemoteRepositoryFormat()
1208
1488
        repo_fmt._custom_format = stacked_branch.repository._format
1235
1515
        # this will also do vfs access, but that goes direct to the transport
1236
1516
        # and isn't seen by the FakeClient.
1237
1517
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1238
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1518
            RemoteBzrDirFormat(), _client=client)
1239
1519
        branch = bzrdir.open_branch()
1240
1520
        result = branch.get_stacked_on_url()
1241
1521
        self.assertEqual('../base', result)
1268
1548
            'Branch.get_stacked_on_url', ('stacked/',),
1269
1549
            'success', ('ok', '../base'))
1270
1550
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1271
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1551
            RemoteBzrDirFormat(), _client=client)
1272
1552
        branch = bzrdir.open_branch()
1273
1553
        result = branch.get_stacked_on_url()
1274
1554
        self.assertEqual('../base', result)
1282
1562
class TestBranchSetLastRevision(RemoteBranchTestCase):
1283
1563
 
1284
1564
    def test_set_empty(self):
1285
 
        # set_revision_history([]) is translated to calling
 
1565
        # _set_last_revision_info('null:') is translated to calling
1286
1566
        # Branch.set_last_revision(path, '') on the wire.
1287
1567
        transport = MemoryTransport()
1288
1568
        transport.mkdir('branch')
1306
1586
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1307
1587
            'success', ('ok',))
1308
1588
        branch = self.make_remote_branch(transport, client)
1309
 
        # This is a hack to work around the problem that RemoteBranch currently
1310
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1311
 
        branch._ensure_real = lambda: None
1312
1589
        branch.lock_write()
1313
 
        result = branch.set_revision_history([])
 
1590
        result = branch._set_last_revision(NULL_REVISION)
1314
1591
        branch.unlock()
1315
1592
        self.assertEqual(None, result)
1316
1593
        self.assertFinished(client)
1317
1594
 
1318
1595
    def test_set_nonempty(self):
1319
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1596
        # set_last_revision_info(N, rev-idN) is translated to calling
1320
1597
        # Branch.set_last_revision(path, rev-idN) on the wire.
1321
1598
        transport = MemoryTransport()
1322
1599
        transport.mkdir('branch')
1343
1620
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1344
1621
            'success', ('ok',))
1345
1622
        branch = self.make_remote_branch(transport, client)
1346
 
        # This is a hack to work around the problem that RemoteBranch currently
1347
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1348
 
        branch._ensure_real = lambda: None
1349
1623
        # Lock the branch, reset the record of remote calls.
1350
1624
        branch.lock_write()
1351
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1625
        result = branch._set_last_revision('rev-id2')
1352
1626
        branch.unlock()
1353
1627
        self.assertEqual(None, result)
1354
1628
        self.assertFinished(client)
1384
1658
        branch = self.make_remote_branch(transport, client)
1385
1659
        branch.lock_write()
1386
1660
        self.assertRaises(
1387
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1661
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1388
1662
        branch.unlock()
1389
1663
        self.assertFinished(client)
1390
1664
 
1418
1692
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1419
1693
            'success', ('ok',))
1420
1694
        branch = self.make_remote_branch(transport, client)
1421
 
        branch._ensure_real = lambda: None
1422
1695
        branch.lock_write()
1423
1696
        # The 'TipChangeRejected' error response triggered by calling
1424
 
        # set_revision_history causes a TipChangeRejected exception.
 
1697
        # set_last_revision_info causes a TipChangeRejected exception.
1425
1698
        err = self.assertRaises(
1426
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1699
            errors.TipChangeRejected,
 
1700
            branch._set_last_revision, 'rev-id')
1427
1701
        # The UTF-8 message from the response has been decoded into a unicode
1428
1702
        # object.
1429
1703
        self.assertIsInstance(err.msg, unicode)
1704
1978
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
1705
1979
 
1706
1980
 
 
1981
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
1982
 
 
1983
    def test_get_branch_conf(self):
 
1984
        # in an empty branch we decode the response properly
 
1985
        client = FakeClient()
 
1986
        client.add_expected_call(
 
1987
            'Branch.get_stacked_on_url', ('memory:///',),
 
1988
            'error', ('NotStacked',),)
 
1989
        client.add_success_response_with_body('# config file body', 'ok')
 
1990
        transport = MemoryTransport()
 
1991
        branch = self.make_remote_branch(transport, client)
 
1992
        config = branch.get_config_stack()
 
1993
        config.get("email")
 
1994
        config.get("log_format")
 
1995
        self.assertEqual(
 
1996
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
1997
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
1998
            client._calls)
 
1999
 
 
2000
    def test_set_branch_conf(self):
 
2001
        client = FakeClient()
 
2002
        client.add_expected_call(
 
2003
            'Branch.get_stacked_on_url', ('memory:///',),
 
2004
            'error', ('NotStacked',),)
 
2005
        client.add_expected_call(
 
2006
            'Branch.lock_write', ('memory:///', '', ''),
 
2007
            'success', ('ok', 'branch token', 'repo token'))
 
2008
        client.add_expected_call(
 
2009
            'Branch.get_config_file', ('memory:///', ),
 
2010
            'success', ('ok', ), "# line 1\n")
 
2011
        client.add_expected_call(
 
2012
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2013
            'repo token'),
 
2014
            'success', ('ok',))
 
2015
        client.add_expected_call(
 
2016
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2017
            'success', ('ok',))
 
2018
        transport = MemoryTransport()
 
2019
        branch = self.make_remote_branch(transport, client)
 
2020
        branch.lock_write()
 
2021
        config = branch.get_config_stack()
 
2022
        config.set('email', 'The Dude <lebowski@example.com>')
 
2023
        branch.unlock()
 
2024
        self.assertFinished(client)
 
2025
        self.assertEqual(
 
2026
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2027
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2028
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2029
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2030
                 ('memory:///', 'branch token', 'repo token'),
 
2031
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2032
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2033
            client._calls)
 
2034
 
 
2035
 
1707
2036
class TestBranchLockWrite(RemoteBranchTestCase):
1708
2037
 
1709
2038
    def test_lock_write_unlockable(self):
1722
2051
        self.assertFinished(client)
1723
2052
 
1724
2053
 
 
2054
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2055
 
 
2056
    def test_simple(self):
 
2057
        transport = MemoryTransport()
 
2058
        client = FakeClient(transport.base)
 
2059
        client.add_expected_call(
 
2060
            'Branch.get_stacked_on_url', ('quack/',),
 
2061
            'error', ('NotStacked',),)
 
2062
        client.add_expected_call(
 
2063
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2064
            'success', ('ok', '0',),)
 
2065
        client.add_expected_call(
 
2066
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2067
            'error', ('NoSuchRevision', 'unknown',),)
 
2068
        transport.mkdir('quack')
 
2069
        transport = transport.clone('quack')
 
2070
        branch = self.make_remote_branch(transport, client)
 
2071
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2072
        self.assertRaises(errors.NoSuchRevision,
 
2073
            branch.revision_id_to_revno, 'unknown')
 
2074
        self.assertFinished(client)
 
2075
 
 
2076
    def test_dotted(self):
 
2077
        transport = MemoryTransport()
 
2078
        client = FakeClient(transport.base)
 
2079
        client.add_expected_call(
 
2080
            'Branch.get_stacked_on_url', ('quack/',),
 
2081
            'error', ('NotStacked',),)
 
2082
        client.add_expected_call(
 
2083
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2084
            'success', ('ok', '0',),)
 
2085
        client.add_expected_call(
 
2086
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2087
            'error', ('NoSuchRevision', 'unknown',),)
 
2088
        transport.mkdir('quack')
 
2089
        transport = transport.clone('quack')
 
2090
        branch = self.make_remote_branch(transport, client)
 
2091
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2092
        self.assertRaises(errors.NoSuchRevision,
 
2093
            branch.revision_id_to_dotted_revno, 'unknown')
 
2094
        self.assertFinished(client)
 
2095
 
 
2096
    def test_dotted_no_smart_verb(self):
 
2097
        self.setup_smart_server_with_call_log()
 
2098
        branch = self.make_branch('.')
 
2099
        self.disable_verb('Branch.revision_id_to_revno')
 
2100
        self.reset_smart_call_log()
 
2101
        self.assertEquals((0, ),
 
2102
            branch.revision_id_to_dotted_revno('null:'))
 
2103
        self.assertLength(7, self.hpss_calls)
 
2104
 
 
2105
 
1725
2106
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1726
2107
 
1727
2108
    def test__get_config(self):
1844
2225
        client = FakeClient(transport.base)
1845
2226
        transport = transport.clone(transport_path)
1846
2227
        # we do not want bzrdir to make any remote calls
1847
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2228
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1848
2229
            _client=False)
1849
2230
        repo = RemoteRepository(bzrdir, None, _client=client)
1850
2231
        return repo, client
1858
2239
 
1859
2240
    def test_get_format_description(self):
1860
2241
        remote_format = RemoteBranchFormat()
1861
 
        real_format = branch.BranchFormat.get_default_format()
 
2242
        real_format = branch.format_registry.get_default()
1862
2243
        remote_format._network_name = real_format.network_name()
1863
2244
        self.assertEqual(remoted_description(real_format),
1864
2245
            remote_format.get_format_description())
1867
2248
class TestRepositoryFormat(TestRemoteRepository):
1868
2249
 
1869
2250
    def test_fast_delta(self):
1870
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2251
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1871
2252
        true_format = RemoteRepositoryFormat()
1872
2253
        true_format._network_name = true_name
1873
2254
        self.assertEqual(True, true_format.fast_deltas)
1874
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2255
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1875
2256
        false_format = RemoteRepositoryFormat()
1876
2257
        false_format._network_name = false_name
1877
2258
        self.assertEqual(False, false_format.fast_deltas)
1878
2259
 
1879
2260
    def test_get_format_description(self):
1880
2261
        remote_repo_format = RemoteRepositoryFormat()
1881
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2262
        real_format = repository.format_registry.get_default()
1882
2263
        remote_repo_format._network_name = real_format.network_name()
1883
2264
        self.assertEqual(remoted_description(real_format),
1884
2265
            remote_repo_format.get_format_description())
1885
2266
 
1886
2267
 
 
2268
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2269
 
 
2270
    def test_empty(self):
 
2271
        transport_path = 'quack'
 
2272
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2273
        client.add_success_response_with_body('', 'ok')
 
2274
        self.assertEquals([], repo.all_revision_ids())
 
2275
        self.assertEqual(
 
2276
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2277
             ('quack/',))],
 
2278
            client._calls)
 
2279
 
 
2280
    def test_with_some_content(self):
 
2281
        transport_path = 'quack'
 
2282
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2283
        client.add_success_response_with_body(
 
2284
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2285
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2286
            repo.all_revision_ids())
 
2287
        self.assertEqual(
 
2288
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2289
             ('quack/',))],
 
2290
            client._calls)
 
2291
 
 
2292
 
1887
2293
class TestRepositoryGatherStats(TestRemoteRepository):
1888
2294
 
1889
2295
    def test_revid_none(self):
1942
2348
                         result)
1943
2349
 
1944
2350
 
 
2351
class TestRepositoryBreakLock(TestRemoteRepository):
 
2352
 
 
2353
    def test_break_lock(self):
 
2354
        transport_path = 'quack'
 
2355
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2356
        client.add_success_response('ok')
 
2357
        repo.break_lock()
 
2358
        self.assertEqual(
 
2359
            [('call', 'Repository.break_lock', ('quack/',))],
 
2360
            client._calls)
 
2361
 
 
2362
 
 
2363
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2364
 
 
2365
    def test_get_serializer_format(self):
 
2366
        transport_path = 'hill'
 
2367
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2368
        client.add_success_response('ok', '7')
 
2369
        self.assertEquals('7', repo.get_serializer_format())
 
2370
        self.assertEqual(
 
2371
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2372
              ('hill/', ))],
 
2373
            client._calls)
 
2374
 
 
2375
 
 
2376
class TestRepositoryReconcile(TestRemoteRepository):
 
2377
 
 
2378
    def test_reconcile(self):
 
2379
        transport_path = 'hill'
 
2380
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2381
        body = ("garbage_inventories: 2\n"
 
2382
                "inconsistent_parents: 3\n")
 
2383
        client.add_expected_call(
 
2384
            'Repository.lock_write', ('hill/', ''),
 
2385
            'success', ('ok', 'a token'))
 
2386
        client.add_success_response_with_body(body, 'ok')
 
2387
        reconciler = repo.reconcile()
 
2388
        self.assertEqual(
 
2389
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2390
             ('call_expecting_body', 'Repository.reconcile',
 
2391
                ('hill/', 'a token'))],
 
2392
            client._calls)
 
2393
        self.assertEquals(2, reconciler.garbage_inventories)
 
2394
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2395
 
 
2396
 
 
2397
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2398
 
 
2399
    def test_text(self):
 
2400
        # ('ok',), body with signature text
 
2401
        transport_path = 'quack'
 
2402
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2403
        client.add_success_response_with_body(
 
2404
            'THETEXT', 'ok')
 
2405
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2406
        self.assertEqual(
 
2407
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2408
             ('quack/', 'revid'))],
 
2409
            client._calls)
 
2410
 
 
2411
    def test_no_signature(self):
 
2412
        transport_path = 'quick'
 
2413
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2414
        client.add_error_response('nosuchrevision', 'unknown')
 
2415
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2416
                "unknown")
 
2417
        self.assertEqual(
 
2418
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2419
              ('quick/', 'unknown'))],
 
2420
            client._calls)
 
2421
 
 
2422
 
1945
2423
class TestRepositoryGetGraph(TestRemoteRepository):
1946
2424
 
1947
2425
    def test_get_graph(self):
1952
2430
        self.assertNotEqual(graph._parents_provider, repo)
1953
2431
 
1954
2432
 
 
2433
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2434
 
 
2435
    def test_add_signature_text(self):
 
2436
        transport_path = 'quack'
 
2437
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2438
        client.add_expected_call(
 
2439
            'Repository.lock_write', ('quack/', ''),
 
2440
            'success', ('ok', 'a token'))
 
2441
        client.add_expected_call(
 
2442
            'Repository.start_write_group', ('quack/', 'a token'),
 
2443
            'success', ('ok', ('token1', )))
 
2444
        client.add_expected_call(
 
2445
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2446
                'token1'),
 
2447
            'success', ('ok', ), None)
 
2448
        repo.lock_write()
 
2449
        repo.start_write_group()
 
2450
        self.assertIs(None,
 
2451
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2452
        self.assertEqual(
 
2453
            ('call_with_body_bytes_expecting_body',
 
2454
              'Repository.add_signature_text',
 
2455
                ('quack/', 'a token', 'rev1', 'token1'),
 
2456
              'every bloody emperor'),
 
2457
            client._calls[-1])
 
2458
 
 
2459
 
1955
2460
class TestRepositoryGetParentMap(TestRemoteRepository):
1956
2461
 
1957
2462
    def test_get_parent_map_caching(self):
2007
2512
        parents = repo.get_parent_map([rev_id])
2008
2513
        self.assertEqual(
2009
2514
            [('call_with_body_bytes_expecting_body',
2010
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
2011
 
              rev_id), '\n\n0'),
 
2515
              'Repository.get_parent_map',
 
2516
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
2012
2517
             ('disconnect medium',),
2013
2518
             ('call_expecting_body', 'Repository.get_revision_graph',
2014
2519
              ('quack/', ''))],
2134
2639
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2135
2640
        self.assertLength(0, self.hpss_calls)
2136
2641
 
 
2642
    def test_exposes_get_cached_parent_map(self):
 
2643
        """RemoteRepository exposes get_cached_parent_map from
 
2644
        _unstacked_provider
 
2645
        """
 
2646
        r1 = u'\u0e33'.encode('utf8')
 
2647
        r2 = u'\u0dab'.encode('utf8')
 
2648
        lines = [' '.join([r2, r1]), r1]
 
2649
        encoded_body = bz2.compress('\n'.join(lines))
 
2650
 
 
2651
        transport_path = 'quack'
 
2652
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2653
        client.add_success_response_with_body(encoded_body, 'ok')
 
2654
        repo.lock_read()
 
2655
        # get_cached_parent_map should *not* trigger an RPC
 
2656
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2657
        self.assertEqual([], client._calls)
 
2658
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2659
        self.assertEqual({r1: (NULL_REVISION,)},
 
2660
            repo.get_cached_parent_map([r1]))
 
2661
        self.assertEqual(
 
2662
            [('call_with_body_bytes_expecting_body',
 
2663
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2664
              '\n\n0')],
 
2665
            client._calls)
 
2666
        repo.unlock()
 
2667
 
2137
2668
 
2138
2669
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2139
2670
 
2154
2685
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2155
2686
 
2156
2687
 
 
2688
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2689
 
 
2690
    def test_hpss_missing_revision(self):
 
2691
        transport_path = 'quack'
 
2692
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2693
        client.add_success_response_with_body(
 
2694
            '', 'ok', '10')
 
2695
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2696
            ['somerev1', 'anotherrev2'])
 
2697
        self.assertEqual(
 
2698
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2699
             ('quack/', ), "somerev1\nanotherrev2")],
 
2700
            client._calls)
 
2701
 
 
2702
    def test_hpss_get_single_revision(self):
 
2703
        transport_path = 'quack'
 
2704
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2705
        somerev1 = Revision("somerev1")
 
2706
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2707
        somerev1.timestamp = 1321828927
 
2708
        somerev1.timezone = -60
 
2709
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2710
        somerev1.message = "Message"
 
2711
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2712
            somerev1))
 
2713
        # Split up body into two bits to make sure the zlib compression object
 
2714
        # gets data fed twice.
 
2715
        client.add_success_response_with_body(
 
2716
                [body[:10], body[10:]], 'ok', '10')
 
2717
        revs = repo.get_revisions(['somerev1'])
 
2718
        self.assertEquals(revs, [somerev1])
 
2719
        self.assertEqual(
 
2720
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2721
             ('quack/', ), "somerev1")],
 
2722
            client._calls)
 
2723
 
 
2724
 
2157
2725
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2158
2726
 
2159
2727
    def test_null_revision(self):
2310
2878
                              call.call.method == verb])
2311
2879
 
2312
2880
 
 
2881
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2882
 
 
2883
    def test_has_signature_for_revision_id(self):
 
2884
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2885
        transport_path = 'quack'
 
2886
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2887
        client.add_success_response('yes')
 
2888
        result = repo.has_signature_for_revision_id('A')
 
2889
        self.assertEqual(
 
2890
            [('call', 'Repository.has_signature_for_revision_id',
 
2891
              ('quack/', 'A'))],
 
2892
            client._calls)
 
2893
        self.assertEqual(True, result)
 
2894
 
 
2895
    def test_is_not_shared(self):
 
2896
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2897
        transport_path = 'qwack'
 
2898
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2899
        client.add_success_response('no')
 
2900
        result = repo.has_signature_for_revision_id('A')
 
2901
        self.assertEqual(
 
2902
            [('call', 'Repository.has_signature_for_revision_id',
 
2903
              ('qwack/', 'A'))],
 
2904
            client._calls)
 
2905
        self.assertEqual(False, result)
 
2906
 
 
2907
 
 
2908
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2909
 
 
2910
    def test_get_physical_lock_status_yes(self):
 
2911
        transport_path = 'qwack'
 
2912
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2913
        client.add_success_response('yes')
 
2914
        result = repo.get_physical_lock_status()
 
2915
        self.assertEqual(
 
2916
            [('call', 'Repository.get_physical_lock_status',
 
2917
              ('qwack/', ))],
 
2918
            client._calls)
 
2919
        self.assertEqual(True, result)
 
2920
 
 
2921
    def test_get_physical_lock_status_no(self):
 
2922
        transport_path = 'qwack'
 
2923
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2924
        client.add_success_response('no')
 
2925
        result = repo.get_physical_lock_status()
 
2926
        self.assertEqual(
 
2927
            [('call', 'Repository.get_physical_lock_status',
 
2928
              ('qwack/', ))],
 
2929
            client._calls)
 
2930
        self.assertEqual(False, result)
 
2931
 
 
2932
 
2313
2933
class TestRepositoryIsShared(TestRemoteRepository):
2314
2934
 
2315
2935
    def test_is_shared(self):
2335
2955
        self.assertEqual(False, result)
2336
2956
 
2337
2957
 
 
2958
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
2959
 
 
2960
    def test_make_working_trees(self):
 
2961
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
2962
        transport_path = 'quack'
 
2963
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2964
        client.add_success_response('yes')
 
2965
        result = repo.make_working_trees()
 
2966
        self.assertEqual(
 
2967
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
2968
            client._calls)
 
2969
        self.assertEqual(True, result)
 
2970
 
 
2971
    def test_no_working_trees(self):
 
2972
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
2973
        transport_path = 'qwack'
 
2974
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2975
        client.add_success_response('no')
 
2976
        result = repo.make_working_trees()
 
2977
        self.assertEqual(
 
2978
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
2979
            client._calls)
 
2980
        self.assertEqual(False, result)
 
2981
 
 
2982
 
2338
2983
class TestRepositoryLockWrite(TestRemoteRepository):
2339
2984
 
2340
2985
    def test_lock_write(self):
2366
3011
            client._calls)
2367
3012
 
2368
3013
 
 
3014
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3015
 
 
3016
    def test_start_write_group(self):
 
3017
        transport_path = 'quack'
 
3018
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3019
        client.add_expected_call(
 
3020
            'Repository.lock_write', ('quack/', ''),
 
3021
            'success', ('ok', 'a token'))
 
3022
        client.add_expected_call(
 
3023
            'Repository.start_write_group', ('quack/', 'a token'),
 
3024
            'success', ('ok', ('token1', )))
 
3025
        repo.lock_write()
 
3026
        repo.start_write_group()
 
3027
 
 
3028
    def test_start_write_group_unsuspendable(self):
 
3029
        # Some repositories do not support suspending write
 
3030
        # groups. For those, fall back to the "real" repository.
 
3031
        transport_path = 'quack'
 
3032
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3033
        def stub_ensure_real():
 
3034
            client._calls.append(('_ensure_real',))
 
3035
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3036
        repo._ensure_real = stub_ensure_real
 
3037
        client.add_expected_call(
 
3038
            'Repository.lock_write', ('quack/', ''),
 
3039
            'success', ('ok', 'a token'))
 
3040
        client.add_expected_call(
 
3041
            'Repository.start_write_group', ('quack/', 'a token'),
 
3042
            'error', ('UnsuspendableWriteGroup',))
 
3043
        repo.lock_write()
 
3044
        repo.start_write_group()
 
3045
        self.assertEquals(client._calls[-2:], [ 
 
3046
            ('_ensure_real',),
 
3047
            ('start_write_group',)])
 
3048
 
 
3049
    def test_commit_write_group(self):
 
3050
        transport_path = 'quack'
 
3051
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3052
        client.add_expected_call(
 
3053
            'Repository.lock_write', ('quack/', ''),
 
3054
            'success', ('ok', 'a token'))
 
3055
        client.add_expected_call(
 
3056
            'Repository.start_write_group', ('quack/', 'a token'),
 
3057
            'success', ('ok', ['token1']))
 
3058
        client.add_expected_call(
 
3059
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3060
            'success', ('ok',))
 
3061
        repo.lock_write()
 
3062
        repo.start_write_group()
 
3063
        repo.commit_write_group()
 
3064
 
 
3065
    def test_abort_write_group(self):
 
3066
        transport_path = 'quack'
 
3067
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3068
        client.add_expected_call(
 
3069
            'Repository.lock_write', ('quack/', ''),
 
3070
            'success', ('ok', 'a token'))
 
3071
        client.add_expected_call(
 
3072
            'Repository.start_write_group', ('quack/', 'a token'),
 
3073
            'success', ('ok', ['token1']))
 
3074
        client.add_expected_call(
 
3075
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3076
            'success', ('ok',))
 
3077
        repo.lock_write()
 
3078
        repo.start_write_group()
 
3079
        repo.abort_write_group(False)
 
3080
 
 
3081
    def test_suspend_write_group(self):
 
3082
        transport_path = 'quack'
 
3083
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3084
        self.assertEquals([], repo.suspend_write_group())
 
3085
 
 
3086
    def test_resume_write_group(self):
 
3087
        transport_path = 'quack'
 
3088
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3089
        client.add_expected_call(
 
3090
            'Repository.lock_write', ('quack/', ''),
 
3091
            'success', ('ok', 'a token'))
 
3092
        client.add_expected_call(
 
3093
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3094
            'success', ('ok',))
 
3095
        repo.lock_write()
 
3096
        repo.resume_write_group(['token1'])
 
3097
 
 
3098
 
2369
3099
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2370
3100
 
2371
3101
    def test_backwards_compat(self):
2430
3160
        self.assertEqual([], client._calls)
2431
3161
 
2432
3162
 
 
3163
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3164
    """Test Repository.iter_file_bytes."""
 
3165
 
 
3166
    def test_single(self):
 
3167
        transport_path = 'quack'
 
3168
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3169
        client.add_expected_call(
 
3170
            'Repository.iter_files_bytes', ('quack/', ),
 
3171
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3172
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3173
                "somerev", "myid")]):
 
3174
            self.assertEquals("myid", identifier)
 
3175
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3176
 
 
3177
    def test_missing(self):
 
3178
        transport_path = 'quack'
 
3179
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3180
        client.add_expected_call(
 
3181
            'Repository.iter_files_bytes',
 
3182
                ('quack/', ),
 
3183
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3184
            iter(["absent\0somefile\0somerev\n"]))
 
3185
        self.assertRaises(errors.RevisionNotPresent, list,
 
3186
                repo.iter_files_bytes(
 
3187
                [("somefile", "somerev", "myid")]))
 
3188
 
 
3189
 
2433
3190
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2434
3191
    """Base class for Repository.insert_stream and .insert_stream_1.19
2435
3192
    tests.
2442
3199
        the client is finished.
2443
3200
        """
2444
3201
        sink = repo._get_sink()
2445
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3202
        fmt = repository.format_registry.get_default()
2446
3203
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2447
3204
        self.assertEqual([], resume_tokens)
2448
3205
        self.assertEqual(set(), missing_keys)
2548
3305
                return True
2549
3306
        repo._real_repository = FakeRealRepository()
2550
3307
        sink = repo._get_sink()
2551
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3308
        fmt = repository.format_registry.get_default()
2552
3309
        stream = self.make_stream_with_inv_deltas(fmt)
2553
3310
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2554
3311
        # Every record from the first inventory delta should have been sent to
2710
3467
        self.calls = calls
2711
3468
        self._pack_collection = _StubPackCollection(calls)
2712
3469
 
 
3470
    def start_write_group(self):
 
3471
        self.calls.append(('start_write_group',))
 
3472
 
2713
3473
    def is_in_write_group(self):
2714
3474
        return False
2715
3475
 
2774
3534
             ('pack collection autopack',)],
2775
3535
            client._calls)
2776
3536
 
 
3537
    def test_oom_error_reporting(self):
 
3538
        """An out-of-memory condition on the server is reported clearly"""
 
3539
        transport_path = 'quack'
 
3540
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3541
        client.add_expected_call(
 
3542
            'PackRepository.autopack', ('quack/',),
 
3543
            'error', ('MemoryError',))
 
3544
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3545
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3546
 
2777
3547
 
2778
3548
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2779
3549
    """Base class for unit tests for bzrlib.remote._translate_error."""
2852
3622
            detail='extra detail')
2853
3623
        self.assertEqual(expected_error, translated_error)
2854
3624
 
 
3625
    def test_norepository(self):
 
3626
        bzrdir = self.make_bzrdir('')
 
3627
        translated_error = self.translateTuple(('norepository',),
 
3628
            bzrdir=bzrdir)
 
3629
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3630
        self.assertEqual(expected_error, translated_error)
 
3631
 
2855
3632
    def test_LockContention(self):
2856
3633
        translated_error = self.translateTuple(('LockContention',))
2857
3634
        expected_error = errors.LockContention('(remote lock)')
2885
3662
        expected_error = errors.DivergedBranches(branch, other_branch)
2886
3663
        self.assertEqual(expected_error, translated_error)
2887
3664
 
 
3665
    def test_NotStacked(self):
 
3666
        branch = self.make_branch('')
 
3667
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3668
        expected_error = errors.NotStacked(branch)
 
3669
        self.assertEqual(expected_error, translated_error)
 
3670
 
2888
3671
    def test_ReadError_no_args(self):
2889
3672
        path = 'a path'
2890
3673
        translated_error = self.translateTuple(('ReadError',), path=path)
2906
3689
 
2907
3690
    def test_PermissionDenied_no_args(self):
2908
3691
        path = 'a path'
2909
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3692
        translated_error = self.translateTuple(('PermissionDenied',),
 
3693
            path=path)
2910
3694
        expected_error = errors.PermissionDenied(path)
2911
3695
        self.assertEqual(expected_error, translated_error)
2912
3696
 
2935
3719
        expected_error = errors.PermissionDenied(path, extra)
2936
3720
        self.assertEqual(expected_error, translated_error)
2937
3721
 
 
3722
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3723
 
 
3724
    def test_NoSuchFile_context_path(self):
 
3725
        local_path = "local path"
 
3726
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3727
            path=local_path)
 
3728
        expected_error = errors.ReadError(local_path)
 
3729
        self.assertEqual(expected_error, translated_error)
 
3730
 
 
3731
    def test_NoSuchFile_without_context(self):
 
3732
        remote_path = "remote path"
 
3733
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3734
        expected_error = errors.ReadError(remote_path)
 
3735
        self.assertEqual(expected_error, translated_error)
 
3736
 
 
3737
    def test_ReadOnlyError(self):
 
3738
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3739
        expected_error = errors.TransportNotPossible("readonly transport")
 
3740
        self.assertEqual(expected_error, translated_error)
 
3741
 
 
3742
    def test_MemoryError(self):
 
3743
        translated_error = self.translateTuple(('MemoryError',))
 
3744
        self.assertStartsWith(str(translated_error),
 
3745
            "remote server out of memory")
 
3746
 
 
3747
    def test_generic_IndexError_no_classname(self):
 
3748
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3749
        translated_error = self.translateErrorFromSmartServer(err)
 
3750
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3751
        self.assertEqual(expected_error, translated_error)
 
3752
 
 
3753
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3754
 
 
3755
    def test_generic_KeyError(self):
 
3756
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3757
        translated_error = self.translateErrorFromSmartServer(err)
 
3758
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3759
        self.assertEqual(expected_error, translated_error)
 
3760
 
2938
3761
 
2939
3762
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2940
3763
    """Unit tests for bzrlib.remote._translate_error's robustness.
3085
3908
        _, stacked = branch_factory()
3086
3909
        source = stacked.repository._get_source(target_repository_format)
3087
3910
        tip = stacked.last_revision()
3088
 
        revs = stacked.repository.get_ancestry(tip)
3089
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3911
        stacked.repository._ensure_real()
 
3912
        graph = stacked.repository.get_graph()
 
3913
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3914
                if r != NULL_REVISION]
 
3915
        revs.reverse()
 
3916
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3090
3917
        self.reset_smart_call_log()
3091
3918
        stream = source.get_stream(search)
3092
 
        if None in revs:
3093
 
            revs.remove(None)
3094
3919
        # We trust that if a revision is in the stream the rest of the new
3095
3920
        # content for it is too, as per our main fetch tests; here we are
3096
3921
        # checking that the revisions are actually included at all, and their
3135
3960
        self.assertEqual(expected_revs, rev_ord)
3136
3961
        # Getting topological sort requires VFS calls still - one of which is
3137
3962
        # pushing up from the bound branch.
3138
 
        self.assertLength(13, self.hpss_calls)
 
3963
        self.assertLength(14, self.hpss_calls)
3139
3964
 
3140
3965
    def test_stacked_get_stream_groupcompress(self):
3141
3966
        # Repository._get_source.get_stream() from a stacked repository with
3182
4007
 
3183
4008
    def test_copy_content_into_avoids_revision_history(self):
3184
4009
        local = self.make_branch('local')
3185
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3186
 
        remote_backing_tree.commit("Commit.")
 
4010
        builder = self.make_branch_builder('remote')
 
4011
        builder.build_commit(message="Commit.")
3187
4012
        remote_branch_url = self.smart_server.get_url() + 'remote'
3188
4013
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3189
4014
        local.repository.fetch(remote_branch.repository)
3190
4015
        self.hpss_calls = []
3191
4016
        remote_branch.copy_content_into(local)
3192
4017
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4018
 
 
4019
    def test_fetch_everything_needs_just_one_call(self):
 
4020
        local = self.make_branch('local')
 
4021
        builder = self.make_branch_builder('remote')
 
4022
        builder.build_commit(message="Commit.")
 
4023
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4024
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4025
        self.hpss_calls = []
 
4026
        local.repository.fetch(
 
4027
            remote_branch.repository,
 
4028
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4029
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4030
 
 
4031
    def override_verb(self, verb_name, verb):
 
4032
        request_handlers = request.request_handlers
 
4033
        orig_verb = request_handlers.get(verb_name)
 
4034
        orig_info = request_handlers.get_info(verb_name)
 
4035
        request_handlers.register(verb_name, verb, override_existing=True)
 
4036
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4037
                override_existing=True, info=orig_info)
 
4038
 
 
4039
    def test_fetch_everything_backwards_compat(self):
 
4040
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4041
        
 
4042
        Pre-2.4 do not support 'everything' searches with the
 
4043
        Repository.get_stream_1.19 verb.
 
4044
        """
 
4045
        verb_log = []
 
4046
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4047
            """A version of the Repository.get_stream_1.19 verb patched to
 
4048
            reject 'everything' searches the way 2.3 and earlier do.
 
4049
            """
 
4050
            def recreate_search(self, repository, search_bytes,
 
4051
                                discard_excess=False):
 
4052
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4053
                if search_bytes == 'everything':
 
4054
                    return (None,
 
4055
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4056
                return super(OldGetStreamVerb,
 
4057
                        self).recreate_search(repository, search_bytes,
 
4058
                            discard_excess=discard_excess)
 
4059
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4060
        local = self.make_branch('local')
 
4061
        builder = self.make_branch_builder('remote')
 
4062
        builder.build_commit(message="Commit.")
 
4063
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4064
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4065
        self.hpss_calls = []
 
4066
        local.repository.fetch(
 
4067
            remote_branch.repository,
 
4068
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4069
        # make sure the overridden verb was used
 
4070
        self.assertLength(1, verb_log)
 
4071
        # more than one HPSS call is needed, but because it's a VFS callback
 
4072
        # its hard to predict exactly how many.
 
4073
        self.assertTrue(len(self.hpss_calls) > 1)
 
4074
 
 
4075
 
 
4076
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4077
    tests.TestCaseWithTransport):
 
4078
    """Ensure correct handling of bound_location modifications.
 
4079
 
 
4080
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4081
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4082
    happen in this context.
 
4083
    """
 
4084
 
 
4085
    def setUp(self):
 
4086
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4087
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4088
 
 
4089
    def make_master_and_checkout(self, master_name, checkout_name):
 
4090
        # Create the master branch and its associated checkout
 
4091
        self.master = self.make_branch_and_tree(master_name)
 
4092
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4093
        # Modify the master branch so there is something to update
 
4094
        self.master.commit('add stuff')
 
4095
        self.last_revid = self.master.commit('even more stuff')
 
4096
        self.bound_location = self.checkout.branch.get_bound_location()
 
4097
 
 
4098
    def assertUpdateSucceeds(self, new_location):
 
4099
        self.checkout.branch.set_bound_location(new_location)
 
4100
        self.checkout.update()
 
4101
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4102
 
 
4103
    def test_without_final_slash(self):
 
4104
        self.make_master_and_checkout('master', 'checkout')
 
4105
        # For unclear reasons some users have a bound_location without a final
 
4106
        # '/', simulate that by forcing such a value
 
4107
        self.assertEndsWith(self.bound_location, '/')
 
4108
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4109
 
 
4110
    def test_plus_sign(self):
 
4111
        self.make_master_and_checkout('+master', 'checkout')
 
4112
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4113
 
 
4114
    def test_tilda(self):
 
4115
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4116
        # interpretation
 
4117
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4118
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4119
 
 
4120
 
 
4121
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4122
 
 
4123
    def test_no_context(self):
 
4124
        class OutOfCoffee(errors.BzrError):
 
4125
            """A dummy exception for testing."""
 
4126
 
 
4127
            def __init__(self, urgency):
 
4128
                self.urgency = urgency
 
4129
        remote.no_context_error_translators.register("OutOfCoffee",
 
4130
            lambda err: OutOfCoffee(err.error_args[0]))
 
4131
        transport = MemoryTransport()
 
4132
        client = FakeClient(transport.base)
 
4133
        client.add_expected_call(
 
4134
            'Branch.get_stacked_on_url', ('quack/',),
 
4135
            'error', ('NotStacked',))
 
4136
        client.add_expected_call(
 
4137
            'Branch.last_revision_info',
 
4138
            ('quack/',),
 
4139
            'error', ('OutOfCoffee', 'low'))
 
4140
        transport.mkdir('quack')
 
4141
        transport = transport.clone('quack')
 
4142
        branch = self.make_remote_branch(transport, client)
 
4143
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4144
        self.assertFinished(client)
 
4145
 
 
4146
    def test_with_context(self):
 
4147
        class OutOfTea(errors.BzrError):
 
4148
            def __init__(self, branch, urgency):
 
4149
                self.branch = branch
 
4150
                self.urgency = urgency
 
4151
        remote.error_translators.register("OutOfTea",
 
4152
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4153
                find("branch")))
 
4154
        transport = MemoryTransport()
 
4155
        client = FakeClient(transport.base)
 
4156
        client.add_expected_call(
 
4157
            'Branch.get_stacked_on_url', ('quack/',),
 
4158
            'error', ('NotStacked',))
 
4159
        client.add_expected_call(
 
4160
            'Branch.last_revision_info',
 
4161
            ('quack/',),
 
4162
            'error', ('OutOfTea', 'low'))
 
4163
        transport.mkdir('quack')
 
4164
        transport = transport.clone('quack')
 
4165
        branch = self.make_remote_branch(transport, client)
 
4166
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4167
        self.assertFinished(client)
 
4168
 
 
4169
 
 
4170
class TestRepositoryPack(TestRemoteRepository):
 
4171
 
 
4172
    def test_pack(self):
 
4173
        transport_path = 'quack'
 
4174
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4175
        client.add_expected_call(
 
4176
            'Repository.lock_write', ('quack/', ''),
 
4177
            'success', ('ok', 'token'))
 
4178
        client.add_expected_call(
 
4179
            'Repository.pack', ('quack/', 'token', 'False'),
 
4180
            'success', ('ok',), )
 
4181
        client.add_expected_call(
 
4182
            'Repository.unlock', ('quack/', 'token'),
 
4183
            'success', ('ok', ))
 
4184
        repo.pack()
 
4185
 
 
4186
    def test_pack_with_hint(self):
 
4187
        transport_path = 'quack'
 
4188
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4189
        client.add_expected_call(
 
4190
            'Repository.lock_write', ('quack/', ''),
 
4191
            'success', ('ok', 'token'))
 
4192
        client.add_expected_call(
 
4193
            'Repository.pack', ('quack/', 'token', 'False'),
 
4194
            'success', ('ok',), )
 
4195
        client.add_expected_call(
 
4196
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4197
            'success', ('ok', ))
 
4198
        repo.pack(['hinta', 'hintb'])