~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Vincent Ladeuil
  • Date: 2012-03-09 16:48:55 UTC
  • mto: (6437.23.24 2.5)
  • mto: This revision was merged to the branch mainline in revision 6499.
  • Revision ID: v.ladeuil+lp@free.fr-20120309164855-htdn25hp7x65mmir
Rely on sphinx for texinfo doc generation

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 (
 
31
    bencode,
30
32
    branch,
31
33
    bzrdir,
32
34
    config,
 
35
    controldir,
33
36
    errors,
34
 
    graph,
35
37
    inventory,
36
38
    inventory_delta,
37
 
    pack,
38
39
    remote,
39
40
    repository,
40
41
    tests,
 
42
    transport,
41
43
    treebuilder,
42
 
    urlutils,
43
44
    versionedfile,
 
45
    vf_search,
44
46
    )
45
47
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
48
from bzrlib.bzrdir import (
 
49
    BzrDir,
 
50
    BzrDirFormat,
 
51
    RemoteBzrProber,
 
52
    )
 
53
from bzrlib.chk_serializer import chk_bencode_serializer
47
54
from bzrlib.remote import (
48
55
    RemoteBranch,
49
56
    RemoteBranchFormat,
52
59
    RemoteRepository,
53
60
    RemoteRepositoryFormat,
54
61
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
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
58
68
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
69
from bzrlib.smart.repository import (
 
70
    SmartServerRepositoryGetParentMap,
 
71
    SmartServerRepositoryGetStream_1_19,
 
72
    _stream_to_byte_stream,
 
73
    )
 
74
from bzrlib.symbol_versioning import deprecated_in
60
75
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
76
    test_server,
65
77
    )
66
 
from bzrlib.transport import get_transport
 
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
79
from bzrlib.transport.memory import MemoryTransport
68
80
from bzrlib.transport.remote import (
69
81
    RemoteTransport,
70
82
    RemoteSSHTransport,
71
83
    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 = [
 
84
    )
 
85
 
 
86
 
 
87
load_tests = load_tests_apply_scenarios
 
88
 
 
89
 
 
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
91
 
 
92
    scenarios = [
78
93
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
94
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
95
        ('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):
 
96
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
97
 
86
98
 
87
99
    def setUp(self):
88
100
        super(BasicRemoteObjectTests, self).setUp()
89
101
        self.transport = self.get_transport()
90
102
        # make a branch that can be opened over the smart transport
91
103
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
104
        self.addCleanup(self.transport.disconnect)
96
105
 
97
106
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
107
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
108
        self.assertIsInstance(b, BzrDir)
100
109
 
101
110
    def test_open_remote_branch(self):
102
111
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
112
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
113
        branch = b.open_branch()
105
114
        self.assertIsInstance(branch, Branch)
106
115
 
114
123
 
115
124
    def test_remote_branch_revision_history(self):
116
125
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
 
126
        self.assertEqual([],
 
127
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
128
        r1 = self.local_wt.commit('1st commit')
119
129
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
 
130
        self.assertEqual([r1, r2],
 
131
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
121
132
 
122
133
    def test_find_correct_format(self):
123
134
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
135
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
136
        self.assertTrue(bzrdir.RemoteBzrProber
 
137
                        in controldir.ControlDirFormat._server_probers)
 
138
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
139
 
129
140
    def test_open_detected_smart_format(self):
130
141
        fmt = BzrDirFormat.find_format(self.transport)
164
175
    def test_remote_branch_set_append_revisions_only(self):
165
176
        # Make a format 1.9 branch, which supports append_revisions_only
166
177
        branch = self.make_branch('branch', format='1.9')
167
 
        config = branch.get_config()
168
178
        branch.set_append_revisions_only(True)
 
179
        config = branch.get_config_stack()
169
180
        self.assertEqual(
170
 
            'True', config.get_user_option('append_revisions_only'))
 
181
            True, config.get('append_revisions_only'))
171
182
        branch.set_append_revisions_only(False)
 
183
        config = branch.get_config_stack()
172
184
        self.assertEqual(
173
 
            'False', config.get_user_option('append_revisions_only'))
 
185
            False, config.get('append_revisions_only'))
174
186
 
175
187
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
176
188
        branch = self.make_branch('branch', format='knit')
177
 
        config = branch.get_config()
178
189
        self.assertRaises(
179
190
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
180
191
 
359
370
        a given client_base and transport_base.
360
371
        """
361
372
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
373
        t = transport.get_transport(transport_base)
 
374
        result = client_medium.remote_path_from_transport(t)
364
375
        self.assertEqual(expected, result)
365
376
 
366
377
    def test_remote_path_from_transport(self):
377
388
        a given transport_base and relpath of that transport.  (Note that
378
389
        HttpTransportBase is a subclass of SmartClientMedium)
379
390
        """
380
 
        base_transport = get_transport(transport_base)
 
391
        base_transport = transport.get_transport(transport_base)
381
392
        client_medium = base_transport.get_smart_medium()
382
393
        cloned_transport = base_transport.clone(relpath)
383
394
        result = client_medium.remote_path_from_transport(cloned_transport)
450
461
        client.add_expected_call(
451
462
            'BzrDir.open_branchV3', ('quack/',),
452
463
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
464
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
465
            _client=client)
455
466
        result = a_bzrdir.cloning_metadir()
456
467
        # We should have got a control dir matching the referenced branch.
469
480
        client.add_expected_call(
470
481
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
482
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
483
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
484
            _client=client)
474
485
        result = a_bzrdir.cloning_metadir()
475
486
        # We should have got a reference control dir with default branch and
480
491
        self.assertEqual(None, result._branch_format)
481
492
        self.assertFinished(client)
482
493
 
 
494
    def test_unknown(self):
 
495
        transport = self.get_transport('quack')
 
496
        referenced = self.make_branch('referenced')
 
497
        expected = referenced.bzrdir.cloning_metadir()
 
498
        client = FakeClient(transport.base)
 
499
        client.add_expected_call(
 
500
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
501
            'success', ('unknown', 'unknown', ('branch', ''))),
 
502
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
503
            _client=client)
 
504
        self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
 
505
 
 
506
 
 
507
class TestBzrDirCheckoutMetaDir(TestRemote):
 
508
 
 
509
    def test__get_checkout_format(self):
 
510
        transport = MemoryTransport()
 
511
        client = FakeClient(transport.base)
 
512
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
513
        control_name = reference_bzrdir_format.network_name()
 
514
        client.add_expected_call(
 
515
            'BzrDir.checkout_metadir', ('quack/', ),
 
516
            'success', (control_name, '', ''))
 
517
        transport.mkdir('quack')
 
518
        transport = transport.clone('quack')
 
519
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
520
            _client=client)
 
521
        result = a_bzrdir.checkout_metadir()
 
522
        # We should have got a reference control dir with default branch and
 
523
        # repository formats.
 
524
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
525
        self.assertEqual(None, result._repository_format)
 
526
        self.assertEqual(None, result._branch_format)
 
527
        self.assertFinished(client)
 
528
 
 
529
    def test_unknown_format(self):
 
530
        transport = MemoryTransport()
 
531
        client = FakeClient(transport.base)
 
532
        client.add_expected_call(
 
533
            'BzrDir.checkout_metadir', ('quack/',),
 
534
            'success', ('dontknow', '', ''))
 
535
        transport.mkdir('quack')
 
536
        transport = transport.clone('quack')
 
537
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
538
            _client=client)
 
539
        self.assertRaises(errors.UnknownFormatError,
 
540
            a_bzrdir.checkout_metadir)
 
541
        self.assertFinished(client)
 
542
 
 
543
 
 
544
class TestBzrDirGetBranches(TestRemote):
 
545
 
 
546
    def test_get_branches(self):
 
547
        transport = MemoryTransport()
 
548
        client = FakeClient(transport.base)
 
549
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
550
        branch_name = reference_bzrdir_format.get_branch_format().network_name()
 
551
        client.add_success_response_with_body(
 
552
            bencode.bencode({
 
553
                "foo": ("branch", branch_name),
 
554
                "": ("branch", branch_name)}), "success")
 
555
        client.add_success_response(
 
556
            'ok', '', 'no', 'no', 'no',
 
557
                reference_bzrdir_format.repository_format.network_name())
 
558
        client.add_error_response('NotStacked')
 
559
        client.add_success_response(
 
560
            'ok', '', 'no', 'no', 'no',
 
561
                reference_bzrdir_format.repository_format.network_name())
 
562
        client.add_error_response('NotStacked')
 
563
        transport.mkdir('quack')
 
564
        transport = transport.clone('quack')
 
565
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
566
            _client=client)
 
567
        result = a_bzrdir.get_branches()
 
568
        self.assertEquals(set(["", "foo"]), set(result.keys()))
 
569
        self.assertEqual(
 
570
            [('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
 
571
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
572
             ('call', 'Branch.get_stacked_on_url', ('quack/', )),
 
573
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
574
             ('call', 'Branch.get_stacked_on_url', ('quack/', ))],
 
575
            client._calls)
 
576
 
 
577
 
 
578
class TestBzrDirDestroyBranch(TestRemote):
 
579
 
 
580
    def test_destroy_default(self):
 
581
        transport = self.get_transport('quack')
 
582
        referenced = self.make_branch('referenced')
 
583
        client = FakeClient(transport.base)
 
584
        client.add_expected_call(
 
585
            'BzrDir.destroy_branch', ('quack/', ),
 
586
            'success', ('ok',)),
 
587
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
588
            _client=client)
 
589
        a_bzrdir.destroy_branch()
 
590
        self.assertFinished(client)
 
591
 
 
592
 
 
593
class TestBzrDirHasWorkingTree(TestRemote):
 
594
 
 
595
    def test_has_workingtree(self):
 
596
        transport = self.get_transport('quack')
 
597
        client = FakeClient(transport.base)
 
598
        client.add_expected_call(
 
599
            'BzrDir.has_workingtree', ('quack/',),
 
600
            'success', ('yes',)),
 
601
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
602
            _client=client)
 
603
        self.assertTrue(a_bzrdir.has_workingtree())
 
604
        self.assertFinished(client)
 
605
 
 
606
    def test_no_workingtree(self):
 
607
        transport = self.get_transport('quack')
 
608
        client = FakeClient(transport.base)
 
609
        client.add_expected_call(
 
610
            'BzrDir.has_workingtree', ('quack/',),
 
611
            'success', ('no',)),
 
612
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
613
            _client=client)
 
614
        self.assertFalse(a_bzrdir.has_workingtree())
 
615
        self.assertFinished(client)
 
616
 
 
617
 
 
618
class TestBzrDirDestroyRepository(TestRemote):
 
619
 
 
620
    def test_destroy_repository(self):
 
621
        transport = self.get_transport('quack')
 
622
        client = FakeClient(transport.base)
 
623
        client.add_expected_call(
 
624
            'BzrDir.destroy_repository', ('quack/',),
 
625
            'success', ('ok',)),
 
626
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
627
            _client=client)
 
628
        a_bzrdir.destroy_repository()
 
629
        self.assertFinished(client)
 
630
 
483
631
 
484
632
class TestBzrDirOpen(TestRemote):
485
633
 
495
643
        client.add_expected_call(
496
644
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
645
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
646
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
647
        self.assertFinished(client)
500
648
 
501
649
    def test_present_without_workingtree(self):
502
650
        client, transport = self.make_fake_client_and_transport()
503
651
        client.add_expected_call(
504
652
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
653
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
654
            _client=client, _force_probe=True)
507
655
        self.assertIsInstance(bd, RemoteBzrDir)
508
656
        self.assertFalse(bd.has_workingtree())
513
661
        client, transport = self.make_fake_client_and_transport()
514
662
        client.add_expected_call(
515
663
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
664
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
665
            _client=client, _force_probe=True)
518
666
        self.assertIsInstance(bd, RemoteBzrDir)
519
667
        self.assertTrue(bd.has_workingtree())
526
674
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
675
        client.add_expected_call(
528
676
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
677
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
678
            _client=client, _force_probe=True)
531
679
        self.assertIsInstance(bd, RemoteBzrDir)
532
680
        self.assertFinished(client)
548
696
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
697
        client.add_expected_call(
550
698
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
699
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
700
            _client=client, _force_probe=True)
553
701
        self.assertIsInstance(bd, RemoteBzrDir)
554
702
        self.assertFinished(client)
585
733
        client.add_expected_call(
586
734
            'Branch.get_stacked_on_url', ('quack/',),
587
735
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
736
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
737
            _client=client)
590
738
        result = bzrdir.open_branch()
591
739
        self.assertIsInstance(result, RemoteBranch)
598
746
        transport = transport.clone('quack')
599
747
        client = FakeClient(transport.base)
600
748
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
749
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
750
            _client=client)
603
751
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
752
        self.assertEqual(
609
757
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
758
        # branch opening, not any other network requests.
611
759
        calls = []
612
 
        def open_branch():
 
760
        def open_branch(name=None, possible_transports=None):
613
761
            calls.append("Called")
614
762
            return "a-branch"
615
763
        transport = MemoryTransport()
616
764
        # no requests on the network - catches other api calls being made.
617
765
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
766
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
767
            _client=client)
620
768
        # patch the open_branch call to record that it was called.
621
769
        bzrdir.open_branch = open_branch
640
788
        client.add_expected_call(
641
789
            'Branch.get_stacked_on_url', ('~hello/',),
642
790
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
791
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
792
            _client=client)
645
793
        result = bzrdir.open_branch()
646
794
        self.assertFinished(client)
663
811
        client.add_success_response(
664
812
            'ok', '', rich_response, subtree_response, external_lookup,
665
813
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
814
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
815
            _client=client)
668
816
        result = bzrdir.open_repository()
669
817
        self.assertEqual(
686
834
        old.
687
835
        """
688
836
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
837
            RemoteBzrProber.probe_transport, OldServerTransport())
690
838
 
691
839
 
692
840
class TestBzrDirCreateBranch(TestRemote):
715
863
            'BzrDir.create_branch', ('quack/', network_name),
716
864
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
865
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
866
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
867
            _client=client)
720
868
        branch = a_bzrdir.create_branch()
721
869
        # We should have got a remote branch
724
872
        format = branch._format
725
873
        self.assertEqual(network_name, format.network_name())
726
874
 
 
875
    def test_already_open_repo_and_reused_medium(self):
 
876
        """Bug 726584: create_branch(..., repository=repo) should work
 
877
        regardless of what the smart medium's base URL is.
 
878
        """
 
879
        self.transport_server = test_server.SmartTCPServer_for_testing
 
880
        transport = self.get_transport('.')
 
881
        repo = self.make_repository('quack')
 
882
        # Client's medium rooted a transport root (not at the bzrdir)
 
883
        client = FakeClient(transport.base)
 
884
        transport = transport.clone('quack')
 
885
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
886
        reference_format = reference_bzrdir_format.get_branch_format()
 
887
        network_name = reference_format.network_name()
 
888
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
889
        reference_repo_name = reference_repo_fmt.network_name()
 
890
        client.add_expected_call(
 
891
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
892
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
893
            reference_repo_name))
 
894
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
895
            _client=client)
 
896
        branch = a_bzrdir.create_branch(repository=repo)
 
897
        # We should have got a remote branch
 
898
        self.assertIsInstance(branch, remote.RemoteBranch)
 
899
        # its format should have the settings from the response
 
900
        format = branch._format
 
901
        self.assertEqual(network_name, format.network_name())
 
902
 
727
903
 
728
904
class TestBzrDirCreateRepository(TestRemote):
729
905
 
750
926
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
927
                'False'),
752
928
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
929
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
930
            _client=client)
755
931
        repo = a_bzrdir.create_repository()
756
932
        # We should have got a remote repository
779
955
        # name.
780
956
        client.add_success_response_with_body(
781
957
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
958
        client.add_success_response('stat', '0', '65535')
782
959
        client.add_success_response_with_body(
783
960
            reference_format.get_format_string(), 'ok')
784
961
        # PackRepository wants to do a stat
785
962
        client.add_success_response('stat', '0', '65535')
786
963
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
964
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
965
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
966
            _client=client)
790
967
        repo = bzrdir.open_repository()
791
968
        self.assertEqual(
793
970
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
971
             ('call', 'BzrDir.find_repository', ('quack/',)),
795
972
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
973
             ('call', 'stat', ('/quack/.bzr',)),
796
974
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
975
             ('call', 'stat', ('/quack/.bzr/repository',)),
798
976
             ],
812
990
        # name.
813
991
        client.add_success_response_with_body(
814
992
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
993
        client.add_success_response('stat', '0', '65535')
815
994
        client.add_success_response_with_body(
816
995
            reference_format.get_format_string(), 'ok')
817
996
        # PackRepository wants to do a stat
818
997
        client.add_success_response('stat', '0', '65535')
819
998
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
999
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
1000
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
1001
            _client=client)
823
1002
        repo = bzrdir.open_repository()
824
1003
        self.assertEqual(
825
1004
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
1005
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
1006
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
1007
             ('call', 'stat', ('/quack/.bzr',)),
828
1008
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
1009
             ('call', 'stat', ('/quack/.bzr/repository',)),
830
1010
             ],
839
1019
        transport = transport.clone('quack')
840
1020
        client = FakeClient(transport.base)
841
1021
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1022
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
1023
            _client=client)
844
1024
        repo = bzrdir.open_repository()
845
1025
        self.assertEqual(
852
1032
 
853
1033
    def test_success(self):
854
1034
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1035
        fmt = RemoteBzrDirFormat()
856
1036
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1037
        transport = self.get_transport()
858
1038
        client = FakeClient(transport.base)
874
1054
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1055
        corresponding error from the client.
876
1056
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1057
        fmt = RemoteBzrDirFormat()
878
1058
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1059
        transport = self.get_transport()
880
1060
        client = FakeClient(transport.base)
898
1078
        """Integration test for error translation."""
899
1079
        transport = self.make_smart_server('foo')
900
1080
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1081
        fmt = RemoteBzrDirFormat()
902
1082
        err = self.assertRaises(errors.NoSuchFile,
903
1083
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1084
 
935
1115
 
936
1116
    def make_remote_bzrdir(self, transport, client):
937
1117
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1118
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1119
            _client=client)
940
1120
 
941
1121
 
967
1147
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1148
 
969
1149
 
 
1150
class TestBranchBreakLock(RemoteBranchTestCase):
 
1151
 
 
1152
    def test_break_lock(self):
 
1153
        transport_path = 'quack'
 
1154
        transport = MemoryTransport()
 
1155
        client = FakeClient(transport.base)
 
1156
        client.add_expected_call(
 
1157
            'Branch.get_stacked_on_url', ('quack/',),
 
1158
            'error', ('NotStacked',))
 
1159
        client.add_expected_call(
 
1160
            'Branch.break_lock', ('quack/',),
 
1161
            'success', ('ok',))
 
1162
        transport.mkdir('quack')
 
1163
        transport = transport.clone('quack')
 
1164
        branch = self.make_remote_branch(transport, client)
 
1165
        branch.break_lock()
 
1166
        self.assertFinished(client)
 
1167
 
 
1168
 
 
1169
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1170
 
 
1171
    def test_get_physical_lock_status_yes(self):
 
1172
        transport = MemoryTransport()
 
1173
        client = FakeClient(transport.base)
 
1174
        client.add_expected_call(
 
1175
            'Branch.get_stacked_on_url', ('quack/',),
 
1176
            'error', ('NotStacked',))
 
1177
        client.add_expected_call(
 
1178
            'Branch.get_physical_lock_status', ('quack/',),
 
1179
            'success', ('yes',))
 
1180
        transport.mkdir('quack')
 
1181
        transport = transport.clone('quack')
 
1182
        branch = self.make_remote_branch(transport, client)
 
1183
        result = branch.get_physical_lock_status()
 
1184
        self.assertFinished(client)
 
1185
        self.assertEqual(True, result)
 
1186
 
 
1187
    def test_get_physical_lock_status_no(self):
 
1188
        transport = MemoryTransport()
 
1189
        client = FakeClient(transport.base)
 
1190
        client.add_expected_call(
 
1191
            'Branch.get_stacked_on_url', ('quack/',),
 
1192
            'error', ('NotStacked',))
 
1193
        client.add_expected_call(
 
1194
            'Branch.get_physical_lock_status', ('quack/',),
 
1195
            'success', ('no',))
 
1196
        transport.mkdir('quack')
 
1197
        transport = transport.clone('quack')
 
1198
        branch = self.make_remote_branch(transport, client)
 
1199
        result = branch.get_physical_lock_status()
 
1200
        self.assertFinished(client)
 
1201
        self.assertEqual(False, result)
 
1202
 
 
1203
 
970
1204
class TestBranchGetParent(RemoteBranchTestCase):
971
1205
 
972
1206
    def test_no_parent(self):
1062
1296
        verb = 'Branch.set_parent_location'
1063
1297
        self.disable_verb(verb)
1064
1298
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1299
        self.assertLength(13, self.hpss_calls)
1066
1300
 
1067
1301
 
1068
1302
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1143
1377
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1378
 
1145
1379
 
 
1380
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1381
 
 
1382
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1383
        transport = MemoryTransport()
 
1384
        client = FakeClient(transport.base)
 
1385
        client.add_expected_call(
 
1386
            'Branch.get_stacked_on_url', ('quack/',),
 
1387
            'error', ('NotStacked',))
 
1388
        client.add_expected_call(
 
1389
            'Branch.last_revision_info', ('quack/',),
 
1390
            'success', ('ok', '1', 'rev-tip'))
 
1391
        client.add_expected_call(
 
1392
            'Branch.get_config_file', ('quack/',),
 
1393
            'success', ('ok',), '')
 
1394
        transport.mkdir('quack')
 
1395
        transport = transport.clone('quack')
 
1396
        branch = self.make_remote_branch(transport, client)
 
1397
        result = branch.heads_to_fetch()
 
1398
        self.assertFinished(client)
 
1399
        self.assertEqual((set(['rev-tip']), set()), result)
 
1400
 
 
1401
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1402
        transport = MemoryTransport()
 
1403
        client = FakeClient(transport.base)
 
1404
        client.add_expected_call(
 
1405
            'Branch.get_stacked_on_url', ('quack/',),
 
1406
            'error', ('NotStacked',))
 
1407
        client.add_expected_call(
 
1408
            'Branch.last_revision_info', ('quack/',),
 
1409
            'success', ('ok', '1', 'rev-tip'))
 
1410
        client.add_expected_call(
 
1411
            'Branch.get_config_file', ('quack/',),
 
1412
            'success', ('ok',), 'branch.fetch_tags = True')
 
1413
        # XXX: this will break if the default format's serialization of tags
 
1414
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1415
        client.add_expected_call(
 
1416
            'Branch.get_tags_bytes', ('quack/',),
 
1417
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1418
        transport.mkdir('quack')
 
1419
        transport = transport.clone('quack')
 
1420
        branch = self.make_remote_branch(transport, client)
 
1421
        result = branch.heads_to_fetch()
 
1422
        self.assertFinished(client)
 
1423
        self.assertEqual(
 
1424
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1425
 
 
1426
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1427
        transport = MemoryTransport()
 
1428
        client = FakeClient(transport.base)
 
1429
        client.add_expected_call(
 
1430
            'Branch.get_stacked_on_url', ('quack/',),
 
1431
            'error', ('NotStacked',))
 
1432
        client.add_expected_call(
 
1433
            'Branch.heads_to_fetch', ('quack/',),
 
1434
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1435
        transport.mkdir('quack')
 
1436
        transport = transport.clone('quack')
 
1437
        branch = self.make_remote_branch(transport, client)
 
1438
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1439
        result = branch.heads_to_fetch()
 
1440
        self.assertFinished(client)
 
1441
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1442
 
 
1443
    def make_branch_with_tags(self):
 
1444
        self.setup_smart_server_with_call_log()
 
1445
        # Make a branch with a single revision.
 
1446
        builder = self.make_branch_builder('foo')
 
1447
        builder.start_series()
 
1448
        builder.build_snapshot('tip', None, [
 
1449
            ('add', ('', 'root-id', 'directory', ''))])
 
1450
        builder.finish_series()
 
1451
        branch = builder.get_branch()
 
1452
        # Add two tags to that branch
 
1453
        branch.tags.set_tag('tag-1', 'rev-1')
 
1454
        branch.tags.set_tag('tag-2', 'rev-2')
 
1455
        return branch
 
1456
 
 
1457
    def test_backwards_compatible(self):
 
1458
        branch = self.make_branch_with_tags()
 
1459
        c = branch.get_config_stack()
 
1460
        c.set('branch.fetch_tags', True)
 
1461
        self.addCleanup(branch.lock_read().unlock)
 
1462
        # Disable the heads_to_fetch verb
 
1463
        verb = 'Branch.heads_to_fetch'
 
1464
        self.disable_verb(verb)
 
1465
        self.reset_smart_call_log()
 
1466
        result = branch.heads_to_fetch()
 
1467
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1468
        self.assertEqual(
 
1469
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1470
             'Branch.get_tags_bytes'],
 
1471
            [call.call.method for call in self.hpss_calls])
 
1472
 
 
1473
    def test_backwards_compatible_no_tags(self):
 
1474
        branch = self.make_branch_with_tags()
 
1475
        c = branch.get_config_stack()
 
1476
        c.set('branch.fetch_tags', False)
 
1477
        self.addCleanup(branch.lock_read().unlock)
 
1478
        # Disable the heads_to_fetch verb
 
1479
        verb = 'Branch.heads_to_fetch'
 
1480
        self.disable_verb(verb)
 
1481
        self.reset_smart_call_log()
 
1482
        result = branch.heads_to_fetch()
 
1483
        self.assertEqual((set(['tip']), set()), result)
 
1484
        self.assertEqual(
 
1485
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1486
            [call.call.method for call in self.hpss_calls])
 
1487
 
 
1488
 
1146
1489
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1490
 
1148
1491
    def test_empty_branch(self):
1203
1546
        client.add_expected_call(
1204
1547
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1548
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1549
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1550
            _client=client)
1208
1551
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1552
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1579
        # this will also do vfs access, but that goes direct to the transport
1237
1580
        # and isn't seen by the FakeClient.
1238
1581
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1582
            RemoteBzrDirFormat(), _client=client)
1240
1583
        branch = bzrdir.open_branch()
1241
1584
        result = branch.get_stacked_on_url()
1242
1585
        self.assertEqual('../base', result)
1269
1612
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1613
            'success', ('ok', '../base'))
1271
1614
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1615
            RemoteBzrDirFormat(), _client=client)
1273
1616
        branch = bzrdir.open_branch()
1274
1617
        result = branch.get_stacked_on_url()
1275
1618
        self.assertEqual('../base', result)
1283
1626
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1627
 
1285
1628
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1629
        # _set_last_revision_info('null:') is translated to calling
1287
1630
        # Branch.set_last_revision(path, '') on the wire.
1288
1631
        transport = MemoryTransport()
1289
1632
        transport.mkdir('branch')
1307
1650
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1651
            'success', ('ok',))
1309
1652
        branch = self.make_remote_branch(transport, client)
1310
 
        # This is a hack to work around the problem that RemoteBranch currently
1311
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1312
 
        branch._ensure_real = lambda: None
1313
1653
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1654
        result = branch._set_last_revision(NULL_REVISION)
1315
1655
        branch.unlock()
1316
1656
        self.assertEqual(None, result)
1317
1657
        self.assertFinished(client)
1318
1658
 
1319
1659
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1660
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1661
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1662
        transport = MemoryTransport()
1323
1663
        transport.mkdir('branch')
1344
1684
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1685
            'success', ('ok',))
1346
1686
        branch = self.make_remote_branch(transport, client)
1347
 
        # This is a hack to work around the problem that RemoteBranch currently
1348
 
        # unnecessarily invokes _ensure_real upon a call to lock_write.
1349
 
        branch._ensure_real = lambda: None
1350
1687
        # Lock the branch, reset the record of remote calls.
1351
1688
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1689
        result = branch._set_last_revision('rev-id2')
1353
1690
        branch.unlock()
1354
1691
        self.assertEqual(None, result)
1355
1692
        self.assertFinished(client)
1385
1722
        branch = self.make_remote_branch(transport, client)
1386
1723
        branch.lock_write()
1387
1724
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1725
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1726
        branch.unlock()
1390
1727
        self.assertFinished(client)
1391
1728
 
1419
1756
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1757
            'success', ('ok',))
1421
1758
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1759
        branch.lock_write()
1424
1760
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1761
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1762
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1763
            errors.TipChangeRejected,
 
1764
            branch._set_last_revision, 'rev-id')
1428
1765
        # The UTF-8 message from the response has been decoded into a unicode
1429
1766
        # object.
1430
1767
        self.assertIsInstance(err.msg, unicode)
1618
1955
    def test_get_multi_line_branch_conf(self):
1619
1956
        # Make sure that multiple-line branch.conf files are supported
1620
1957
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1958
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1959
        client = FakeClient()
1623
1960
        client.add_expected_call(
1624
1961
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1989
        branch.unlock()
1653
1990
        self.assertFinished(client)
1654
1991
 
 
1992
    def test_set_option_with_dict(self):
 
1993
        client = FakeClient()
 
1994
        client.add_expected_call(
 
1995
            'Branch.get_stacked_on_url', ('memory:///',),
 
1996
            'error', ('NotStacked',),)
 
1997
        client.add_expected_call(
 
1998
            'Branch.lock_write', ('memory:///', '', ''),
 
1999
            'success', ('ok', 'branch token', 'repo token'))
 
2000
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
2001
        client.add_expected_call(
 
2002
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
2003
            'repo token', encoded_dict_value, 'foo', ''),
 
2004
            'success', ())
 
2005
        client.add_expected_call(
 
2006
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2007
            'success', ('ok',))
 
2008
        transport = MemoryTransport()
 
2009
        branch = self.make_remote_branch(transport, client)
 
2010
        branch.lock_write()
 
2011
        config = branch._get_config()
 
2012
        config.set_option(
 
2013
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2014
            'foo')
 
2015
        branch.unlock()
 
2016
        self.assertFinished(client)
 
2017
 
1655
2018
    def test_backwards_compat_set_option(self):
1656
2019
        self.setup_smart_server_with_call_log()
1657
2020
        branch = self.make_branch('.')
1661
2024
        self.addCleanup(branch.unlock)
1662
2025
        self.reset_smart_call_log()
1663
2026
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2027
        self.assertLength(11, self.hpss_calls)
1665
2028
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2029
 
 
2030
    def test_backwards_compat_set_option_with_dict(self):
 
2031
        self.setup_smart_server_with_call_log()
 
2032
        branch = self.make_branch('.')
 
2033
        verb = 'Branch.set_config_option_dict'
 
2034
        self.disable_verb(verb)
 
2035
        branch.lock_write()
 
2036
        self.addCleanup(branch.unlock)
 
2037
        self.reset_smart_call_log()
 
2038
        config = branch._get_config()
 
2039
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2040
        config.set_option(value_dict, 'name')
 
2041
        self.assertLength(11, self.hpss_calls)
 
2042
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2043
 
 
2044
 
 
2045
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2046
 
 
2047
    def test_get_branch_conf(self):
 
2048
        # in an empty branch we decode the response properly
 
2049
        client = FakeClient()
 
2050
        client.add_expected_call(
 
2051
            'Branch.get_stacked_on_url', ('memory:///',),
 
2052
            'error', ('NotStacked',),)
 
2053
        client.add_success_response_with_body('# config file body', 'ok')
 
2054
        transport = MemoryTransport()
 
2055
        branch = self.make_remote_branch(transport, client)
 
2056
        config = branch.get_config_stack()
 
2057
        config.get("email")
 
2058
        config.get("log_format")
 
2059
        self.assertEqual(
 
2060
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2061
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2062
            client._calls)
 
2063
 
 
2064
    def test_set_branch_conf(self):
 
2065
        client = FakeClient()
 
2066
        client.add_expected_call(
 
2067
            'Branch.get_stacked_on_url', ('memory:///',),
 
2068
            'error', ('NotStacked',),)
 
2069
        client.add_expected_call(
 
2070
            'Branch.lock_write', ('memory:///', '', ''),
 
2071
            'success', ('ok', 'branch token', 'repo token'))
 
2072
        client.add_expected_call(
 
2073
            'Branch.get_config_file', ('memory:///', ),
 
2074
            'success', ('ok', ), "# line 1\n")
 
2075
        client.add_expected_call(
 
2076
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2077
            'repo token'),
 
2078
            'success', ('ok',))
 
2079
        client.add_expected_call(
 
2080
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2081
            'success', ('ok',))
 
2082
        transport = MemoryTransport()
 
2083
        branch = self.make_remote_branch(transport, client)
 
2084
        branch.lock_write()
 
2085
        config = branch.get_config_stack()
 
2086
        config.set('email', 'The Dude <lebowski@example.com>')
 
2087
        branch.unlock()
 
2088
        self.assertFinished(client)
 
2089
        self.assertEqual(
 
2090
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2091
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2092
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2093
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2094
                 ('memory:///', 'branch token', 'repo token'),
 
2095
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2096
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2097
            client._calls)
 
2098
 
1667
2099
 
1668
2100
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2101
 
1683
2115
        self.assertFinished(client)
1684
2116
 
1685
2117
 
 
2118
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2119
 
 
2120
    def test_simple(self):
 
2121
        transport = MemoryTransport()
 
2122
        client = FakeClient(transport.base)
 
2123
        client.add_expected_call(
 
2124
            'Branch.get_stacked_on_url', ('quack/',),
 
2125
            'error', ('NotStacked',),)
 
2126
        client.add_expected_call(
 
2127
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2128
            'success', ('ok', '0',),)
 
2129
        client.add_expected_call(
 
2130
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2131
            'error', ('NoSuchRevision', 'unknown',),)
 
2132
        transport.mkdir('quack')
 
2133
        transport = transport.clone('quack')
 
2134
        branch = self.make_remote_branch(transport, client)
 
2135
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2136
        self.assertRaises(errors.NoSuchRevision,
 
2137
            branch.revision_id_to_revno, 'unknown')
 
2138
        self.assertFinished(client)
 
2139
 
 
2140
    def test_dotted(self):
 
2141
        transport = MemoryTransport()
 
2142
        client = FakeClient(transport.base)
 
2143
        client.add_expected_call(
 
2144
            'Branch.get_stacked_on_url', ('quack/',),
 
2145
            'error', ('NotStacked',),)
 
2146
        client.add_expected_call(
 
2147
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2148
            'success', ('ok', '0',),)
 
2149
        client.add_expected_call(
 
2150
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2151
            'error', ('NoSuchRevision', 'unknown',),)
 
2152
        transport.mkdir('quack')
 
2153
        transport = transport.clone('quack')
 
2154
        branch = self.make_remote_branch(transport, client)
 
2155
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2156
        self.assertRaises(errors.NoSuchRevision,
 
2157
            branch.revision_id_to_dotted_revno, 'unknown')
 
2158
        self.assertFinished(client)
 
2159
 
 
2160
    def test_dotted_no_smart_verb(self):
 
2161
        self.setup_smart_server_with_call_log()
 
2162
        branch = self.make_branch('.')
 
2163
        self.disable_verb('Branch.revision_id_to_revno')
 
2164
        self.reset_smart_call_log()
 
2165
        self.assertEquals((0, ),
 
2166
            branch.revision_id_to_dotted_revno('null:'))
 
2167
        self.assertLength(8, self.hpss_calls)
 
2168
 
 
2169
 
1686
2170
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2171
 
1688
2172
    def test__get_config(self):
1702
2186
        self.reset_smart_call_log()
1703
2187
        config = bzrdir.get_config()
1704
2188
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2189
        self.assertLength(4, self.hpss_calls)
1706
2190
 
1707
2191
    def test_backwards_compat_get_option(self):
1708
2192
        self.setup_smart_server_with_call_log()
1712
2196
        self.reset_smart_call_log()
1713
2197
        self.assertEqual(None,
1714
2198
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2199
        self.assertLength(4, self.hpss_calls)
1716
2200
 
1717
2201
 
1718
2202
class TestTransportIsReadonly(tests.TestCase):
1805
2289
        client = FakeClient(transport.base)
1806
2290
        transport = transport.clone(transport_path)
1807
2291
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2292
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2293
            _client=False)
1810
2294
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2295
        return repo, client
1819
2303
 
1820
2304
    def test_get_format_description(self):
1821
2305
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2306
        real_format = branch.format_registry.get_default()
1823
2307
        remote_format._network_name = real_format.network_name()
1824
2308
        self.assertEqual(remoted_description(real_format),
1825
2309
            remote_format.get_format_description())
1828
2312
class TestRepositoryFormat(TestRemoteRepository):
1829
2313
 
1830
2314
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2315
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2316
        true_format = RemoteRepositoryFormat()
1833
2317
        true_format._network_name = true_name
1834
2318
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2319
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2320
        false_format = RemoteRepositoryFormat()
1837
2321
        false_format._network_name = false_name
1838
2322
        self.assertEqual(False, false_format.fast_deltas)
1839
2323
 
1840
2324
    def test_get_format_description(self):
1841
2325
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2326
        real_format = repository.format_registry.get_default()
1843
2327
        remote_repo_format._network_name = real_format.network_name()
1844
2328
        self.assertEqual(remoted_description(real_format),
1845
2329
            remote_repo_format.get_format_description())
1846
2330
 
1847
2331
 
 
2332
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2333
 
 
2334
    def test_empty(self):
 
2335
        transport_path = 'quack'
 
2336
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2337
        client.add_success_response_with_body('', 'ok')
 
2338
        self.assertEquals([], repo.all_revision_ids())
 
2339
        self.assertEqual(
 
2340
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2341
             ('quack/',))],
 
2342
            client._calls)
 
2343
 
 
2344
    def test_with_some_content(self):
 
2345
        transport_path = 'quack'
 
2346
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2347
        client.add_success_response_with_body(
 
2348
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2349
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2350
            repo.all_revision_ids())
 
2351
        self.assertEqual(
 
2352
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2353
             ('quack/',))],
 
2354
            client._calls)
 
2355
 
 
2356
 
1848
2357
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2358
 
1850
2359
    def test_revid_none(self):
1903
2412
                         result)
1904
2413
 
1905
2414
 
 
2415
class TestRepositoryBreakLock(TestRemoteRepository):
 
2416
 
 
2417
    def test_break_lock(self):
 
2418
        transport_path = 'quack'
 
2419
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2420
        client.add_success_response('ok')
 
2421
        repo.break_lock()
 
2422
        self.assertEqual(
 
2423
            [('call', 'Repository.break_lock', ('quack/',))],
 
2424
            client._calls)
 
2425
 
 
2426
 
 
2427
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2428
 
 
2429
    def test_get_serializer_format(self):
 
2430
        transport_path = 'hill'
 
2431
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2432
        client.add_success_response('ok', '7')
 
2433
        self.assertEquals('7', repo.get_serializer_format())
 
2434
        self.assertEqual(
 
2435
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2436
              ('hill/', ))],
 
2437
            client._calls)
 
2438
 
 
2439
 
 
2440
class TestRepositoryReconcile(TestRemoteRepository):
 
2441
 
 
2442
    def test_reconcile(self):
 
2443
        transport_path = 'hill'
 
2444
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2445
        body = ("garbage_inventories: 2\n"
 
2446
                "inconsistent_parents: 3\n")
 
2447
        client.add_expected_call(
 
2448
            'Repository.lock_write', ('hill/', ''),
 
2449
            'success', ('ok', 'a token'))
 
2450
        client.add_success_response_with_body(body, 'ok')
 
2451
        reconciler = repo.reconcile()
 
2452
        self.assertEqual(
 
2453
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2454
             ('call_expecting_body', 'Repository.reconcile',
 
2455
                ('hill/', 'a token'))],
 
2456
            client._calls)
 
2457
        self.assertEquals(2, reconciler.garbage_inventories)
 
2458
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2459
 
 
2460
 
 
2461
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2462
 
 
2463
    def test_text(self):
 
2464
        # ('ok',), body with signature text
 
2465
        transport_path = 'quack'
 
2466
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2467
        client.add_success_response_with_body(
 
2468
            'THETEXT', 'ok')
 
2469
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2470
        self.assertEqual(
 
2471
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2472
             ('quack/', 'revid'))],
 
2473
            client._calls)
 
2474
 
 
2475
    def test_no_signature(self):
 
2476
        transport_path = 'quick'
 
2477
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2478
        client.add_error_response('nosuchrevision', 'unknown')
 
2479
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2480
                "unknown")
 
2481
        self.assertEqual(
 
2482
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2483
              ('quick/', 'unknown'))],
 
2484
            client._calls)
 
2485
 
 
2486
 
1906
2487
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2488
 
1908
2489
    def test_get_graph(self):
1913
2494
        self.assertNotEqual(graph._parents_provider, repo)
1914
2495
 
1915
2496
 
 
2497
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2498
 
 
2499
    def test_add_signature_text(self):
 
2500
        transport_path = 'quack'
 
2501
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2502
        client.add_expected_call(
 
2503
            'Repository.lock_write', ('quack/', ''),
 
2504
            'success', ('ok', 'a token'))
 
2505
        client.add_expected_call(
 
2506
            'Repository.start_write_group', ('quack/', 'a token'),
 
2507
            'success', ('ok', ('token1', )))
 
2508
        client.add_expected_call(
 
2509
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2510
                'token1'),
 
2511
            'success', ('ok', ), None)
 
2512
        repo.lock_write()
 
2513
        repo.start_write_group()
 
2514
        self.assertIs(None,
 
2515
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2516
        self.assertEqual(
 
2517
            ('call_with_body_bytes_expecting_body',
 
2518
              'Repository.add_signature_text',
 
2519
                ('quack/', 'a token', 'rev1', 'token1'),
 
2520
              'every bloody emperor'),
 
2521
            client._calls[-1])
 
2522
 
 
2523
 
1916
2524
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2525
 
1918
2526
    def test_get_parent_map_caching(self):
1968
2576
        parents = repo.get_parent_map([rev_id])
1969
2577
        self.assertEqual(
1970
2578
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2579
              'Repository.get_parent_map',
 
2580
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2581
             ('disconnect medium',),
1974
2582
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2583
              ('quack/', ''))],
2095
2703
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2704
        self.assertLength(0, self.hpss_calls)
2097
2705
 
 
2706
    def test_exposes_get_cached_parent_map(self):
 
2707
        """RemoteRepository exposes get_cached_parent_map from
 
2708
        _unstacked_provider
 
2709
        """
 
2710
        r1 = u'\u0e33'.encode('utf8')
 
2711
        r2 = u'\u0dab'.encode('utf8')
 
2712
        lines = [' '.join([r2, r1]), r1]
 
2713
        encoded_body = bz2.compress('\n'.join(lines))
 
2714
 
 
2715
        transport_path = 'quack'
 
2716
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2717
        client.add_success_response_with_body(encoded_body, 'ok')
 
2718
        repo.lock_read()
 
2719
        # get_cached_parent_map should *not* trigger an RPC
 
2720
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2721
        self.assertEqual([], client._calls)
 
2722
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2723
        self.assertEqual({r1: (NULL_REVISION,)},
 
2724
            repo.get_cached_parent_map([r1]))
 
2725
        self.assertEqual(
 
2726
            [('call_with_body_bytes_expecting_body',
 
2727
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2728
              '\n\n0')],
 
2729
            client._calls)
 
2730
        repo.unlock()
 
2731
 
2098
2732
 
2099
2733
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2734
 
2115
2749
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2750
 
2117
2751
 
 
2752
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2753
 
 
2754
    def test_hpss_missing_revision(self):
 
2755
        transport_path = 'quack'
 
2756
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2757
        client.add_success_response_with_body(
 
2758
            '', 'ok', '10')
 
2759
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2760
            ['somerev1', 'anotherrev2'])
 
2761
        self.assertEqual(
 
2762
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2763
             ('quack/', ), "somerev1\nanotherrev2")],
 
2764
            client._calls)
 
2765
 
 
2766
    def test_hpss_get_single_revision(self):
 
2767
        transport_path = 'quack'
 
2768
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2769
        somerev1 = Revision("somerev1")
 
2770
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2771
        somerev1.timestamp = 1321828927
 
2772
        somerev1.timezone = -60
 
2773
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2774
        somerev1.message = "Message"
 
2775
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2776
            somerev1))
 
2777
        # Split up body into two bits to make sure the zlib compression object
 
2778
        # gets data fed twice.
 
2779
        client.add_success_response_with_body(
 
2780
                [body[:10], body[10:]], 'ok', '10')
 
2781
        revs = repo.get_revisions(['somerev1'])
 
2782
        self.assertEquals(revs, [somerev1])
 
2783
        self.assertEqual(
 
2784
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2785
             ('quack/', ), "somerev1")],
 
2786
            client._calls)
 
2787
 
 
2788
 
2118
2789
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2790
 
2120
2791
    def test_null_revision(self):
2257
2928
        self.setup_smart_server_with_call_log()
2258
2929
        tree = self.make_branch_and_memory_tree('.')
2259
2930
        tree.lock_write()
 
2931
        tree.add('')
2260
2932
        rev1 = tree.commit('First')
2261
2933
        rev2 = tree.commit('Second')
2262
2934
        tree.unlock()
2270
2942
                              call.call.method == verb])
2271
2943
 
2272
2944
 
 
2945
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2946
 
 
2947
    def test_has_signature_for_revision_id(self):
 
2948
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2949
        transport_path = 'quack'
 
2950
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2951
        client.add_success_response('yes')
 
2952
        result = repo.has_signature_for_revision_id('A')
 
2953
        self.assertEqual(
 
2954
            [('call', 'Repository.has_signature_for_revision_id',
 
2955
              ('quack/', 'A'))],
 
2956
            client._calls)
 
2957
        self.assertEqual(True, result)
 
2958
 
 
2959
    def test_is_not_shared(self):
 
2960
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2961
        transport_path = 'qwack'
 
2962
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2963
        client.add_success_response('no')
 
2964
        result = repo.has_signature_for_revision_id('A')
 
2965
        self.assertEqual(
 
2966
            [('call', 'Repository.has_signature_for_revision_id',
 
2967
              ('qwack/', 'A'))],
 
2968
            client._calls)
 
2969
        self.assertEqual(False, result)
 
2970
 
 
2971
 
 
2972
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2973
 
 
2974
    def test_get_physical_lock_status_yes(self):
 
2975
        transport_path = 'qwack'
 
2976
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2977
        client.add_success_response('yes')
 
2978
        result = repo.get_physical_lock_status()
 
2979
        self.assertEqual(
 
2980
            [('call', 'Repository.get_physical_lock_status',
 
2981
              ('qwack/', ))],
 
2982
            client._calls)
 
2983
        self.assertEqual(True, result)
 
2984
 
 
2985
    def test_get_physical_lock_status_no(self):
 
2986
        transport_path = 'qwack'
 
2987
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2988
        client.add_success_response('no')
 
2989
        result = repo.get_physical_lock_status()
 
2990
        self.assertEqual(
 
2991
            [('call', 'Repository.get_physical_lock_status',
 
2992
              ('qwack/', ))],
 
2993
            client._calls)
 
2994
        self.assertEqual(False, result)
 
2995
 
 
2996
 
2273
2997
class TestRepositoryIsShared(TestRemoteRepository):
2274
2998
 
2275
2999
    def test_is_shared(self):
2295
3019
        self.assertEqual(False, result)
2296
3020
 
2297
3021
 
 
3022
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3023
 
 
3024
    def test_make_working_trees(self):
 
3025
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3026
        transport_path = 'quack'
 
3027
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3028
        client.add_success_response('yes')
 
3029
        result = repo.make_working_trees()
 
3030
        self.assertEqual(
 
3031
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3032
            client._calls)
 
3033
        self.assertEqual(True, result)
 
3034
 
 
3035
    def test_no_working_trees(self):
 
3036
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3037
        transport_path = 'qwack'
 
3038
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3039
        client.add_success_response('no')
 
3040
        result = repo.make_working_trees()
 
3041
        self.assertEqual(
 
3042
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3043
            client._calls)
 
3044
        self.assertEqual(False, result)
 
3045
 
 
3046
 
2298
3047
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3048
 
2300
3049
    def test_lock_write(self):
2301
3050
        transport_path = 'quack'
2302
3051
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3052
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3053
        token = repo.lock_write().repository_token
2305
3054
        self.assertEqual(
2306
3055
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3056
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3057
        self.assertEqual('a token', token)
2309
3058
 
2310
3059
    def test_lock_write_already_locked(self):
2311
3060
        transport_path = 'quack'
2326
3075
            client._calls)
2327
3076
 
2328
3077
 
 
3078
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3079
 
 
3080
    def test_start_write_group(self):
 
3081
        transport_path = 'quack'
 
3082
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3083
        client.add_expected_call(
 
3084
            'Repository.lock_write', ('quack/', ''),
 
3085
            'success', ('ok', 'a token'))
 
3086
        client.add_expected_call(
 
3087
            'Repository.start_write_group', ('quack/', 'a token'),
 
3088
            'success', ('ok', ('token1', )))
 
3089
        repo.lock_write()
 
3090
        repo.start_write_group()
 
3091
 
 
3092
    def test_start_write_group_unsuspendable(self):
 
3093
        # Some repositories do not support suspending write
 
3094
        # groups. For those, fall back to the "real" repository.
 
3095
        transport_path = 'quack'
 
3096
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3097
        def stub_ensure_real():
 
3098
            client._calls.append(('_ensure_real',))
 
3099
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3100
        repo._ensure_real = stub_ensure_real
 
3101
        client.add_expected_call(
 
3102
            'Repository.lock_write', ('quack/', ''),
 
3103
            'success', ('ok', 'a token'))
 
3104
        client.add_expected_call(
 
3105
            'Repository.start_write_group', ('quack/', 'a token'),
 
3106
            'error', ('UnsuspendableWriteGroup',))
 
3107
        repo.lock_write()
 
3108
        repo.start_write_group()
 
3109
        self.assertEquals(client._calls[-2:], [ 
 
3110
            ('_ensure_real',),
 
3111
            ('start_write_group',)])
 
3112
 
 
3113
    def test_commit_write_group(self):
 
3114
        transport_path = 'quack'
 
3115
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3116
        client.add_expected_call(
 
3117
            'Repository.lock_write', ('quack/', ''),
 
3118
            'success', ('ok', 'a token'))
 
3119
        client.add_expected_call(
 
3120
            'Repository.start_write_group', ('quack/', 'a token'),
 
3121
            'success', ('ok', ['token1']))
 
3122
        client.add_expected_call(
 
3123
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3124
            'success', ('ok',))
 
3125
        repo.lock_write()
 
3126
        repo.start_write_group()
 
3127
        repo.commit_write_group()
 
3128
 
 
3129
    def test_abort_write_group(self):
 
3130
        transport_path = 'quack'
 
3131
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3132
        client.add_expected_call(
 
3133
            'Repository.lock_write', ('quack/', ''),
 
3134
            'success', ('ok', 'a token'))
 
3135
        client.add_expected_call(
 
3136
            'Repository.start_write_group', ('quack/', 'a token'),
 
3137
            'success', ('ok', ['token1']))
 
3138
        client.add_expected_call(
 
3139
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3140
            'success', ('ok',))
 
3141
        repo.lock_write()
 
3142
        repo.start_write_group()
 
3143
        repo.abort_write_group(False)
 
3144
 
 
3145
    def test_suspend_write_group(self):
 
3146
        transport_path = 'quack'
 
3147
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3148
        self.assertEquals([], repo.suspend_write_group())
 
3149
 
 
3150
    def test_resume_write_group(self):
 
3151
        transport_path = 'quack'
 
3152
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3153
        client.add_expected_call(
 
3154
            'Repository.lock_write', ('quack/', ''),
 
3155
            'success', ('ok', 'a token'))
 
3156
        client.add_expected_call(
 
3157
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3158
            'success', ('ok',))
 
3159
        repo.lock_write()
 
3160
        repo.resume_write_group(['token1'])
 
3161
 
 
3162
 
2329
3163
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3164
 
2331
3165
    def test_backwards_compat(self):
2390
3224
        self.assertEqual([], client._calls)
2391
3225
 
2392
3226
 
 
3227
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3228
    """Test Repository.iter_file_bytes."""
 
3229
 
 
3230
    def test_single(self):
 
3231
        transport_path = 'quack'
 
3232
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3233
        client.add_expected_call(
 
3234
            'Repository.iter_files_bytes', ('quack/', ),
 
3235
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3236
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3237
                "somerev", "myid")]):
 
3238
            self.assertEquals("myid", identifier)
 
3239
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3240
 
 
3241
    def test_missing(self):
 
3242
        transport_path = 'quack'
 
3243
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3244
        client.add_expected_call(
 
3245
            'Repository.iter_files_bytes',
 
3246
                ('quack/', ),
 
3247
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3248
            iter(["absent\0somefile\0somerev\n"]))
 
3249
        self.assertRaises(errors.RevisionNotPresent, list,
 
3250
                repo.iter_files_bytes(
 
3251
                [("somefile", "somerev", "myid")]))
 
3252
 
 
3253
 
2393
3254
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3255
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3256
    tests.
2402
3263
        the client is finished.
2403
3264
        """
2404
3265
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3266
        fmt = repository.format_registry.get_default()
2406
3267
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3268
        self.assertEqual([], resume_tokens)
2408
3269
        self.assertEqual(set(), missing_keys)
2508
3369
                return True
2509
3370
        repo._real_repository = FakeRealRepository()
2510
3371
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3372
        fmt = repository.format_registry.get_default()
2512
3373
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3374
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3375
        # Every record from the first inventory delta should have been sent to
2670
3531
        self.calls = calls
2671
3532
        self._pack_collection = _StubPackCollection(calls)
2672
3533
 
 
3534
    def start_write_group(self):
 
3535
        self.calls.append(('start_write_group',))
 
3536
 
2673
3537
    def is_in_write_group(self):
2674
3538
        return False
2675
3539
 
2734
3598
             ('pack collection autopack',)],
2735
3599
            client._calls)
2736
3600
 
 
3601
    def test_oom_error_reporting(self):
 
3602
        """An out-of-memory condition on the server is reported clearly"""
 
3603
        transport_path = 'quack'
 
3604
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3605
        client.add_expected_call(
 
3606
            'PackRepository.autopack', ('quack/',),
 
3607
            'error', ('MemoryError',))
 
3608
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3609
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3610
 
2737
3611
 
2738
3612
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3613
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3686
            detail='extra detail')
2813
3687
        self.assertEqual(expected_error, translated_error)
2814
3688
 
 
3689
    def test_norepository(self):
 
3690
        bzrdir = self.make_bzrdir('')
 
3691
        translated_error = self.translateTuple(('norepository',),
 
3692
            bzrdir=bzrdir)
 
3693
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3694
        self.assertEqual(expected_error, translated_error)
 
3695
 
2815
3696
    def test_LockContention(self):
2816
3697
        translated_error = self.translateTuple(('LockContention',))
2817
3698
        expected_error = errors.LockContention('(remote lock)')
2845
3726
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3727
        self.assertEqual(expected_error, translated_error)
2847
3728
 
 
3729
    def test_NotStacked(self):
 
3730
        branch = self.make_branch('')
 
3731
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3732
        expected_error = errors.NotStacked(branch)
 
3733
        self.assertEqual(expected_error, translated_error)
 
3734
 
2848
3735
    def test_ReadError_no_args(self):
2849
3736
        path = 'a path'
2850
3737
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3753
 
2867
3754
    def test_PermissionDenied_no_args(self):
2868
3755
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3756
        translated_error = self.translateTuple(('PermissionDenied',),
 
3757
            path=path)
2870
3758
        expected_error = errors.PermissionDenied(path)
2871
3759
        self.assertEqual(expected_error, translated_error)
2872
3760
 
2895
3783
        expected_error = errors.PermissionDenied(path, extra)
2896
3784
        self.assertEqual(expected_error, translated_error)
2897
3785
 
 
3786
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3787
 
 
3788
    def test_NoSuchFile_context_path(self):
 
3789
        local_path = "local path"
 
3790
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3791
            path=local_path)
 
3792
        expected_error = errors.ReadError(local_path)
 
3793
        self.assertEqual(expected_error, translated_error)
 
3794
 
 
3795
    def test_NoSuchFile_without_context(self):
 
3796
        remote_path = "remote path"
 
3797
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3798
        expected_error = errors.ReadError(remote_path)
 
3799
        self.assertEqual(expected_error, translated_error)
 
3800
 
 
3801
    def test_ReadOnlyError(self):
 
3802
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3803
        expected_error = errors.TransportNotPossible("readonly transport")
 
3804
        self.assertEqual(expected_error, translated_error)
 
3805
 
 
3806
    def test_MemoryError(self):
 
3807
        translated_error = self.translateTuple(('MemoryError',))
 
3808
        self.assertStartsWith(str(translated_error),
 
3809
            "remote server out of memory")
 
3810
 
 
3811
    def test_generic_IndexError_no_classname(self):
 
3812
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3813
        translated_error = self.translateErrorFromSmartServer(err)
 
3814
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3815
        self.assertEqual(expected_error, translated_error)
 
3816
 
 
3817
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3818
 
 
3819
    def test_generic_KeyError(self):
 
3820
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3821
        translated_error = self.translateErrorFromSmartServer(err)
 
3822
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3823
        self.assertEqual(expected_error, translated_error)
 
3824
 
2898
3825
 
2899
3826
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3827
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3972
        _, stacked = branch_factory()
3046
3973
        source = stacked.repository._get_source(target_repository_format)
3047
3974
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3975
        stacked.repository._ensure_real()
 
3976
        graph = stacked.repository.get_graph()
 
3977
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3978
                if r != NULL_REVISION]
 
3979
        revs.reverse()
 
3980
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3981
        self.reset_smart_call_log()
3051
3982
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3983
        # We trust that if a revision is in the stream the rest of the new
3055
3984
        # content for it is too, as per our main fetch tests; here we are
3056
3985
        # checking that the revisions are actually included at all, and their
3095
4024
        self.assertEqual(expected_revs, rev_ord)
3096
4025
        # Getting topological sort requires VFS calls still - one of which is
3097
4026
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4027
        self.assertLength(14, self.hpss_calls)
3099
4028
 
3100
4029
    def test_stacked_get_stream_groupcompress(self):
3101
4030
        # Repository._get_source.get_stream() from a stacked repository with
3142
4071
 
3143
4072
    def test_copy_content_into_avoids_revision_history(self):
3144
4073
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4074
        builder = self.make_branch_builder('remote')
 
4075
        builder.build_commit(message="Commit.")
3147
4076
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4077
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4078
        local.repository.fetch(remote_branch.repository)
3150
4079
        self.hpss_calls = []
3151
4080
        remote_branch.copy_content_into(local)
3152
4081
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4082
 
 
4083
    def test_fetch_everything_needs_just_one_call(self):
 
4084
        local = self.make_branch('local')
 
4085
        builder = self.make_branch_builder('remote')
 
4086
        builder.build_commit(message="Commit.")
 
4087
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4088
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4089
        self.hpss_calls = []
 
4090
        local.repository.fetch(
 
4091
            remote_branch.repository,
 
4092
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4093
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4094
 
 
4095
    def override_verb(self, verb_name, verb):
 
4096
        request_handlers = request.request_handlers
 
4097
        orig_verb = request_handlers.get(verb_name)
 
4098
        orig_info = request_handlers.get_info(verb_name)
 
4099
        request_handlers.register(verb_name, verb, override_existing=True)
 
4100
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4101
                override_existing=True, info=orig_info)
 
4102
 
 
4103
    def test_fetch_everything_backwards_compat(self):
 
4104
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4105
        
 
4106
        Pre-2.4 do not support 'everything' searches with the
 
4107
        Repository.get_stream_1.19 verb.
 
4108
        """
 
4109
        verb_log = []
 
4110
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4111
            """A version of the Repository.get_stream_1.19 verb patched to
 
4112
            reject 'everything' searches the way 2.3 and earlier do.
 
4113
            """
 
4114
            def recreate_search(self, repository, search_bytes,
 
4115
                                discard_excess=False):
 
4116
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4117
                if search_bytes == 'everything':
 
4118
                    return (None,
 
4119
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4120
                return super(OldGetStreamVerb,
 
4121
                        self).recreate_search(repository, search_bytes,
 
4122
                            discard_excess=discard_excess)
 
4123
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4124
        local = self.make_branch('local')
 
4125
        builder = self.make_branch_builder('remote')
 
4126
        builder.build_commit(message="Commit.")
 
4127
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4128
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4129
        self.hpss_calls = []
 
4130
        local.repository.fetch(
 
4131
            remote_branch.repository,
 
4132
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4133
        # make sure the overridden verb was used
 
4134
        self.assertLength(1, verb_log)
 
4135
        # more than one HPSS call is needed, but because it's a VFS callback
 
4136
        # its hard to predict exactly how many.
 
4137
        self.assertTrue(len(self.hpss_calls) > 1)
 
4138
 
 
4139
 
 
4140
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4141
    tests.TestCaseWithTransport):
 
4142
    """Ensure correct handling of bound_location modifications.
 
4143
 
 
4144
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4145
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4146
    happen in this context.
 
4147
    """
 
4148
 
 
4149
    def setUp(self):
 
4150
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4151
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4152
 
 
4153
    def make_master_and_checkout(self, master_name, checkout_name):
 
4154
        # Create the master branch and its associated checkout
 
4155
        self.master = self.make_branch_and_tree(master_name)
 
4156
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4157
        # Modify the master branch so there is something to update
 
4158
        self.master.commit('add stuff')
 
4159
        self.last_revid = self.master.commit('even more stuff')
 
4160
        self.bound_location = self.checkout.branch.get_bound_location()
 
4161
 
 
4162
    def assertUpdateSucceeds(self, new_location):
 
4163
        self.checkout.branch.set_bound_location(new_location)
 
4164
        self.checkout.update()
 
4165
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4166
 
 
4167
    def test_without_final_slash(self):
 
4168
        self.make_master_and_checkout('master', 'checkout')
 
4169
        # For unclear reasons some users have a bound_location without a final
 
4170
        # '/', simulate that by forcing such a value
 
4171
        self.assertEndsWith(self.bound_location, '/')
 
4172
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4173
 
 
4174
    def test_plus_sign(self):
 
4175
        self.make_master_and_checkout('+master', 'checkout')
 
4176
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4177
 
 
4178
    def test_tilda(self):
 
4179
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4180
        # interpretation
 
4181
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4182
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4183
 
 
4184
 
 
4185
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4186
 
 
4187
    def test_no_context(self):
 
4188
        class OutOfCoffee(errors.BzrError):
 
4189
            """A dummy exception for testing."""
 
4190
 
 
4191
            def __init__(self, urgency):
 
4192
                self.urgency = urgency
 
4193
        remote.no_context_error_translators.register("OutOfCoffee",
 
4194
            lambda err: OutOfCoffee(err.error_args[0]))
 
4195
        transport = MemoryTransport()
 
4196
        client = FakeClient(transport.base)
 
4197
        client.add_expected_call(
 
4198
            'Branch.get_stacked_on_url', ('quack/',),
 
4199
            'error', ('NotStacked',))
 
4200
        client.add_expected_call(
 
4201
            'Branch.last_revision_info',
 
4202
            ('quack/',),
 
4203
            'error', ('OutOfCoffee', 'low'))
 
4204
        transport.mkdir('quack')
 
4205
        transport = transport.clone('quack')
 
4206
        branch = self.make_remote_branch(transport, client)
 
4207
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4208
        self.assertFinished(client)
 
4209
 
 
4210
    def test_with_context(self):
 
4211
        class OutOfTea(errors.BzrError):
 
4212
            def __init__(self, branch, urgency):
 
4213
                self.branch = branch
 
4214
                self.urgency = urgency
 
4215
        remote.error_translators.register("OutOfTea",
 
4216
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4217
                find("branch")))
 
4218
        transport = MemoryTransport()
 
4219
        client = FakeClient(transport.base)
 
4220
        client.add_expected_call(
 
4221
            'Branch.get_stacked_on_url', ('quack/',),
 
4222
            'error', ('NotStacked',))
 
4223
        client.add_expected_call(
 
4224
            'Branch.last_revision_info',
 
4225
            ('quack/',),
 
4226
            'error', ('OutOfTea', 'low'))
 
4227
        transport.mkdir('quack')
 
4228
        transport = transport.clone('quack')
 
4229
        branch = self.make_remote_branch(transport, client)
 
4230
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4231
        self.assertFinished(client)
 
4232
 
 
4233
 
 
4234
class TestRepositoryPack(TestRemoteRepository):
 
4235
 
 
4236
    def test_pack(self):
 
4237
        transport_path = 'quack'
 
4238
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4239
        client.add_expected_call(
 
4240
            'Repository.lock_write', ('quack/', ''),
 
4241
            'success', ('ok', 'token'))
 
4242
        client.add_expected_call(
 
4243
            'Repository.pack', ('quack/', 'token', 'False'),
 
4244
            'success', ('ok',), )
 
4245
        client.add_expected_call(
 
4246
            'Repository.unlock', ('quack/', 'token'),
 
4247
            'success', ('ok', ))
 
4248
        repo.pack()
 
4249
 
 
4250
    def test_pack_with_hint(self):
 
4251
        transport_path = 'quack'
 
4252
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4253
        client.add_expected_call(
 
4254
            'Repository.lock_write', ('quack/', ''),
 
4255
            'success', ('ok', 'token'))
 
4256
        client.add_expected_call(
 
4257
            'Repository.pack', ('quack/', 'token', 'False'),
 
4258
            'success', ('ok',), )
 
4259
        client.add_expected_call(
 
4260
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4261
            'success', ('ok', ))
 
4262
        repo.pack(['hinta', 'hintb'])
 
4263
 
 
4264
 
 
4265
class TestRepositoryIterInventories(TestRemoteRepository):
 
4266
    """Test Repository.iter_inventories."""
 
4267
 
 
4268
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4269
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4270
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4271
 
 
4272
    def test_single_empty(self):
 
4273
        transport_path = 'quack'
 
4274
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4275
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4276
        repo._format = fmt
 
4277
        stream = [('inventory-deltas', [
 
4278
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4279
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4280
        client.add_expected_call(
 
4281
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4282
            'success', ('ok', ),
 
4283
            _stream_to_byte_stream(stream, fmt))
 
4284
        ret = list(repo.iter_inventories(["somerevid"]))
 
4285
        self.assertLength(1, ret)
 
4286
        inv = ret[0]
 
4287
        self.assertEquals("somerevid", inv.revision_id)
 
4288
 
 
4289
    def test_empty(self):
 
4290
        transport_path = 'quack'
 
4291
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4292
        ret = list(repo.iter_inventories([]))
 
4293
        self.assertEquals(ret, [])
 
4294
 
 
4295
    def test_missing(self):
 
4296
        transport_path = 'quack'
 
4297
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4298
        client.add_expected_call(
 
4299
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4300
            'success', ('ok', ), iter([]))
 
4301
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4302
            ["somerevid"]))