~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Wouter van Heyst
  • Date: 2012-01-25 19:07:22 UTC
  • mfrom: (6437.19.2 2.5)
  • mto: (6437.3.27 2.5)
  • mto: This revision was merged to the branch mainline in revision 6451.
  • Revision ID: larstiq@larstiq.dyndns.org-20120125190722-1bf3j0d6my1zd8v1
ensure files actually hit the disk under pypy

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(["", "foo"], 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
    def test_destroy_named(self):
 
593
        transport = self.get_transport('quack')
 
594
        referenced = self.make_branch('referenced')
 
595
        client = FakeClient(transport.base)
 
596
        client.add_expected_call(
 
597
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
598
            'success', ('ok',)),
 
599
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
600
            _client=client)
 
601
        a_bzrdir.destroy_branch("foo")
 
602
        self.assertFinished(client)
 
603
 
 
604
 
 
605
class TestBzrDirHasWorkingTree(TestRemote):
 
606
 
 
607
    def test_has_workingtree(self):
 
608
        transport = self.get_transport('quack')
 
609
        client = FakeClient(transport.base)
 
610
        client.add_expected_call(
 
611
            'BzrDir.has_workingtree', ('quack/',),
 
612
            'success', ('yes',)),
 
613
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
614
            _client=client)
 
615
        self.assertTrue(a_bzrdir.has_workingtree())
 
616
        self.assertFinished(client)
 
617
 
 
618
    def test_no_workingtree(self):
 
619
        transport = self.get_transport('quack')
 
620
        client = FakeClient(transport.base)
 
621
        client.add_expected_call(
 
622
            'BzrDir.has_workingtree', ('quack/',),
 
623
            'success', ('no',)),
 
624
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
625
            _client=client)
 
626
        self.assertFalse(a_bzrdir.has_workingtree())
 
627
        self.assertFinished(client)
 
628
 
 
629
 
 
630
class TestBzrDirDestroyRepository(TestRemote):
 
631
 
 
632
    def test_destroy_repository(self):
 
633
        transport = self.get_transport('quack')
 
634
        client = FakeClient(transport.base)
 
635
        client.add_expected_call(
 
636
            'BzrDir.destroy_repository', ('quack/',),
 
637
            'success', ('ok',)),
 
638
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
639
            _client=client)
 
640
        a_bzrdir.destroy_repository()
 
641
        self.assertFinished(client)
 
642
 
483
643
 
484
644
class TestBzrDirOpen(TestRemote):
485
645
 
495
655
        client.add_expected_call(
496
656
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
657
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
658
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
659
        self.assertFinished(client)
500
660
 
501
661
    def test_present_without_workingtree(self):
502
662
        client, transport = self.make_fake_client_and_transport()
503
663
        client.add_expected_call(
504
664
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
665
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
666
            _client=client, _force_probe=True)
507
667
        self.assertIsInstance(bd, RemoteBzrDir)
508
668
        self.assertFalse(bd.has_workingtree())
513
673
        client, transport = self.make_fake_client_and_transport()
514
674
        client.add_expected_call(
515
675
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
676
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
677
            _client=client, _force_probe=True)
518
678
        self.assertIsInstance(bd, RemoteBzrDir)
519
679
        self.assertTrue(bd.has_workingtree())
526
686
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
687
        client.add_expected_call(
528
688
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
689
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
690
            _client=client, _force_probe=True)
531
691
        self.assertIsInstance(bd, RemoteBzrDir)
532
692
        self.assertFinished(client)
548
708
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
709
        client.add_expected_call(
550
710
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
711
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
712
            _client=client, _force_probe=True)
553
713
        self.assertIsInstance(bd, RemoteBzrDir)
554
714
        self.assertFinished(client)
585
745
        client.add_expected_call(
586
746
            'Branch.get_stacked_on_url', ('quack/',),
587
747
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
748
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
749
            _client=client)
590
750
        result = bzrdir.open_branch()
591
751
        self.assertIsInstance(result, RemoteBranch)
598
758
        transport = transport.clone('quack')
599
759
        client = FakeClient(transport.base)
600
760
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
761
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
762
            _client=client)
603
763
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
764
        self.assertEqual(
609
769
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
770
        # branch opening, not any other network requests.
611
771
        calls = []
612
 
        def open_branch():
 
772
        def open_branch(name=None, possible_transports=None):
613
773
            calls.append("Called")
614
774
            return "a-branch"
615
775
        transport = MemoryTransport()
616
776
        # no requests on the network - catches other api calls being made.
617
777
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
778
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
779
            _client=client)
620
780
        # patch the open_branch call to record that it was called.
621
781
        bzrdir.open_branch = open_branch
640
800
        client.add_expected_call(
641
801
            'Branch.get_stacked_on_url', ('~hello/',),
642
802
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
803
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
804
            _client=client)
645
805
        result = bzrdir.open_branch()
646
806
        self.assertFinished(client)
663
823
        client.add_success_response(
664
824
            'ok', '', rich_response, subtree_response, external_lookup,
665
825
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
826
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
827
            _client=client)
668
828
        result = bzrdir.open_repository()
669
829
        self.assertEqual(
686
846
        old.
687
847
        """
688
848
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
849
            RemoteBzrProber.probe_transport, OldServerTransport())
690
850
 
691
851
 
692
852
class TestBzrDirCreateBranch(TestRemote):
715
875
            'BzrDir.create_branch', ('quack/', network_name),
716
876
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
877
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
878
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
879
            _client=client)
720
880
        branch = a_bzrdir.create_branch()
721
881
        # We should have got a remote branch
724
884
        format = branch._format
725
885
        self.assertEqual(network_name, format.network_name())
726
886
 
 
887
    def test_already_open_repo_and_reused_medium(self):
 
888
        """Bug 726584: create_branch(..., repository=repo) should work
 
889
        regardless of what the smart medium's base URL is.
 
890
        """
 
891
        self.transport_server = test_server.SmartTCPServer_for_testing
 
892
        transport = self.get_transport('.')
 
893
        repo = self.make_repository('quack')
 
894
        # Client's medium rooted a transport root (not at the bzrdir)
 
895
        client = FakeClient(transport.base)
 
896
        transport = transport.clone('quack')
 
897
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
898
        reference_format = reference_bzrdir_format.get_branch_format()
 
899
        network_name = reference_format.network_name()
 
900
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
901
        reference_repo_name = reference_repo_fmt.network_name()
 
902
        client.add_expected_call(
 
903
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
904
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
905
            reference_repo_name))
 
906
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
907
            _client=client)
 
908
        branch = a_bzrdir.create_branch(repository=repo)
 
909
        # We should have got a remote branch
 
910
        self.assertIsInstance(branch, remote.RemoteBranch)
 
911
        # its format should have the settings from the response
 
912
        format = branch._format
 
913
        self.assertEqual(network_name, format.network_name())
 
914
 
727
915
 
728
916
class TestBzrDirCreateRepository(TestRemote):
729
917
 
750
938
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
939
                'False'),
752
940
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
941
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
942
            _client=client)
755
943
        repo = a_bzrdir.create_repository()
756
944
        # We should have got a remote repository
779
967
        # name.
780
968
        client.add_success_response_with_body(
781
969
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
970
        client.add_success_response('stat', '0', '65535')
782
971
        client.add_success_response_with_body(
783
972
            reference_format.get_format_string(), 'ok')
784
973
        # PackRepository wants to do a stat
785
974
        client.add_success_response('stat', '0', '65535')
786
975
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
976
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
977
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
978
            _client=client)
790
979
        repo = bzrdir.open_repository()
791
980
        self.assertEqual(
793
982
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
983
             ('call', 'BzrDir.find_repository', ('quack/',)),
795
984
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
985
             ('call', 'stat', ('/quack/.bzr',)),
796
986
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
987
             ('call', 'stat', ('/quack/.bzr/repository',)),
798
988
             ],
812
1002
        # name.
813
1003
        client.add_success_response_with_body(
814
1004
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
1005
        client.add_success_response('stat', '0', '65535')
815
1006
        client.add_success_response_with_body(
816
1007
            reference_format.get_format_string(), 'ok')
817
1008
        # PackRepository wants to do a stat
818
1009
        client.add_success_response('stat', '0', '65535')
819
1010
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
1011
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
1012
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
1013
            _client=client)
823
1014
        repo = bzrdir.open_repository()
824
1015
        self.assertEqual(
825
1016
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
1017
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
1018
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
1019
             ('call', 'stat', ('/quack/.bzr',)),
828
1020
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
1021
             ('call', 'stat', ('/quack/.bzr/repository',)),
830
1022
             ],
839
1031
        transport = transport.clone('quack')
840
1032
        client = FakeClient(transport.base)
841
1033
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1034
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
1035
            _client=client)
844
1036
        repo = bzrdir.open_repository()
845
1037
        self.assertEqual(
852
1044
 
853
1045
    def test_success(self):
854
1046
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1047
        fmt = RemoteBzrDirFormat()
856
1048
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1049
        transport = self.get_transport()
858
1050
        client = FakeClient(transport.base)
874
1066
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1067
        corresponding error from the client.
876
1068
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1069
        fmt = RemoteBzrDirFormat()
878
1070
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1071
        transport = self.get_transport()
880
1072
        client = FakeClient(transport.base)
898
1090
        """Integration test for error translation."""
899
1091
        transport = self.make_smart_server('foo')
900
1092
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1093
        fmt = RemoteBzrDirFormat()
902
1094
        err = self.assertRaises(errors.NoSuchFile,
903
1095
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1096
 
935
1127
 
936
1128
    def make_remote_bzrdir(self, transport, client):
937
1129
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1130
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1131
            _client=client)
940
1132
 
941
1133
 
967
1159
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1160
 
969
1161
 
 
1162
class TestBranchBreakLock(RemoteBranchTestCase):
 
1163
 
 
1164
    def test_break_lock(self):
 
1165
        transport_path = 'quack'
 
1166
        transport = MemoryTransport()
 
1167
        client = FakeClient(transport.base)
 
1168
        client.add_expected_call(
 
1169
            'Branch.get_stacked_on_url', ('quack/',),
 
1170
            'error', ('NotStacked',))
 
1171
        client.add_expected_call(
 
1172
            'Branch.break_lock', ('quack/',),
 
1173
            'success', ('ok',))
 
1174
        transport.mkdir('quack')
 
1175
        transport = transport.clone('quack')
 
1176
        branch = self.make_remote_branch(transport, client)
 
1177
        branch.break_lock()
 
1178
        self.assertFinished(client)
 
1179
 
 
1180
 
 
1181
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1182
 
 
1183
    def test_get_physical_lock_status_yes(self):
 
1184
        transport = MemoryTransport()
 
1185
        client = FakeClient(transport.base)
 
1186
        client.add_expected_call(
 
1187
            'Branch.get_stacked_on_url', ('quack/',),
 
1188
            'error', ('NotStacked',))
 
1189
        client.add_expected_call(
 
1190
            'Branch.get_physical_lock_status', ('quack/',),
 
1191
            'success', ('yes',))
 
1192
        transport.mkdir('quack')
 
1193
        transport = transport.clone('quack')
 
1194
        branch = self.make_remote_branch(transport, client)
 
1195
        result = branch.get_physical_lock_status()
 
1196
        self.assertFinished(client)
 
1197
        self.assertEqual(True, result)
 
1198
 
 
1199
    def test_get_physical_lock_status_no(self):
 
1200
        transport = MemoryTransport()
 
1201
        client = FakeClient(transport.base)
 
1202
        client.add_expected_call(
 
1203
            'Branch.get_stacked_on_url', ('quack/',),
 
1204
            'error', ('NotStacked',))
 
1205
        client.add_expected_call(
 
1206
            'Branch.get_physical_lock_status', ('quack/',),
 
1207
            'success', ('no',))
 
1208
        transport.mkdir('quack')
 
1209
        transport = transport.clone('quack')
 
1210
        branch = self.make_remote_branch(transport, client)
 
1211
        result = branch.get_physical_lock_status()
 
1212
        self.assertFinished(client)
 
1213
        self.assertEqual(False, result)
 
1214
 
 
1215
 
970
1216
class TestBranchGetParent(RemoteBranchTestCase):
971
1217
 
972
1218
    def test_no_parent(self):
1062
1308
        verb = 'Branch.set_parent_location'
1063
1309
        self.disable_verb(verb)
1064
1310
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1311
        self.assertLength(13, self.hpss_calls)
1066
1312
 
1067
1313
 
1068
1314
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1143
1389
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1390
 
1145
1391
 
 
1392
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1393
 
 
1394
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1395
        transport = MemoryTransport()
 
1396
        client = FakeClient(transport.base)
 
1397
        client.add_expected_call(
 
1398
            'Branch.get_stacked_on_url', ('quack/',),
 
1399
            'error', ('NotStacked',))
 
1400
        client.add_expected_call(
 
1401
            'Branch.last_revision_info', ('quack/',),
 
1402
            'success', ('ok', '1', 'rev-tip'))
 
1403
        client.add_expected_call(
 
1404
            'Branch.get_config_file', ('quack/',),
 
1405
            'success', ('ok',), '')
 
1406
        transport.mkdir('quack')
 
1407
        transport = transport.clone('quack')
 
1408
        branch = self.make_remote_branch(transport, client)
 
1409
        result = branch.heads_to_fetch()
 
1410
        self.assertFinished(client)
 
1411
        self.assertEqual((set(['rev-tip']), set()), result)
 
1412
 
 
1413
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1414
        transport = MemoryTransport()
 
1415
        client = FakeClient(transport.base)
 
1416
        client.add_expected_call(
 
1417
            'Branch.get_stacked_on_url', ('quack/',),
 
1418
            'error', ('NotStacked',))
 
1419
        client.add_expected_call(
 
1420
            'Branch.last_revision_info', ('quack/',),
 
1421
            'success', ('ok', '1', 'rev-tip'))
 
1422
        client.add_expected_call(
 
1423
            'Branch.get_config_file', ('quack/',),
 
1424
            'success', ('ok',), 'branch.fetch_tags = True')
 
1425
        # XXX: this will break if the default format's serialization of tags
 
1426
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1427
        client.add_expected_call(
 
1428
            'Branch.get_tags_bytes', ('quack/',),
 
1429
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1430
        transport.mkdir('quack')
 
1431
        transport = transport.clone('quack')
 
1432
        branch = self.make_remote_branch(transport, client)
 
1433
        result = branch.heads_to_fetch()
 
1434
        self.assertFinished(client)
 
1435
        self.assertEqual(
 
1436
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1437
 
 
1438
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1439
        transport = MemoryTransport()
 
1440
        client = FakeClient(transport.base)
 
1441
        client.add_expected_call(
 
1442
            'Branch.get_stacked_on_url', ('quack/',),
 
1443
            'error', ('NotStacked',))
 
1444
        client.add_expected_call(
 
1445
            'Branch.heads_to_fetch', ('quack/',),
 
1446
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1447
        transport.mkdir('quack')
 
1448
        transport = transport.clone('quack')
 
1449
        branch = self.make_remote_branch(transport, client)
 
1450
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1451
        result = branch.heads_to_fetch()
 
1452
        self.assertFinished(client)
 
1453
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1454
 
 
1455
    def make_branch_with_tags(self):
 
1456
        self.setup_smart_server_with_call_log()
 
1457
        # Make a branch with a single revision.
 
1458
        builder = self.make_branch_builder('foo')
 
1459
        builder.start_series()
 
1460
        builder.build_snapshot('tip', None, [
 
1461
            ('add', ('', 'root-id', 'directory', ''))])
 
1462
        builder.finish_series()
 
1463
        branch = builder.get_branch()
 
1464
        # Add two tags to that branch
 
1465
        branch.tags.set_tag('tag-1', 'rev-1')
 
1466
        branch.tags.set_tag('tag-2', 'rev-2')
 
1467
        return branch
 
1468
 
 
1469
    def test_backwards_compatible(self):
 
1470
        branch = self.make_branch_with_tags()
 
1471
        c = branch.get_config_stack()
 
1472
        c.set('branch.fetch_tags', True)
 
1473
        self.addCleanup(branch.lock_read().unlock)
 
1474
        # Disable the heads_to_fetch verb
 
1475
        verb = 'Branch.heads_to_fetch'
 
1476
        self.disable_verb(verb)
 
1477
        self.reset_smart_call_log()
 
1478
        result = branch.heads_to_fetch()
 
1479
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1480
        self.assertEqual(
 
1481
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1482
             'Branch.get_tags_bytes'],
 
1483
            [call.call.method for call in self.hpss_calls])
 
1484
 
 
1485
    def test_backwards_compatible_no_tags(self):
 
1486
        branch = self.make_branch_with_tags()
 
1487
        c = branch.get_config_stack()
 
1488
        c.set('branch.fetch_tags', False)
 
1489
        self.addCleanup(branch.lock_read().unlock)
 
1490
        # Disable the heads_to_fetch verb
 
1491
        verb = 'Branch.heads_to_fetch'
 
1492
        self.disable_verb(verb)
 
1493
        self.reset_smart_call_log()
 
1494
        result = branch.heads_to_fetch()
 
1495
        self.assertEqual((set(['tip']), set()), result)
 
1496
        self.assertEqual(
 
1497
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1498
            [call.call.method for call in self.hpss_calls])
 
1499
 
 
1500
 
1146
1501
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1502
 
1148
1503
    def test_empty_branch(self):
1203
1558
        client.add_expected_call(
1204
1559
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1560
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1561
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1562
            _client=client)
1208
1563
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1564
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1591
        # this will also do vfs access, but that goes direct to the transport
1237
1592
        # and isn't seen by the FakeClient.
1238
1593
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1594
            RemoteBzrDirFormat(), _client=client)
1240
1595
        branch = bzrdir.open_branch()
1241
1596
        result = branch.get_stacked_on_url()
1242
1597
        self.assertEqual('../base', result)
1269
1624
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1625
            'success', ('ok', '../base'))
1271
1626
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1627
            RemoteBzrDirFormat(), _client=client)
1273
1628
        branch = bzrdir.open_branch()
1274
1629
        result = branch.get_stacked_on_url()
1275
1630
        self.assertEqual('../base', result)
1283
1638
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1639
 
1285
1640
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1641
        # _set_last_revision_info('null:') is translated to calling
1287
1642
        # Branch.set_last_revision(path, '') on the wire.
1288
1643
        transport = MemoryTransport()
1289
1644
        transport.mkdir('branch')
1307
1662
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1663
            'success', ('ok',))
1309
1664
        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
1665
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1666
        result = branch._set_last_revision(NULL_REVISION)
1315
1667
        branch.unlock()
1316
1668
        self.assertEqual(None, result)
1317
1669
        self.assertFinished(client)
1318
1670
 
1319
1671
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1672
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1673
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1674
        transport = MemoryTransport()
1323
1675
        transport.mkdir('branch')
1344
1696
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1697
            'success', ('ok',))
1346
1698
        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
1699
        # Lock the branch, reset the record of remote calls.
1351
1700
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1701
        result = branch._set_last_revision('rev-id2')
1353
1702
        branch.unlock()
1354
1703
        self.assertEqual(None, result)
1355
1704
        self.assertFinished(client)
1385
1734
        branch = self.make_remote_branch(transport, client)
1386
1735
        branch.lock_write()
1387
1736
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1737
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1738
        branch.unlock()
1390
1739
        self.assertFinished(client)
1391
1740
 
1419
1768
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1769
            'success', ('ok',))
1421
1770
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1771
        branch.lock_write()
1424
1772
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1773
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1774
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1775
            errors.TipChangeRejected,
 
1776
            branch._set_last_revision, 'rev-id')
1428
1777
        # The UTF-8 message from the response has been decoded into a unicode
1429
1778
        # object.
1430
1779
        self.assertIsInstance(err.msg, unicode)
1618
1967
    def test_get_multi_line_branch_conf(self):
1619
1968
        # Make sure that multiple-line branch.conf files are supported
1620
1969
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1970
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1971
        client = FakeClient()
1623
1972
        client.add_expected_call(
1624
1973
            'Branch.get_stacked_on_url', ('memory:///',),
1652
2001
        branch.unlock()
1653
2002
        self.assertFinished(client)
1654
2003
 
 
2004
    def test_set_option_with_dict(self):
 
2005
        client = FakeClient()
 
2006
        client.add_expected_call(
 
2007
            'Branch.get_stacked_on_url', ('memory:///',),
 
2008
            'error', ('NotStacked',),)
 
2009
        client.add_expected_call(
 
2010
            'Branch.lock_write', ('memory:///', '', ''),
 
2011
            'success', ('ok', 'branch token', 'repo token'))
 
2012
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
2013
        client.add_expected_call(
 
2014
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
2015
            'repo token', encoded_dict_value, 'foo', ''),
 
2016
            'success', ())
 
2017
        client.add_expected_call(
 
2018
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2019
            'success', ('ok',))
 
2020
        transport = MemoryTransport()
 
2021
        branch = self.make_remote_branch(transport, client)
 
2022
        branch.lock_write()
 
2023
        config = branch._get_config()
 
2024
        config.set_option(
 
2025
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2026
            'foo')
 
2027
        branch.unlock()
 
2028
        self.assertFinished(client)
 
2029
 
1655
2030
    def test_backwards_compat_set_option(self):
1656
2031
        self.setup_smart_server_with_call_log()
1657
2032
        branch = self.make_branch('.')
1661
2036
        self.addCleanup(branch.unlock)
1662
2037
        self.reset_smart_call_log()
1663
2038
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2039
        self.assertLength(11, self.hpss_calls)
1665
2040
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2041
 
 
2042
    def test_backwards_compat_set_option_with_dict(self):
 
2043
        self.setup_smart_server_with_call_log()
 
2044
        branch = self.make_branch('.')
 
2045
        verb = 'Branch.set_config_option_dict'
 
2046
        self.disable_verb(verb)
 
2047
        branch.lock_write()
 
2048
        self.addCleanup(branch.unlock)
 
2049
        self.reset_smart_call_log()
 
2050
        config = branch._get_config()
 
2051
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2052
        config.set_option(value_dict, 'name')
 
2053
        self.assertLength(11, self.hpss_calls)
 
2054
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2055
 
 
2056
 
 
2057
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2058
 
 
2059
    def test_get_branch_conf(self):
 
2060
        # in an empty branch we decode the response properly
 
2061
        client = FakeClient()
 
2062
        client.add_expected_call(
 
2063
            'Branch.get_stacked_on_url', ('memory:///',),
 
2064
            'error', ('NotStacked',),)
 
2065
        client.add_success_response_with_body('# config file body', 'ok')
 
2066
        transport = MemoryTransport()
 
2067
        branch = self.make_remote_branch(transport, client)
 
2068
        config = branch.get_config_stack()
 
2069
        config.get("email")
 
2070
        config.get("log_format")
 
2071
        self.assertEqual(
 
2072
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2073
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2074
            client._calls)
 
2075
 
 
2076
    def test_set_branch_conf(self):
 
2077
        client = FakeClient()
 
2078
        client.add_expected_call(
 
2079
            'Branch.get_stacked_on_url', ('memory:///',),
 
2080
            'error', ('NotStacked',),)
 
2081
        client.add_expected_call(
 
2082
            'Branch.lock_write', ('memory:///', '', ''),
 
2083
            'success', ('ok', 'branch token', 'repo token'))
 
2084
        client.add_expected_call(
 
2085
            'Branch.get_config_file', ('memory:///', ),
 
2086
            'success', ('ok', ), "# line 1\n")
 
2087
        client.add_expected_call(
 
2088
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2089
            'repo token'),
 
2090
            'success', ('ok',))
 
2091
        client.add_expected_call(
 
2092
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2093
            'success', ('ok',))
 
2094
        transport = MemoryTransport()
 
2095
        branch = self.make_remote_branch(transport, client)
 
2096
        branch.lock_write()
 
2097
        config = branch.get_config_stack()
 
2098
        config.set('email', 'The Dude <lebowski@example.com>')
 
2099
        branch.unlock()
 
2100
        self.assertFinished(client)
 
2101
        self.assertEqual(
 
2102
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2103
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2104
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2105
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2106
                 ('memory:///', 'branch token', 'repo token'),
 
2107
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2108
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2109
            client._calls)
 
2110
 
1667
2111
 
1668
2112
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2113
 
1683
2127
        self.assertFinished(client)
1684
2128
 
1685
2129
 
 
2130
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2131
 
 
2132
    def test_simple(self):
 
2133
        transport = MemoryTransport()
 
2134
        client = FakeClient(transport.base)
 
2135
        client.add_expected_call(
 
2136
            'Branch.get_stacked_on_url', ('quack/',),
 
2137
            'error', ('NotStacked',),)
 
2138
        client.add_expected_call(
 
2139
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2140
            'success', ('ok', '0',),)
 
2141
        client.add_expected_call(
 
2142
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2143
            'error', ('NoSuchRevision', 'unknown',),)
 
2144
        transport.mkdir('quack')
 
2145
        transport = transport.clone('quack')
 
2146
        branch = self.make_remote_branch(transport, client)
 
2147
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2148
        self.assertRaises(errors.NoSuchRevision,
 
2149
            branch.revision_id_to_revno, 'unknown')
 
2150
        self.assertFinished(client)
 
2151
 
 
2152
    def test_dotted(self):
 
2153
        transport = MemoryTransport()
 
2154
        client = FakeClient(transport.base)
 
2155
        client.add_expected_call(
 
2156
            'Branch.get_stacked_on_url', ('quack/',),
 
2157
            'error', ('NotStacked',),)
 
2158
        client.add_expected_call(
 
2159
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2160
            'success', ('ok', '0',),)
 
2161
        client.add_expected_call(
 
2162
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2163
            'error', ('NoSuchRevision', 'unknown',),)
 
2164
        transport.mkdir('quack')
 
2165
        transport = transport.clone('quack')
 
2166
        branch = self.make_remote_branch(transport, client)
 
2167
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2168
        self.assertRaises(errors.NoSuchRevision,
 
2169
            branch.revision_id_to_dotted_revno, 'unknown')
 
2170
        self.assertFinished(client)
 
2171
 
 
2172
    def test_dotted_no_smart_verb(self):
 
2173
        self.setup_smart_server_with_call_log()
 
2174
        branch = self.make_branch('.')
 
2175
        self.disable_verb('Branch.revision_id_to_revno')
 
2176
        self.reset_smart_call_log()
 
2177
        self.assertEquals((0, ),
 
2178
            branch.revision_id_to_dotted_revno('null:'))
 
2179
        self.assertLength(8, self.hpss_calls)
 
2180
 
 
2181
 
1686
2182
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2183
 
1688
2184
    def test__get_config(self):
1702
2198
        self.reset_smart_call_log()
1703
2199
        config = bzrdir.get_config()
1704
2200
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2201
        self.assertLength(4, self.hpss_calls)
1706
2202
 
1707
2203
    def test_backwards_compat_get_option(self):
1708
2204
        self.setup_smart_server_with_call_log()
1712
2208
        self.reset_smart_call_log()
1713
2209
        self.assertEqual(None,
1714
2210
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2211
        self.assertLength(4, self.hpss_calls)
1716
2212
 
1717
2213
 
1718
2214
class TestTransportIsReadonly(tests.TestCase):
1805
2301
        client = FakeClient(transport.base)
1806
2302
        transport = transport.clone(transport_path)
1807
2303
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2304
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2305
            _client=False)
1810
2306
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2307
        return repo, client
1819
2315
 
1820
2316
    def test_get_format_description(self):
1821
2317
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2318
        real_format = branch.format_registry.get_default()
1823
2319
        remote_format._network_name = real_format.network_name()
1824
2320
        self.assertEqual(remoted_description(real_format),
1825
2321
            remote_format.get_format_description())
1828
2324
class TestRepositoryFormat(TestRemoteRepository):
1829
2325
 
1830
2326
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2327
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2328
        true_format = RemoteRepositoryFormat()
1833
2329
        true_format._network_name = true_name
1834
2330
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2331
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2332
        false_format = RemoteRepositoryFormat()
1837
2333
        false_format._network_name = false_name
1838
2334
        self.assertEqual(False, false_format.fast_deltas)
1839
2335
 
1840
2336
    def test_get_format_description(self):
1841
2337
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2338
        real_format = repository.format_registry.get_default()
1843
2339
        remote_repo_format._network_name = real_format.network_name()
1844
2340
        self.assertEqual(remoted_description(real_format),
1845
2341
            remote_repo_format.get_format_description())
1846
2342
 
1847
2343
 
 
2344
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2345
 
 
2346
    def test_empty(self):
 
2347
        transport_path = 'quack'
 
2348
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2349
        client.add_success_response_with_body('', 'ok')
 
2350
        self.assertEquals([], repo.all_revision_ids())
 
2351
        self.assertEqual(
 
2352
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2353
             ('quack/',))],
 
2354
            client._calls)
 
2355
 
 
2356
    def test_with_some_content(self):
 
2357
        transport_path = 'quack'
 
2358
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2359
        client.add_success_response_with_body(
 
2360
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2361
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2362
            repo.all_revision_ids())
 
2363
        self.assertEqual(
 
2364
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2365
             ('quack/',))],
 
2366
            client._calls)
 
2367
 
 
2368
 
1848
2369
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2370
 
1850
2371
    def test_revid_none(self):
1903
2424
                         result)
1904
2425
 
1905
2426
 
 
2427
class TestRepositoryBreakLock(TestRemoteRepository):
 
2428
 
 
2429
    def test_break_lock(self):
 
2430
        transport_path = 'quack'
 
2431
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2432
        client.add_success_response('ok')
 
2433
        repo.break_lock()
 
2434
        self.assertEqual(
 
2435
            [('call', 'Repository.break_lock', ('quack/',))],
 
2436
            client._calls)
 
2437
 
 
2438
 
 
2439
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2440
 
 
2441
    def test_get_serializer_format(self):
 
2442
        transport_path = 'hill'
 
2443
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2444
        client.add_success_response('ok', '7')
 
2445
        self.assertEquals('7', repo.get_serializer_format())
 
2446
        self.assertEqual(
 
2447
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2448
              ('hill/', ))],
 
2449
            client._calls)
 
2450
 
 
2451
 
 
2452
class TestRepositoryReconcile(TestRemoteRepository):
 
2453
 
 
2454
    def test_reconcile(self):
 
2455
        transport_path = 'hill'
 
2456
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2457
        body = ("garbage_inventories: 2\n"
 
2458
                "inconsistent_parents: 3\n")
 
2459
        client.add_expected_call(
 
2460
            'Repository.lock_write', ('hill/', ''),
 
2461
            'success', ('ok', 'a token'))
 
2462
        client.add_success_response_with_body(body, 'ok')
 
2463
        reconciler = repo.reconcile()
 
2464
        self.assertEqual(
 
2465
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2466
             ('call_expecting_body', 'Repository.reconcile',
 
2467
                ('hill/', 'a token'))],
 
2468
            client._calls)
 
2469
        self.assertEquals(2, reconciler.garbage_inventories)
 
2470
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2471
 
 
2472
 
 
2473
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2474
 
 
2475
    def test_text(self):
 
2476
        # ('ok',), body with signature text
 
2477
        transport_path = 'quack'
 
2478
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2479
        client.add_success_response_with_body(
 
2480
            'THETEXT', 'ok')
 
2481
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2482
        self.assertEqual(
 
2483
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2484
             ('quack/', 'revid'))],
 
2485
            client._calls)
 
2486
 
 
2487
    def test_no_signature(self):
 
2488
        transport_path = 'quick'
 
2489
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2490
        client.add_error_response('nosuchrevision', 'unknown')
 
2491
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2492
                "unknown")
 
2493
        self.assertEqual(
 
2494
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2495
              ('quick/', 'unknown'))],
 
2496
            client._calls)
 
2497
 
 
2498
 
1906
2499
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2500
 
1908
2501
    def test_get_graph(self):
1913
2506
        self.assertNotEqual(graph._parents_provider, repo)
1914
2507
 
1915
2508
 
 
2509
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2510
 
 
2511
    def test_add_signature_text(self):
 
2512
        transport_path = 'quack'
 
2513
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2514
        client.add_expected_call(
 
2515
            'Repository.lock_write', ('quack/', ''),
 
2516
            'success', ('ok', 'a token'))
 
2517
        client.add_expected_call(
 
2518
            'Repository.start_write_group', ('quack/', 'a token'),
 
2519
            'success', ('ok', ('token1', )))
 
2520
        client.add_expected_call(
 
2521
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2522
                'token1'),
 
2523
            'success', ('ok', ), None)
 
2524
        repo.lock_write()
 
2525
        repo.start_write_group()
 
2526
        self.assertIs(None,
 
2527
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2528
        self.assertEqual(
 
2529
            ('call_with_body_bytes_expecting_body',
 
2530
              'Repository.add_signature_text',
 
2531
                ('quack/', 'a token', 'rev1', 'token1'),
 
2532
              'every bloody emperor'),
 
2533
            client._calls[-1])
 
2534
 
 
2535
 
1916
2536
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2537
 
1918
2538
    def test_get_parent_map_caching(self):
1968
2588
        parents = repo.get_parent_map([rev_id])
1969
2589
        self.assertEqual(
1970
2590
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2591
              'Repository.get_parent_map',
 
2592
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2593
             ('disconnect medium',),
1974
2594
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2595
              ('quack/', ''))],
2095
2715
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2716
        self.assertLength(0, self.hpss_calls)
2097
2717
 
 
2718
    def test_exposes_get_cached_parent_map(self):
 
2719
        """RemoteRepository exposes get_cached_parent_map from
 
2720
        _unstacked_provider
 
2721
        """
 
2722
        r1 = u'\u0e33'.encode('utf8')
 
2723
        r2 = u'\u0dab'.encode('utf8')
 
2724
        lines = [' '.join([r2, r1]), r1]
 
2725
        encoded_body = bz2.compress('\n'.join(lines))
 
2726
 
 
2727
        transport_path = 'quack'
 
2728
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2729
        client.add_success_response_with_body(encoded_body, 'ok')
 
2730
        repo.lock_read()
 
2731
        # get_cached_parent_map should *not* trigger an RPC
 
2732
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2733
        self.assertEqual([], client._calls)
 
2734
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2735
        self.assertEqual({r1: (NULL_REVISION,)},
 
2736
            repo.get_cached_parent_map([r1]))
 
2737
        self.assertEqual(
 
2738
            [('call_with_body_bytes_expecting_body',
 
2739
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2740
              '\n\n0')],
 
2741
            client._calls)
 
2742
        repo.unlock()
 
2743
 
2098
2744
 
2099
2745
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2746
 
2115
2761
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2762
 
2117
2763
 
 
2764
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2765
 
 
2766
    def test_hpss_missing_revision(self):
 
2767
        transport_path = 'quack'
 
2768
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2769
        client.add_success_response_with_body(
 
2770
            '', 'ok', '10')
 
2771
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2772
            ['somerev1', 'anotherrev2'])
 
2773
        self.assertEqual(
 
2774
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2775
             ('quack/', ), "somerev1\nanotherrev2")],
 
2776
            client._calls)
 
2777
 
 
2778
    def test_hpss_get_single_revision(self):
 
2779
        transport_path = 'quack'
 
2780
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2781
        somerev1 = Revision("somerev1")
 
2782
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2783
        somerev1.timestamp = 1321828927
 
2784
        somerev1.timezone = -60
 
2785
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2786
        somerev1.message = "Message"
 
2787
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2788
            somerev1))
 
2789
        # Split up body into two bits to make sure the zlib compression object
 
2790
        # gets data fed twice.
 
2791
        client.add_success_response_with_body(
 
2792
                [body[:10], body[10:]], 'ok', '10')
 
2793
        revs = repo.get_revisions(['somerev1'])
 
2794
        self.assertEquals(revs, [somerev1])
 
2795
        self.assertEqual(
 
2796
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2797
             ('quack/', ), "somerev1")],
 
2798
            client._calls)
 
2799
 
 
2800
 
2118
2801
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2802
 
2120
2803
    def test_null_revision(self):
2257
2940
        self.setup_smart_server_with_call_log()
2258
2941
        tree = self.make_branch_and_memory_tree('.')
2259
2942
        tree.lock_write()
 
2943
        tree.add('')
2260
2944
        rev1 = tree.commit('First')
2261
2945
        rev2 = tree.commit('Second')
2262
2946
        tree.unlock()
2270
2954
                              call.call.method == verb])
2271
2955
 
2272
2956
 
 
2957
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2958
 
 
2959
    def test_has_signature_for_revision_id(self):
 
2960
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2961
        transport_path = 'quack'
 
2962
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2963
        client.add_success_response('yes')
 
2964
        result = repo.has_signature_for_revision_id('A')
 
2965
        self.assertEqual(
 
2966
            [('call', 'Repository.has_signature_for_revision_id',
 
2967
              ('quack/', 'A'))],
 
2968
            client._calls)
 
2969
        self.assertEqual(True, result)
 
2970
 
 
2971
    def test_is_not_shared(self):
 
2972
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2973
        transport_path = 'qwack'
 
2974
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2975
        client.add_success_response('no')
 
2976
        result = repo.has_signature_for_revision_id('A')
 
2977
        self.assertEqual(
 
2978
            [('call', 'Repository.has_signature_for_revision_id',
 
2979
              ('qwack/', 'A'))],
 
2980
            client._calls)
 
2981
        self.assertEqual(False, result)
 
2982
 
 
2983
 
 
2984
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2985
 
 
2986
    def test_get_physical_lock_status_yes(self):
 
2987
        transport_path = 'qwack'
 
2988
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2989
        client.add_success_response('yes')
 
2990
        result = repo.get_physical_lock_status()
 
2991
        self.assertEqual(
 
2992
            [('call', 'Repository.get_physical_lock_status',
 
2993
              ('qwack/', ))],
 
2994
            client._calls)
 
2995
        self.assertEqual(True, result)
 
2996
 
 
2997
    def test_get_physical_lock_status_no(self):
 
2998
        transport_path = 'qwack'
 
2999
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3000
        client.add_success_response('no')
 
3001
        result = repo.get_physical_lock_status()
 
3002
        self.assertEqual(
 
3003
            [('call', 'Repository.get_physical_lock_status',
 
3004
              ('qwack/', ))],
 
3005
            client._calls)
 
3006
        self.assertEqual(False, result)
 
3007
 
 
3008
 
2273
3009
class TestRepositoryIsShared(TestRemoteRepository):
2274
3010
 
2275
3011
    def test_is_shared(self):
2295
3031
        self.assertEqual(False, result)
2296
3032
 
2297
3033
 
 
3034
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3035
 
 
3036
    def test_make_working_trees(self):
 
3037
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3038
        transport_path = 'quack'
 
3039
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3040
        client.add_success_response('yes')
 
3041
        result = repo.make_working_trees()
 
3042
        self.assertEqual(
 
3043
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3044
            client._calls)
 
3045
        self.assertEqual(True, result)
 
3046
 
 
3047
    def test_no_working_trees(self):
 
3048
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3049
        transport_path = 'qwack'
 
3050
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3051
        client.add_success_response('no')
 
3052
        result = repo.make_working_trees()
 
3053
        self.assertEqual(
 
3054
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3055
            client._calls)
 
3056
        self.assertEqual(False, result)
 
3057
 
 
3058
 
2298
3059
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3060
 
2300
3061
    def test_lock_write(self):
2301
3062
        transport_path = 'quack'
2302
3063
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3064
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3065
        token = repo.lock_write().repository_token
2305
3066
        self.assertEqual(
2306
3067
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3068
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3069
        self.assertEqual('a token', token)
2309
3070
 
2310
3071
    def test_lock_write_already_locked(self):
2311
3072
        transport_path = 'quack'
2326
3087
            client._calls)
2327
3088
 
2328
3089
 
 
3090
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3091
 
 
3092
    def test_start_write_group(self):
 
3093
        transport_path = 'quack'
 
3094
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3095
        client.add_expected_call(
 
3096
            'Repository.lock_write', ('quack/', ''),
 
3097
            'success', ('ok', 'a token'))
 
3098
        client.add_expected_call(
 
3099
            'Repository.start_write_group', ('quack/', 'a token'),
 
3100
            'success', ('ok', ('token1', )))
 
3101
        repo.lock_write()
 
3102
        repo.start_write_group()
 
3103
 
 
3104
    def test_start_write_group_unsuspendable(self):
 
3105
        # Some repositories do not support suspending write
 
3106
        # groups. For those, fall back to the "real" repository.
 
3107
        transport_path = 'quack'
 
3108
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3109
        def stub_ensure_real():
 
3110
            client._calls.append(('_ensure_real',))
 
3111
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3112
        repo._ensure_real = stub_ensure_real
 
3113
        client.add_expected_call(
 
3114
            'Repository.lock_write', ('quack/', ''),
 
3115
            'success', ('ok', 'a token'))
 
3116
        client.add_expected_call(
 
3117
            'Repository.start_write_group', ('quack/', 'a token'),
 
3118
            'error', ('UnsuspendableWriteGroup',))
 
3119
        repo.lock_write()
 
3120
        repo.start_write_group()
 
3121
        self.assertEquals(client._calls[-2:], [ 
 
3122
            ('_ensure_real',),
 
3123
            ('start_write_group',)])
 
3124
 
 
3125
    def test_commit_write_group(self):
 
3126
        transport_path = 'quack'
 
3127
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3128
        client.add_expected_call(
 
3129
            'Repository.lock_write', ('quack/', ''),
 
3130
            'success', ('ok', 'a token'))
 
3131
        client.add_expected_call(
 
3132
            'Repository.start_write_group', ('quack/', 'a token'),
 
3133
            'success', ('ok', ['token1']))
 
3134
        client.add_expected_call(
 
3135
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3136
            'success', ('ok',))
 
3137
        repo.lock_write()
 
3138
        repo.start_write_group()
 
3139
        repo.commit_write_group()
 
3140
 
 
3141
    def test_abort_write_group(self):
 
3142
        transport_path = 'quack'
 
3143
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3144
        client.add_expected_call(
 
3145
            'Repository.lock_write', ('quack/', ''),
 
3146
            'success', ('ok', 'a token'))
 
3147
        client.add_expected_call(
 
3148
            'Repository.start_write_group', ('quack/', 'a token'),
 
3149
            'success', ('ok', ['token1']))
 
3150
        client.add_expected_call(
 
3151
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3152
            'success', ('ok',))
 
3153
        repo.lock_write()
 
3154
        repo.start_write_group()
 
3155
        repo.abort_write_group(False)
 
3156
 
 
3157
    def test_suspend_write_group(self):
 
3158
        transport_path = 'quack'
 
3159
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3160
        self.assertEquals([], repo.suspend_write_group())
 
3161
 
 
3162
    def test_resume_write_group(self):
 
3163
        transport_path = 'quack'
 
3164
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3165
        client.add_expected_call(
 
3166
            'Repository.lock_write', ('quack/', ''),
 
3167
            'success', ('ok', 'a token'))
 
3168
        client.add_expected_call(
 
3169
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3170
            'success', ('ok',))
 
3171
        repo.lock_write()
 
3172
        repo.resume_write_group(['token1'])
 
3173
 
 
3174
 
2329
3175
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3176
 
2331
3177
    def test_backwards_compat(self):
2390
3236
        self.assertEqual([], client._calls)
2391
3237
 
2392
3238
 
 
3239
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3240
    """Test Repository.iter_file_bytes."""
 
3241
 
 
3242
    def test_single(self):
 
3243
        transport_path = 'quack'
 
3244
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3245
        client.add_expected_call(
 
3246
            'Repository.iter_files_bytes', ('quack/', ),
 
3247
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3248
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3249
                "somerev", "myid")]):
 
3250
            self.assertEquals("myid", identifier)
 
3251
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3252
 
 
3253
    def test_missing(self):
 
3254
        transport_path = 'quack'
 
3255
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3256
        client.add_expected_call(
 
3257
            'Repository.iter_files_bytes',
 
3258
                ('quack/', ),
 
3259
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3260
            iter(["absent\0somefile\0somerev\n"]))
 
3261
        self.assertRaises(errors.RevisionNotPresent, list,
 
3262
                repo.iter_files_bytes(
 
3263
                [("somefile", "somerev", "myid")]))
 
3264
 
 
3265
 
2393
3266
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3267
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3268
    tests.
2402
3275
        the client is finished.
2403
3276
        """
2404
3277
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3278
        fmt = repository.format_registry.get_default()
2406
3279
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3280
        self.assertEqual([], resume_tokens)
2408
3281
        self.assertEqual(set(), missing_keys)
2508
3381
                return True
2509
3382
        repo._real_repository = FakeRealRepository()
2510
3383
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3384
        fmt = repository.format_registry.get_default()
2512
3385
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3386
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3387
        # Every record from the first inventory delta should have been sent to
2670
3543
        self.calls = calls
2671
3544
        self._pack_collection = _StubPackCollection(calls)
2672
3545
 
 
3546
    def start_write_group(self):
 
3547
        self.calls.append(('start_write_group',))
 
3548
 
2673
3549
    def is_in_write_group(self):
2674
3550
        return False
2675
3551
 
2734
3610
             ('pack collection autopack',)],
2735
3611
            client._calls)
2736
3612
 
 
3613
    def test_oom_error_reporting(self):
 
3614
        """An out-of-memory condition on the server is reported clearly"""
 
3615
        transport_path = 'quack'
 
3616
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3617
        client.add_expected_call(
 
3618
            'PackRepository.autopack', ('quack/',),
 
3619
            'error', ('MemoryError',))
 
3620
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3621
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3622
 
2737
3623
 
2738
3624
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3625
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3698
            detail='extra detail')
2813
3699
        self.assertEqual(expected_error, translated_error)
2814
3700
 
 
3701
    def test_norepository(self):
 
3702
        bzrdir = self.make_bzrdir('')
 
3703
        translated_error = self.translateTuple(('norepository',),
 
3704
            bzrdir=bzrdir)
 
3705
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3706
        self.assertEqual(expected_error, translated_error)
 
3707
 
2815
3708
    def test_LockContention(self):
2816
3709
        translated_error = self.translateTuple(('LockContention',))
2817
3710
        expected_error = errors.LockContention('(remote lock)')
2845
3738
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3739
        self.assertEqual(expected_error, translated_error)
2847
3740
 
 
3741
    def test_NotStacked(self):
 
3742
        branch = self.make_branch('')
 
3743
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3744
        expected_error = errors.NotStacked(branch)
 
3745
        self.assertEqual(expected_error, translated_error)
 
3746
 
2848
3747
    def test_ReadError_no_args(self):
2849
3748
        path = 'a path'
2850
3749
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3765
 
2867
3766
    def test_PermissionDenied_no_args(self):
2868
3767
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3768
        translated_error = self.translateTuple(('PermissionDenied',),
 
3769
            path=path)
2870
3770
        expected_error = errors.PermissionDenied(path)
2871
3771
        self.assertEqual(expected_error, translated_error)
2872
3772
 
2895
3795
        expected_error = errors.PermissionDenied(path, extra)
2896
3796
        self.assertEqual(expected_error, translated_error)
2897
3797
 
 
3798
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3799
 
 
3800
    def test_NoSuchFile_context_path(self):
 
3801
        local_path = "local path"
 
3802
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3803
            path=local_path)
 
3804
        expected_error = errors.ReadError(local_path)
 
3805
        self.assertEqual(expected_error, translated_error)
 
3806
 
 
3807
    def test_NoSuchFile_without_context(self):
 
3808
        remote_path = "remote path"
 
3809
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3810
        expected_error = errors.ReadError(remote_path)
 
3811
        self.assertEqual(expected_error, translated_error)
 
3812
 
 
3813
    def test_ReadOnlyError(self):
 
3814
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3815
        expected_error = errors.TransportNotPossible("readonly transport")
 
3816
        self.assertEqual(expected_error, translated_error)
 
3817
 
 
3818
    def test_MemoryError(self):
 
3819
        translated_error = self.translateTuple(('MemoryError',))
 
3820
        self.assertStartsWith(str(translated_error),
 
3821
            "remote server out of memory")
 
3822
 
 
3823
    def test_generic_IndexError_no_classname(self):
 
3824
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3825
        translated_error = self.translateErrorFromSmartServer(err)
 
3826
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3827
        self.assertEqual(expected_error, translated_error)
 
3828
 
 
3829
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3830
 
 
3831
    def test_generic_KeyError(self):
 
3832
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3833
        translated_error = self.translateErrorFromSmartServer(err)
 
3834
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3835
        self.assertEqual(expected_error, translated_error)
 
3836
 
2898
3837
 
2899
3838
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3839
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3984
        _, stacked = branch_factory()
3046
3985
        source = stacked.repository._get_source(target_repository_format)
3047
3986
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3987
        stacked.repository._ensure_real()
 
3988
        graph = stacked.repository.get_graph()
 
3989
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3990
                if r != NULL_REVISION]
 
3991
        revs.reverse()
 
3992
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3993
        self.reset_smart_call_log()
3051
3994
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3995
        # We trust that if a revision is in the stream the rest of the new
3055
3996
        # content for it is too, as per our main fetch tests; here we are
3056
3997
        # checking that the revisions are actually included at all, and their
3095
4036
        self.assertEqual(expected_revs, rev_ord)
3096
4037
        # Getting topological sort requires VFS calls still - one of which is
3097
4038
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4039
        self.assertLength(14, self.hpss_calls)
3099
4040
 
3100
4041
    def test_stacked_get_stream_groupcompress(self):
3101
4042
        # Repository._get_source.get_stream() from a stacked repository with
3142
4083
 
3143
4084
    def test_copy_content_into_avoids_revision_history(self):
3144
4085
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4086
        builder = self.make_branch_builder('remote')
 
4087
        builder.build_commit(message="Commit.")
3147
4088
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4089
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4090
        local.repository.fetch(remote_branch.repository)
3150
4091
        self.hpss_calls = []
3151
4092
        remote_branch.copy_content_into(local)
3152
4093
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4094
 
 
4095
    def test_fetch_everything_needs_just_one_call(self):
 
4096
        local = self.make_branch('local')
 
4097
        builder = self.make_branch_builder('remote')
 
4098
        builder.build_commit(message="Commit.")
 
4099
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4100
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4101
        self.hpss_calls = []
 
4102
        local.repository.fetch(
 
4103
            remote_branch.repository,
 
4104
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4105
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4106
 
 
4107
    def override_verb(self, verb_name, verb):
 
4108
        request_handlers = request.request_handlers
 
4109
        orig_verb = request_handlers.get(verb_name)
 
4110
        orig_info = request_handlers.get_info(verb_name)
 
4111
        request_handlers.register(verb_name, verb, override_existing=True)
 
4112
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4113
                override_existing=True, info=orig_info)
 
4114
 
 
4115
    def test_fetch_everything_backwards_compat(self):
 
4116
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4117
        
 
4118
        Pre-2.4 do not support 'everything' searches with the
 
4119
        Repository.get_stream_1.19 verb.
 
4120
        """
 
4121
        verb_log = []
 
4122
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4123
            """A version of the Repository.get_stream_1.19 verb patched to
 
4124
            reject 'everything' searches the way 2.3 and earlier do.
 
4125
            """
 
4126
            def recreate_search(self, repository, search_bytes,
 
4127
                                discard_excess=False):
 
4128
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4129
                if search_bytes == 'everything':
 
4130
                    return (None,
 
4131
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4132
                return super(OldGetStreamVerb,
 
4133
                        self).recreate_search(repository, search_bytes,
 
4134
                            discard_excess=discard_excess)
 
4135
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4136
        local = self.make_branch('local')
 
4137
        builder = self.make_branch_builder('remote')
 
4138
        builder.build_commit(message="Commit.")
 
4139
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4140
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4141
        self.hpss_calls = []
 
4142
        local.repository.fetch(
 
4143
            remote_branch.repository,
 
4144
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4145
        # make sure the overridden verb was used
 
4146
        self.assertLength(1, verb_log)
 
4147
        # more than one HPSS call is needed, but because it's a VFS callback
 
4148
        # its hard to predict exactly how many.
 
4149
        self.assertTrue(len(self.hpss_calls) > 1)
 
4150
 
 
4151
 
 
4152
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4153
    tests.TestCaseWithTransport):
 
4154
    """Ensure correct handling of bound_location modifications.
 
4155
 
 
4156
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4157
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4158
    happen in this context.
 
4159
    """
 
4160
 
 
4161
    def setUp(self):
 
4162
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4163
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4164
 
 
4165
    def make_master_and_checkout(self, master_name, checkout_name):
 
4166
        # Create the master branch and its associated checkout
 
4167
        self.master = self.make_branch_and_tree(master_name)
 
4168
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4169
        # Modify the master branch so there is something to update
 
4170
        self.master.commit('add stuff')
 
4171
        self.last_revid = self.master.commit('even more stuff')
 
4172
        self.bound_location = self.checkout.branch.get_bound_location()
 
4173
 
 
4174
    def assertUpdateSucceeds(self, new_location):
 
4175
        self.checkout.branch.set_bound_location(new_location)
 
4176
        self.checkout.update()
 
4177
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4178
 
 
4179
    def test_without_final_slash(self):
 
4180
        self.make_master_and_checkout('master', 'checkout')
 
4181
        # For unclear reasons some users have a bound_location without a final
 
4182
        # '/', simulate that by forcing such a value
 
4183
        self.assertEndsWith(self.bound_location, '/')
 
4184
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4185
 
 
4186
    def test_plus_sign(self):
 
4187
        self.make_master_and_checkout('+master', 'checkout')
 
4188
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4189
 
 
4190
    def test_tilda(self):
 
4191
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4192
        # interpretation
 
4193
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4194
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4195
 
 
4196
 
 
4197
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4198
 
 
4199
    def test_no_context(self):
 
4200
        class OutOfCoffee(errors.BzrError):
 
4201
            """A dummy exception for testing."""
 
4202
 
 
4203
            def __init__(self, urgency):
 
4204
                self.urgency = urgency
 
4205
        remote.no_context_error_translators.register("OutOfCoffee",
 
4206
            lambda err: OutOfCoffee(err.error_args[0]))
 
4207
        transport = MemoryTransport()
 
4208
        client = FakeClient(transport.base)
 
4209
        client.add_expected_call(
 
4210
            'Branch.get_stacked_on_url', ('quack/',),
 
4211
            'error', ('NotStacked',))
 
4212
        client.add_expected_call(
 
4213
            'Branch.last_revision_info',
 
4214
            ('quack/',),
 
4215
            'error', ('OutOfCoffee', 'low'))
 
4216
        transport.mkdir('quack')
 
4217
        transport = transport.clone('quack')
 
4218
        branch = self.make_remote_branch(transport, client)
 
4219
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4220
        self.assertFinished(client)
 
4221
 
 
4222
    def test_with_context(self):
 
4223
        class OutOfTea(errors.BzrError):
 
4224
            def __init__(self, branch, urgency):
 
4225
                self.branch = branch
 
4226
                self.urgency = urgency
 
4227
        remote.error_translators.register("OutOfTea",
 
4228
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4229
                find("branch")))
 
4230
        transport = MemoryTransport()
 
4231
        client = FakeClient(transport.base)
 
4232
        client.add_expected_call(
 
4233
            'Branch.get_stacked_on_url', ('quack/',),
 
4234
            'error', ('NotStacked',))
 
4235
        client.add_expected_call(
 
4236
            'Branch.last_revision_info',
 
4237
            ('quack/',),
 
4238
            'error', ('OutOfTea', 'low'))
 
4239
        transport.mkdir('quack')
 
4240
        transport = transport.clone('quack')
 
4241
        branch = self.make_remote_branch(transport, client)
 
4242
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4243
        self.assertFinished(client)
 
4244
 
 
4245
 
 
4246
class TestRepositoryPack(TestRemoteRepository):
 
4247
 
 
4248
    def test_pack(self):
 
4249
        transport_path = 'quack'
 
4250
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4251
        client.add_expected_call(
 
4252
            'Repository.lock_write', ('quack/', ''),
 
4253
            'success', ('ok', 'token'))
 
4254
        client.add_expected_call(
 
4255
            'Repository.pack', ('quack/', 'token', 'False'),
 
4256
            'success', ('ok',), )
 
4257
        client.add_expected_call(
 
4258
            'Repository.unlock', ('quack/', 'token'),
 
4259
            'success', ('ok', ))
 
4260
        repo.pack()
 
4261
 
 
4262
    def test_pack_with_hint(self):
 
4263
        transport_path = 'quack'
 
4264
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4265
        client.add_expected_call(
 
4266
            'Repository.lock_write', ('quack/', ''),
 
4267
            'success', ('ok', 'token'))
 
4268
        client.add_expected_call(
 
4269
            'Repository.pack', ('quack/', 'token', 'False'),
 
4270
            'success', ('ok',), )
 
4271
        client.add_expected_call(
 
4272
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4273
            'success', ('ok', ))
 
4274
        repo.pack(['hinta', 'hintb'])
 
4275
 
 
4276
 
 
4277
class TestRepositoryIterInventories(TestRemoteRepository):
 
4278
    """Test Repository.iter_inventories."""
 
4279
 
 
4280
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4281
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4282
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4283
 
 
4284
    def test_single_empty(self):
 
4285
        transport_path = 'quack'
 
4286
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4287
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4288
        repo._format = fmt
 
4289
        stream = [('inventory-deltas', [
 
4290
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4291
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4292
        client.add_expected_call(
 
4293
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4294
            'success', ('ok', ),
 
4295
            _stream_to_byte_stream(stream, fmt))
 
4296
        ret = list(repo.iter_inventories(["somerevid"]))
 
4297
        self.assertLength(1, ret)
 
4298
        inv = ret[0]
 
4299
        self.assertEquals("somerevid", inv.revision_id)
 
4300
 
 
4301
    def test_empty(self):
 
4302
        transport_path = 'quack'
 
4303
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4304
        ret = list(repo.iter_inventories([]))
 
4305
        self.assertEquals(ret, [])
 
4306
 
 
4307
    def test_missing(self):
 
4308
        transport_path = 'quack'
 
4309
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4310
        client.add_expected_call(
 
4311
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4312
            'success', ('ok', ), iter([]))
 
4313
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4314
            ["somerevid"]))