~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-09 20:55:07 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120109205507-2i3en5r4w4ohdchj
Use idioms coherently and add comments to make their purpose clearer.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
 
26
26
import bz2
27
27
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
30
from bzrlib import (
30
31
    branch,
31
32
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    graph as _mod_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 TestBzrDirDestroyBranch(TestRemote):
 
545
 
 
546
    def test_destroy_default(self):
 
547
        transport = self.get_transport('quack')
 
548
        referenced = self.make_branch('referenced')
 
549
        client = FakeClient(transport.base)
 
550
        client.add_expected_call(
 
551
            'BzrDir.destroy_branch', ('quack/', ),
 
552
            'success', ('ok',)),
 
553
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
554
            _client=client)
 
555
        a_bzrdir.destroy_branch()
 
556
        self.assertFinished(client)
 
557
 
 
558
    def test_destroy_named(self):
 
559
        transport = self.get_transport('quack')
 
560
        referenced = self.make_branch('referenced')
 
561
        client = FakeClient(transport.base)
 
562
        client.add_expected_call(
 
563
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
564
            'success', ('ok',)),
 
565
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
566
            _client=client)
 
567
        a_bzrdir.destroy_branch("foo")
 
568
        self.assertFinished(client)
 
569
 
 
570
 
 
571
class TestBzrDirHasWorkingTree(TestRemote):
 
572
 
 
573
    def test_has_workingtree(self):
 
574
        transport = self.get_transport('quack')
 
575
        client = FakeClient(transport.base)
 
576
        client.add_expected_call(
 
577
            'BzrDir.has_workingtree', ('quack/',),
 
578
            'success', ('yes',)),
 
579
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
580
            _client=client)
 
581
        self.assertTrue(a_bzrdir.has_workingtree())
 
582
        self.assertFinished(client)
 
583
 
 
584
    def test_no_workingtree(self):
 
585
        transport = self.get_transport('quack')
 
586
        client = FakeClient(transport.base)
 
587
        client.add_expected_call(
 
588
            'BzrDir.has_workingtree', ('quack/',),
 
589
            'success', ('no',)),
 
590
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
591
            _client=client)
 
592
        self.assertFalse(a_bzrdir.has_workingtree())
 
593
        self.assertFinished(client)
 
594
 
 
595
 
 
596
class TestBzrDirDestroyRepository(TestRemote):
 
597
 
 
598
    def test_destroy_repository(self):
 
599
        transport = self.get_transport('quack')
 
600
        client = FakeClient(transport.base)
 
601
        client.add_expected_call(
 
602
            'BzrDir.destroy_repository', ('quack/',),
 
603
            'success', ('ok',)),
 
604
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
605
            _client=client)
 
606
        a_bzrdir.destroy_repository()
 
607
        self.assertFinished(client)
 
608
 
483
609
 
484
610
class TestBzrDirOpen(TestRemote):
485
611
 
495
621
        client.add_expected_call(
496
622
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
623
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
624
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
625
        self.assertFinished(client)
500
626
 
501
627
    def test_present_without_workingtree(self):
502
628
        client, transport = self.make_fake_client_and_transport()
503
629
        client.add_expected_call(
504
630
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
631
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
632
            _client=client, _force_probe=True)
507
633
        self.assertIsInstance(bd, RemoteBzrDir)
508
634
        self.assertFalse(bd.has_workingtree())
513
639
        client, transport = self.make_fake_client_and_transport()
514
640
        client.add_expected_call(
515
641
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
642
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
643
            _client=client, _force_probe=True)
518
644
        self.assertIsInstance(bd, RemoteBzrDir)
519
645
        self.assertTrue(bd.has_workingtree())
526
652
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
653
        client.add_expected_call(
528
654
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
655
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
656
            _client=client, _force_probe=True)
531
657
        self.assertIsInstance(bd, RemoteBzrDir)
532
658
        self.assertFinished(client)
548
674
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
675
        client.add_expected_call(
550
676
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
677
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
678
            _client=client, _force_probe=True)
553
679
        self.assertIsInstance(bd, RemoteBzrDir)
554
680
        self.assertFinished(client)
585
711
        client.add_expected_call(
586
712
            'Branch.get_stacked_on_url', ('quack/',),
587
713
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
714
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
715
            _client=client)
590
716
        result = bzrdir.open_branch()
591
717
        self.assertIsInstance(result, RemoteBranch)
598
724
        transport = transport.clone('quack')
599
725
        client = FakeClient(transport.base)
600
726
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
727
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
728
            _client=client)
603
729
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
730
        self.assertEqual(
609
735
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
736
        # branch opening, not any other network requests.
611
737
        calls = []
612
 
        def open_branch():
 
738
        def open_branch(name=None, possible_transports=None):
613
739
            calls.append("Called")
614
740
            return "a-branch"
615
741
        transport = MemoryTransport()
616
742
        # no requests on the network - catches other api calls being made.
617
743
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
744
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
745
            _client=client)
620
746
        # patch the open_branch call to record that it was called.
621
747
        bzrdir.open_branch = open_branch
640
766
        client.add_expected_call(
641
767
            'Branch.get_stacked_on_url', ('~hello/',),
642
768
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
769
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
770
            _client=client)
645
771
        result = bzrdir.open_branch()
646
772
        self.assertFinished(client)
663
789
        client.add_success_response(
664
790
            'ok', '', rich_response, subtree_response, external_lookup,
665
791
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
792
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
793
            _client=client)
668
794
        result = bzrdir.open_repository()
669
795
        self.assertEqual(
686
812
        old.
687
813
        """
688
814
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
815
            RemoteBzrProber.probe_transport, OldServerTransport())
690
816
 
691
817
 
692
818
class TestBzrDirCreateBranch(TestRemote):
715
841
            'BzrDir.create_branch', ('quack/', network_name),
716
842
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
843
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
844
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
845
            _client=client)
720
846
        branch = a_bzrdir.create_branch()
721
847
        # We should have got a remote branch
724
850
        format = branch._format
725
851
        self.assertEqual(network_name, format.network_name())
726
852
 
 
853
    def test_already_open_repo_and_reused_medium(self):
 
854
        """Bug 726584: create_branch(..., repository=repo) should work
 
855
        regardless of what the smart medium's base URL is.
 
856
        """
 
857
        self.transport_server = test_server.SmartTCPServer_for_testing
 
858
        transport = self.get_transport('.')
 
859
        repo = self.make_repository('quack')
 
860
        # Client's medium rooted a transport root (not at the bzrdir)
 
861
        client = FakeClient(transport.base)
 
862
        transport = transport.clone('quack')
 
863
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
864
        reference_format = reference_bzrdir_format.get_branch_format()
 
865
        network_name = reference_format.network_name()
 
866
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
867
        reference_repo_name = reference_repo_fmt.network_name()
 
868
        client.add_expected_call(
 
869
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
870
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
871
            reference_repo_name))
 
872
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
873
            _client=client)
 
874
        branch = a_bzrdir.create_branch(repository=repo)
 
875
        # We should have got a remote branch
 
876
        self.assertIsInstance(branch, remote.RemoteBranch)
 
877
        # its format should have the settings from the response
 
878
        format = branch._format
 
879
        self.assertEqual(network_name, format.network_name())
 
880
 
727
881
 
728
882
class TestBzrDirCreateRepository(TestRemote):
729
883
 
750
904
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
905
                'False'),
752
906
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
907
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
908
            _client=client)
755
909
        repo = a_bzrdir.create_repository()
756
910
        # We should have got a remote repository
779
933
        # name.
780
934
        client.add_success_response_with_body(
781
935
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
936
        client.add_success_response('stat', '0', '65535')
782
937
        client.add_success_response_with_body(
783
938
            reference_format.get_format_string(), 'ok')
784
939
        # PackRepository wants to do a stat
785
940
        client.add_success_response('stat', '0', '65535')
786
941
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
942
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
943
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
944
            _client=client)
790
945
        repo = bzrdir.open_repository()
791
946
        self.assertEqual(
793
948
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
949
             ('call', 'BzrDir.find_repository', ('quack/',)),
795
950
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
951
             ('call', 'stat', ('/quack/.bzr',)),
796
952
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
953
             ('call', 'stat', ('/quack/.bzr/repository',)),
798
954
             ],
812
968
        # name.
813
969
        client.add_success_response_with_body(
814
970
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
971
        client.add_success_response('stat', '0', '65535')
815
972
        client.add_success_response_with_body(
816
973
            reference_format.get_format_string(), 'ok')
817
974
        # PackRepository wants to do a stat
818
975
        client.add_success_response('stat', '0', '65535')
819
976
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
977
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
978
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
979
            _client=client)
823
980
        repo = bzrdir.open_repository()
824
981
        self.assertEqual(
825
982
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
983
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
984
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
985
             ('call', 'stat', ('/quack/.bzr',)),
828
986
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
987
             ('call', 'stat', ('/quack/.bzr/repository',)),
830
988
             ],
839
997
        transport = transport.clone('quack')
840
998
        client = FakeClient(transport.base)
841
999
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1000
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
1001
            _client=client)
844
1002
        repo = bzrdir.open_repository()
845
1003
        self.assertEqual(
852
1010
 
853
1011
    def test_success(self):
854
1012
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1013
        fmt = RemoteBzrDirFormat()
856
1014
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1015
        transport = self.get_transport()
858
1016
        client = FakeClient(transport.base)
874
1032
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1033
        corresponding error from the client.
876
1034
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1035
        fmt = RemoteBzrDirFormat()
878
1036
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1037
        transport = self.get_transport()
880
1038
        client = FakeClient(transport.base)
898
1056
        """Integration test for error translation."""
899
1057
        transport = self.make_smart_server('foo')
900
1058
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1059
        fmt = RemoteBzrDirFormat()
902
1060
        err = self.assertRaises(errors.NoSuchFile,
903
1061
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1062
 
935
1093
 
936
1094
    def make_remote_bzrdir(self, transport, client):
937
1095
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1096
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1097
            _client=client)
940
1098
 
941
1099
 
967
1125
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1126
 
969
1127
 
 
1128
class TestBranchBreakLock(RemoteBranchTestCase):
 
1129
 
 
1130
    def test_break_lock(self):
 
1131
        transport_path = 'quack'
 
1132
        transport = MemoryTransport()
 
1133
        client = FakeClient(transport.base)
 
1134
        client.add_expected_call(
 
1135
            'Branch.get_stacked_on_url', ('quack/',),
 
1136
            'error', ('NotStacked',))
 
1137
        client.add_expected_call(
 
1138
            'Branch.break_lock', ('quack/',),
 
1139
            'success', ('ok',))
 
1140
        transport.mkdir('quack')
 
1141
        transport = transport.clone('quack')
 
1142
        branch = self.make_remote_branch(transport, client)
 
1143
        branch.break_lock()
 
1144
        self.assertFinished(client)
 
1145
 
 
1146
 
 
1147
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1148
 
 
1149
    def test_get_physical_lock_status_yes(self):
 
1150
        transport = MemoryTransport()
 
1151
        client = FakeClient(transport.base)
 
1152
        client.add_expected_call(
 
1153
            'Branch.get_stacked_on_url', ('quack/',),
 
1154
            'error', ('NotStacked',))
 
1155
        client.add_expected_call(
 
1156
            'Branch.get_physical_lock_status', ('quack/',),
 
1157
            'success', ('yes',))
 
1158
        transport.mkdir('quack')
 
1159
        transport = transport.clone('quack')
 
1160
        branch = self.make_remote_branch(transport, client)
 
1161
        result = branch.get_physical_lock_status()
 
1162
        self.assertFinished(client)
 
1163
        self.assertEqual(True, result)
 
1164
 
 
1165
    def test_get_physical_lock_status_no(self):
 
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.get_physical_lock_status', ('quack/',),
 
1173
            'success', ('no',))
 
1174
        transport.mkdir('quack')
 
1175
        transport = transport.clone('quack')
 
1176
        branch = self.make_remote_branch(transport, client)
 
1177
        result = branch.get_physical_lock_status()
 
1178
        self.assertFinished(client)
 
1179
        self.assertEqual(False, result)
 
1180
 
 
1181
 
970
1182
class TestBranchGetParent(RemoteBranchTestCase):
971
1183
 
972
1184
    def test_no_parent(self):
1061
1273
        self.reset_smart_call_log()
1062
1274
        verb = 'Branch.set_parent_location'
1063
1275
        self.disable_verb(verb)
1064
 
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1276
        branch.lock_write()
 
1277
        try:
 
1278
            branch.set_parent('http://foo/')
 
1279
        finally:
 
1280
            branch.unlock()
 
1281
        self.assertLength(14, self.hpss_calls)
1066
1282
 
1067
1283
 
1068
1284
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1143
1359
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1360
 
1145
1361
 
 
1362
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1363
 
 
1364
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1365
        transport = MemoryTransport()
 
1366
        client = FakeClient(transport.base)
 
1367
        client.add_expected_call(
 
1368
            'Branch.get_stacked_on_url', ('quack/',),
 
1369
            'error', ('NotStacked',))
 
1370
        client.add_expected_call(
 
1371
            'Branch.last_revision_info', ('quack/',),
 
1372
            'success', ('ok', '1', 'rev-tip'))
 
1373
        client.add_expected_call(
 
1374
            'Branch.get_config_file', ('quack/',),
 
1375
            'success', ('ok',), '')
 
1376
        transport.mkdir('quack')
 
1377
        transport = transport.clone('quack')
 
1378
        branch = self.make_remote_branch(transport, client)
 
1379
        result = branch.heads_to_fetch()
 
1380
        self.assertFinished(client)
 
1381
        self.assertEqual((set(['rev-tip']), set()), result)
 
1382
 
 
1383
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1384
        transport = MemoryTransport()
 
1385
        client = FakeClient(transport.base)
 
1386
        client.add_expected_call(
 
1387
            'Branch.get_stacked_on_url', ('quack/',),
 
1388
            'error', ('NotStacked',))
 
1389
        client.add_expected_call(
 
1390
            'Branch.last_revision_info', ('quack/',),
 
1391
            'success', ('ok', '1', 'rev-tip'))
 
1392
        client.add_expected_call(
 
1393
            'Branch.get_config_file', ('quack/',),
 
1394
            'success', ('ok',), 'branch.fetch_tags = True')
 
1395
        # XXX: this will break if the default format's serialization of tags
 
1396
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1397
        client.add_expected_call(
 
1398
            'Branch.get_tags_bytes', ('quack/',),
 
1399
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1400
        transport.mkdir('quack')
 
1401
        transport = transport.clone('quack')
 
1402
        branch = self.make_remote_branch(transport, client)
 
1403
        result = branch.heads_to_fetch()
 
1404
        self.assertFinished(client)
 
1405
        self.assertEqual(
 
1406
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1407
 
 
1408
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1409
        transport = MemoryTransport()
 
1410
        client = FakeClient(transport.base)
 
1411
        client.add_expected_call(
 
1412
            'Branch.get_stacked_on_url', ('quack/',),
 
1413
            'error', ('NotStacked',))
 
1414
        client.add_expected_call(
 
1415
            'Branch.heads_to_fetch', ('quack/',),
 
1416
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1417
        transport.mkdir('quack')
 
1418
        transport = transport.clone('quack')
 
1419
        branch = self.make_remote_branch(transport, client)
 
1420
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1421
        result = branch.heads_to_fetch()
 
1422
        self.assertFinished(client)
 
1423
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1424
 
 
1425
    def make_branch_with_tags(self):
 
1426
        self.setup_smart_server_with_call_log()
 
1427
        # Make a branch with a single revision.
 
1428
        builder = self.make_branch_builder('foo')
 
1429
        builder.start_series()
 
1430
        builder.build_snapshot('tip', None, [
 
1431
            ('add', ('', 'root-id', 'directory', ''))])
 
1432
        builder.finish_series()
 
1433
        branch = builder.get_branch()
 
1434
        # Add two tags to that branch
 
1435
        branch.tags.set_tag('tag-1', 'rev-1')
 
1436
        branch.tags.set_tag('tag-2', 'rev-2')
 
1437
        return branch
 
1438
 
 
1439
    def test_backwards_compatible(self):
 
1440
        br = self.make_branch_with_tags()
 
1441
        br.lock_write()
 
1442
        try:
 
1443
            br.get_config_stack().set('branch.fetch_tags', True)
 
1444
        finally:
 
1445
            br.unlock()
 
1446
        self.addCleanup(br.lock_read().unlock)
 
1447
        # Disable the heads_to_fetch verb
 
1448
        verb = 'Branch.heads_to_fetch'
 
1449
        self.disable_verb(verb)
 
1450
        self.reset_smart_call_log()
 
1451
        result = br.heads_to_fetch()
 
1452
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1453
        self.assertEqual(
 
1454
            ['Branch.last_revision_info', 'Branch.get_tags_bytes'],
 
1455
            [call.call.method for call in self.hpss_calls])
 
1456
 
 
1457
    def test_backwards_compatible_no_tags(self):
 
1458
        br = self.make_branch_with_tags()
 
1459
        br.lock_write()
 
1460
        try:
 
1461
            br.get_config_stack().set('branch.fetch_tags', False)
 
1462
        finally:
 
1463
            br.unlock()
 
1464
        self.addCleanup(br.lock_read().unlock)
 
1465
        # Disable the heads_to_fetch verb
 
1466
        verb = 'Branch.heads_to_fetch'
 
1467
        self.disable_verb(verb)
 
1468
        self.reset_smart_call_log()
 
1469
        result = br.heads_to_fetch()
 
1470
        self.assertEqual((set(['tip']), set()), result)
 
1471
        self.assertEqual(
 
1472
            ['Branch.last_revision_info'],
 
1473
            [call.call.method for call in self.hpss_calls])
 
1474
 
 
1475
 
1146
1476
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1477
 
1148
1478
    def test_empty_branch(self):
1203
1533
        client.add_expected_call(
1204
1534
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1535
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1536
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1537
            _client=client)
1208
1538
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1539
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1566
        # this will also do vfs access, but that goes direct to the transport
1237
1567
        # and isn't seen by the FakeClient.
1238
1568
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1569
            RemoteBzrDirFormat(), _client=client)
1240
1570
        branch = bzrdir.open_branch()
1241
1571
        result = branch.get_stacked_on_url()
1242
1572
        self.assertEqual('../base', result)
1269
1599
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1600
            'success', ('ok', '../base'))
1271
1601
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1602
            RemoteBzrDirFormat(), _client=client)
1273
1603
        branch = bzrdir.open_branch()
1274
1604
        result = branch.get_stacked_on_url()
1275
1605
        self.assertEqual('../base', result)
1283
1613
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1614
 
1285
1615
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1616
        # _set_last_revision_info('null:') is translated to calling
1287
1617
        # Branch.set_last_revision(path, '') on the wire.
1288
1618
        transport = MemoryTransport()
1289
1619
        transport.mkdir('branch')
1307
1637
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1638
            'success', ('ok',))
1309
1639
        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
1640
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1641
        result = branch._set_last_revision(NULL_REVISION)
1315
1642
        branch.unlock()
1316
1643
        self.assertEqual(None, result)
1317
1644
        self.assertFinished(client)
1318
1645
 
1319
1646
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1647
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1648
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1649
        transport = MemoryTransport()
1323
1650
        transport.mkdir('branch')
1344
1671
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1672
            'success', ('ok',))
1346
1673
        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
1674
        # Lock the branch, reset the record of remote calls.
1351
1675
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1676
        result = branch._set_last_revision('rev-id2')
1353
1677
        branch.unlock()
1354
1678
        self.assertEqual(None, result)
1355
1679
        self.assertFinished(client)
1385
1709
        branch = self.make_remote_branch(transport, client)
1386
1710
        branch.lock_write()
1387
1711
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1712
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1713
        branch.unlock()
1390
1714
        self.assertFinished(client)
1391
1715
 
1419
1743
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1744
            'success', ('ok',))
1421
1745
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1746
        branch.lock_write()
1424
1747
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1748
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1749
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1750
            errors.TipChangeRejected,
 
1751
            branch._set_last_revision, 'rev-id')
1428
1752
        # The UTF-8 message from the response has been decoded into a unicode
1429
1753
        # object.
1430
1754
        self.assertIsInstance(err.msg, unicode)
1618
1942
    def test_get_multi_line_branch_conf(self):
1619
1943
        # Make sure that multiple-line branch.conf files are supported
1620
1944
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1945
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1946
        client = FakeClient()
1623
1947
        client.add_expected_call(
1624
1948
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1976
        branch.unlock()
1653
1977
        self.assertFinished(client)
1654
1978
 
 
1979
    def test_set_option_with_dict(self):
 
1980
        client = FakeClient()
 
1981
        client.add_expected_call(
 
1982
            'Branch.get_stacked_on_url', ('memory:///',),
 
1983
            'error', ('NotStacked',),)
 
1984
        client.add_expected_call(
 
1985
            'Branch.lock_write', ('memory:///', '', ''),
 
1986
            'success', ('ok', 'branch token', 'repo token'))
 
1987
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1988
        client.add_expected_call(
 
1989
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1990
            'repo token', encoded_dict_value, 'foo', ''),
 
1991
            'success', ())
 
1992
        client.add_expected_call(
 
1993
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1994
            'success', ('ok',))
 
1995
        transport = MemoryTransport()
 
1996
        branch = self.make_remote_branch(transport, client)
 
1997
        branch.lock_write()
 
1998
        config = branch._get_config()
 
1999
        config.set_option(
 
2000
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2001
            'foo')
 
2002
        branch.unlock()
 
2003
        self.assertFinished(client)
 
2004
 
1655
2005
    def test_backwards_compat_set_option(self):
1656
2006
        self.setup_smart_server_with_call_log()
1657
2007
        branch = self.make_branch('.')
1661
2011
        self.addCleanup(branch.unlock)
1662
2012
        self.reset_smart_call_log()
1663
2013
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2014
        self.assertLength(11, self.hpss_calls)
1665
2015
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2016
 
 
2017
    def test_backwards_compat_set_option_with_dict(self):
 
2018
        self.setup_smart_server_with_call_log()
 
2019
        branch = self.make_branch('.')
 
2020
        verb = 'Branch.set_config_option_dict'
 
2021
        self.disable_verb(verb)
 
2022
        branch.lock_write()
 
2023
        self.addCleanup(branch.unlock)
 
2024
        self.reset_smart_call_log()
 
2025
        config = branch._get_config()
 
2026
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2027
        config.set_option(value_dict, 'name')
 
2028
        self.assertLength(11, self.hpss_calls)
 
2029
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2030
 
 
2031
 
 
2032
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2033
 
 
2034
    def test_get_branch_conf(self):
 
2035
        # in an empty branch we decode the response properly
 
2036
        client = FakeClient()
 
2037
        client.add_expected_call(
 
2038
            'Branch.get_stacked_on_url', ('memory:///',),
 
2039
            'error', ('NotStacked',),)
 
2040
        client.add_success_response_with_body('# config file body', 'ok')
 
2041
        transport = MemoryTransport()
 
2042
        branch = self.make_remote_branch(transport, client)
 
2043
        config = branch.get_config_stack()
 
2044
        config.get("email")
 
2045
        config.get("log_format")
 
2046
        self.assertEqual(
 
2047
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2048
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2049
            client._calls)
 
2050
 
 
2051
    def test_set_branch_conf(self):
 
2052
        client = FakeClient()
 
2053
        client.add_expected_call(
 
2054
            'Branch.get_stacked_on_url', ('memory:///',),
 
2055
            'error', ('NotStacked',),)
 
2056
        client.add_expected_call(
 
2057
            'Branch.lock_write', ('memory:///', '', ''),
 
2058
            'success', ('ok', 'branch token', 'repo token'))
 
2059
        client.add_expected_call(
 
2060
            'Branch.get_config_file', ('memory:///', ),
 
2061
            'success', ('ok', ), "# line 1\n")
 
2062
        client.add_expected_call(
 
2063
            'Branch.get_config_file', ('memory:///', ),
 
2064
            'success', ('ok', ), "# line 1\n")
 
2065
        client.add_expected_call(
 
2066
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2067
            'repo token'),
 
2068
            'success', ('ok',))
 
2069
        client.add_expected_call(
 
2070
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2071
            'success', ('ok',))
 
2072
        transport = MemoryTransport()
 
2073
        branch = self.make_remote_branch(transport, client)
 
2074
        branch.lock_write()
 
2075
        config = branch.get_config_stack()
 
2076
        config.set('email', 'The Dude <lebowski@example.com>')
 
2077
        branch.unlock()
 
2078
        self.assertFinished(client)
 
2079
        self.assertEqual(
 
2080
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2081
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2082
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2083
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2084
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2085
                 ('memory:///', 'branch token', 'repo token'),
 
2086
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2087
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2088
            client._calls)
 
2089
 
1667
2090
 
1668
2091
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2092
 
1683
2106
        self.assertFinished(client)
1684
2107
 
1685
2108
 
 
2109
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2110
 
 
2111
    def test_simple(self):
 
2112
        transport = MemoryTransport()
 
2113
        client = FakeClient(transport.base)
 
2114
        client.add_expected_call(
 
2115
            'Branch.get_stacked_on_url', ('quack/',),
 
2116
            'error', ('NotStacked',),)
 
2117
        client.add_expected_call(
 
2118
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2119
            'success', ('ok', '0',),)
 
2120
        client.add_expected_call(
 
2121
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2122
            'error', ('NoSuchRevision', 'unknown',),)
 
2123
        transport.mkdir('quack')
 
2124
        transport = transport.clone('quack')
 
2125
        branch = self.make_remote_branch(transport, client)
 
2126
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2127
        self.assertRaises(errors.NoSuchRevision,
 
2128
            branch.revision_id_to_revno, 'unknown')
 
2129
        self.assertFinished(client)
 
2130
 
 
2131
    def test_dotted(self):
 
2132
        transport = MemoryTransport()
 
2133
        client = FakeClient(transport.base)
 
2134
        client.add_expected_call(
 
2135
            'Branch.get_stacked_on_url', ('quack/',),
 
2136
            'error', ('NotStacked',),)
 
2137
        client.add_expected_call(
 
2138
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2139
            'success', ('ok', '0',),)
 
2140
        client.add_expected_call(
 
2141
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2142
            'error', ('NoSuchRevision', 'unknown',),)
 
2143
        transport.mkdir('quack')
 
2144
        transport = transport.clone('quack')
 
2145
        branch = self.make_remote_branch(transport, client)
 
2146
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2147
        self.assertRaises(errors.NoSuchRevision,
 
2148
            branch.revision_id_to_dotted_revno, 'unknown')
 
2149
        self.assertFinished(client)
 
2150
 
 
2151
    def test_dotted_no_smart_verb(self):
 
2152
        self.setup_smart_server_with_call_log()
 
2153
        branch = self.make_branch('.')
 
2154
        self.disable_verb('Branch.revision_id_to_revno')
 
2155
        self.reset_smart_call_log()
 
2156
        self.assertEquals((0, ),
 
2157
            branch.revision_id_to_dotted_revno('null:'))
 
2158
        self.assertLength(8, self.hpss_calls)
 
2159
 
 
2160
 
1686
2161
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2162
 
1688
2163
    def test__get_config(self):
1702
2177
        self.reset_smart_call_log()
1703
2178
        config = bzrdir.get_config()
1704
2179
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2180
        self.assertLength(4, self.hpss_calls)
1706
2181
 
1707
2182
    def test_backwards_compat_get_option(self):
1708
2183
        self.setup_smart_server_with_call_log()
1712
2187
        self.reset_smart_call_log()
1713
2188
        self.assertEqual(None,
1714
2189
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2190
        self.assertLength(4, self.hpss_calls)
1716
2191
 
1717
2192
 
1718
2193
class TestTransportIsReadonly(tests.TestCase):
1805
2280
        client = FakeClient(transport.base)
1806
2281
        transport = transport.clone(transport_path)
1807
2282
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2283
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2284
            _client=False)
1810
2285
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2286
        return repo, client
1819
2294
 
1820
2295
    def test_get_format_description(self):
1821
2296
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2297
        real_format = branch.format_registry.get_default()
1823
2298
        remote_format._network_name = real_format.network_name()
1824
2299
        self.assertEqual(remoted_description(real_format),
1825
2300
            remote_format.get_format_description())
1828
2303
class TestRepositoryFormat(TestRemoteRepository):
1829
2304
 
1830
2305
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2306
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2307
        true_format = RemoteRepositoryFormat()
1833
2308
        true_format._network_name = true_name
1834
2309
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2310
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2311
        false_format = RemoteRepositoryFormat()
1837
2312
        false_format._network_name = false_name
1838
2313
        self.assertEqual(False, false_format.fast_deltas)
1839
2314
 
1840
2315
    def test_get_format_description(self):
1841
2316
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2317
        real_format = repository.format_registry.get_default()
1843
2318
        remote_repo_format._network_name = real_format.network_name()
1844
2319
        self.assertEqual(remoted_description(real_format),
1845
2320
            remote_repo_format.get_format_description())
1846
2321
 
1847
2322
 
 
2323
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2324
 
 
2325
    def test_empty(self):
 
2326
        transport_path = 'quack'
 
2327
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2328
        client.add_success_response_with_body('', 'ok')
 
2329
        self.assertEquals([], repo.all_revision_ids())
 
2330
        self.assertEqual(
 
2331
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2332
             ('quack/',))],
 
2333
            client._calls)
 
2334
 
 
2335
    def test_with_some_content(self):
 
2336
        transport_path = 'quack'
 
2337
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2338
        client.add_success_response_with_body(
 
2339
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2340
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2341
            repo.all_revision_ids())
 
2342
        self.assertEqual(
 
2343
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2344
             ('quack/',))],
 
2345
            client._calls)
 
2346
 
 
2347
 
1848
2348
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2349
 
1850
2350
    def test_revid_none(self):
1903
2403
                         result)
1904
2404
 
1905
2405
 
 
2406
class TestRepositoryBreakLock(TestRemoteRepository):
 
2407
 
 
2408
    def test_break_lock(self):
 
2409
        transport_path = 'quack'
 
2410
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2411
        client.add_success_response('ok')
 
2412
        repo.break_lock()
 
2413
        self.assertEqual(
 
2414
            [('call', 'Repository.break_lock', ('quack/',))],
 
2415
            client._calls)
 
2416
 
 
2417
 
 
2418
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2419
 
 
2420
    def test_get_serializer_format(self):
 
2421
        transport_path = 'hill'
 
2422
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2423
        client.add_success_response('ok', '7')
 
2424
        self.assertEquals('7', repo.get_serializer_format())
 
2425
        self.assertEqual(
 
2426
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2427
              ('hill/', ))],
 
2428
            client._calls)
 
2429
 
 
2430
 
 
2431
class TestRepositoryReconcile(TestRemoteRepository):
 
2432
 
 
2433
    def test_reconcile(self):
 
2434
        transport_path = 'hill'
 
2435
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2436
        body = ("garbage_inventories: 2\n"
 
2437
                "inconsistent_parents: 3\n")
 
2438
        client.add_expected_call(
 
2439
            'Repository.lock_write', ('hill/', ''),
 
2440
            'success', ('ok', 'a token'))
 
2441
        client.add_success_response_with_body(body, 'ok')
 
2442
        reconciler = repo.reconcile()
 
2443
        self.assertEqual(
 
2444
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2445
             ('call_expecting_body', 'Repository.reconcile',
 
2446
                ('hill/', 'a token'))],
 
2447
            client._calls)
 
2448
        self.assertEquals(2, reconciler.garbage_inventories)
 
2449
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2450
 
 
2451
 
 
2452
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2453
 
 
2454
    def test_text(self):
 
2455
        # ('ok',), body with signature text
 
2456
        transport_path = 'quack'
 
2457
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2458
        client.add_success_response_with_body(
 
2459
            'THETEXT', 'ok')
 
2460
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2461
        self.assertEqual(
 
2462
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2463
             ('quack/', 'revid'))],
 
2464
            client._calls)
 
2465
 
 
2466
    def test_no_signature(self):
 
2467
        transport_path = 'quick'
 
2468
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2469
        client.add_error_response('nosuchrevision', 'unknown')
 
2470
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2471
                "unknown")
 
2472
        self.assertEqual(
 
2473
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2474
              ('quick/', 'unknown'))],
 
2475
            client._calls)
 
2476
 
 
2477
 
1906
2478
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2479
 
1908
2480
    def test_get_graph(self):
1913
2485
        self.assertNotEqual(graph._parents_provider, repo)
1914
2486
 
1915
2487
 
 
2488
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2489
 
 
2490
    def test_add_signature_text(self):
 
2491
        transport_path = 'quack'
 
2492
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2493
        client.add_expected_call(
 
2494
            'Repository.lock_write', ('quack/', ''),
 
2495
            'success', ('ok', 'a token'))
 
2496
        client.add_expected_call(
 
2497
            'Repository.start_write_group', ('quack/', 'a token'),
 
2498
            'success', ('ok', ('token1', )))
 
2499
        client.add_expected_call(
 
2500
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2501
                'token1'),
 
2502
            'success', ('ok', ), None)
 
2503
        repo.lock_write()
 
2504
        repo.start_write_group()
 
2505
        self.assertIs(None,
 
2506
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2507
        self.assertEqual(
 
2508
            ('call_with_body_bytes_expecting_body',
 
2509
              'Repository.add_signature_text',
 
2510
                ('quack/', 'a token', 'rev1', 'token1'),
 
2511
              'every bloody emperor'),
 
2512
            client._calls[-1])
 
2513
 
 
2514
 
1916
2515
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2516
 
1918
2517
    def test_get_parent_map_caching(self):
1968
2567
        parents = repo.get_parent_map([rev_id])
1969
2568
        self.assertEqual(
1970
2569
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2570
              'Repository.get_parent_map',
 
2571
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2572
             ('disconnect medium',),
1974
2573
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2574
              ('quack/', ''))],
2095
2694
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2695
        self.assertLength(0, self.hpss_calls)
2097
2696
 
 
2697
    def test_exposes_get_cached_parent_map(self):
 
2698
        """RemoteRepository exposes get_cached_parent_map from
 
2699
        _unstacked_provider
 
2700
        """
 
2701
        r1 = u'\u0e33'.encode('utf8')
 
2702
        r2 = u'\u0dab'.encode('utf8')
 
2703
        lines = [' '.join([r2, r1]), r1]
 
2704
        encoded_body = bz2.compress('\n'.join(lines))
 
2705
 
 
2706
        transport_path = 'quack'
 
2707
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2708
        client.add_success_response_with_body(encoded_body, 'ok')
 
2709
        repo.lock_read()
 
2710
        # get_cached_parent_map should *not* trigger an RPC
 
2711
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2712
        self.assertEqual([], client._calls)
 
2713
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2714
        self.assertEqual({r1: (NULL_REVISION,)},
 
2715
            repo.get_cached_parent_map([r1]))
 
2716
        self.assertEqual(
 
2717
            [('call_with_body_bytes_expecting_body',
 
2718
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2719
              '\n\n0')],
 
2720
            client._calls)
 
2721
        repo.unlock()
 
2722
 
2098
2723
 
2099
2724
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2725
 
2115
2740
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2741
 
2117
2742
 
 
2743
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2744
 
 
2745
    def test_hpss_missing_revision(self):
 
2746
        transport_path = 'quack'
 
2747
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2748
        client.add_success_response_with_body(
 
2749
            '', 'ok', '10')
 
2750
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2751
            ['somerev1', 'anotherrev2'])
 
2752
        self.assertEqual(
 
2753
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2754
             ('quack/', ), "somerev1\nanotherrev2")],
 
2755
            client._calls)
 
2756
 
 
2757
    def test_hpss_get_single_revision(self):
 
2758
        transport_path = 'quack'
 
2759
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2760
        somerev1 = Revision("somerev1")
 
2761
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2762
        somerev1.timestamp = 1321828927
 
2763
        somerev1.timezone = -60
 
2764
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2765
        somerev1.message = "Message"
 
2766
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2767
            somerev1))
 
2768
        # Split up body into two bits to make sure the zlib compression object
 
2769
        # gets data fed twice.
 
2770
        client.add_success_response_with_body(
 
2771
                [body[:10], body[10:]], 'ok', '10')
 
2772
        revs = repo.get_revisions(['somerev1'])
 
2773
        self.assertEquals(revs, [somerev1])
 
2774
        self.assertEqual(
 
2775
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2776
             ('quack/', ), "somerev1")],
 
2777
            client._calls)
 
2778
 
 
2779
 
2118
2780
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2781
 
2120
2782
    def test_null_revision(self):
2257
2919
        self.setup_smart_server_with_call_log()
2258
2920
        tree = self.make_branch_and_memory_tree('.')
2259
2921
        tree.lock_write()
 
2922
        tree.add('')
2260
2923
        rev1 = tree.commit('First')
2261
2924
        rev2 = tree.commit('Second')
2262
2925
        tree.unlock()
2270
2933
                              call.call.method == verb])
2271
2934
 
2272
2935
 
 
2936
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2937
 
 
2938
    def test_has_signature_for_revision_id(self):
 
2939
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2940
        transport_path = 'quack'
 
2941
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2942
        client.add_success_response('yes')
 
2943
        result = repo.has_signature_for_revision_id('A')
 
2944
        self.assertEqual(
 
2945
            [('call', 'Repository.has_signature_for_revision_id',
 
2946
              ('quack/', 'A'))],
 
2947
            client._calls)
 
2948
        self.assertEqual(True, result)
 
2949
 
 
2950
    def test_is_not_shared(self):
 
2951
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2952
        transport_path = 'qwack'
 
2953
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2954
        client.add_success_response('no')
 
2955
        result = repo.has_signature_for_revision_id('A')
 
2956
        self.assertEqual(
 
2957
            [('call', 'Repository.has_signature_for_revision_id',
 
2958
              ('qwack/', 'A'))],
 
2959
            client._calls)
 
2960
        self.assertEqual(False, result)
 
2961
 
 
2962
 
 
2963
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2964
 
 
2965
    def test_get_physical_lock_status_yes(self):
 
2966
        transport_path = 'qwack'
 
2967
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2968
        client.add_success_response('yes')
 
2969
        result = repo.get_physical_lock_status()
 
2970
        self.assertEqual(
 
2971
            [('call', 'Repository.get_physical_lock_status',
 
2972
              ('qwack/', ))],
 
2973
            client._calls)
 
2974
        self.assertEqual(True, result)
 
2975
 
 
2976
    def test_get_physical_lock_status_no(self):
 
2977
        transport_path = 'qwack'
 
2978
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2979
        client.add_success_response('no')
 
2980
        result = repo.get_physical_lock_status()
 
2981
        self.assertEqual(
 
2982
            [('call', 'Repository.get_physical_lock_status',
 
2983
              ('qwack/', ))],
 
2984
            client._calls)
 
2985
        self.assertEqual(False, result)
 
2986
 
 
2987
 
2273
2988
class TestRepositoryIsShared(TestRemoteRepository):
2274
2989
 
2275
2990
    def test_is_shared(self):
2295
3010
        self.assertEqual(False, result)
2296
3011
 
2297
3012
 
 
3013
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3014
 
 
3015
    def test_make_working_trees(self):
 
3016
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3017
        transport_path = 'quack'
 
3018
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3019
        client.add_success_response('yes')
 
3020
        result = repo.make_working_trees()
 
3021
        self.assertEqual(
 
3022
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3023
            client._calls)
 
3024
        self.assertEqual(True, result)
 
3025
 
 
3026
    def test_no_working_trees(self):
 
3027
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3028
        transport_path = 'qwack'
 
3029
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3030
        client.add_success_response('no')
 
3031
        result = repo.make_working_trees()
 
3032
        self.assertEqual(
 
3033
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3034
            client._calls)
 
3035
        self.assertEqual(False, result)
 
3036
 
 
3037
 
2298
3038
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3039
 
2300
3040
    def test_lock_write(self):
2301
3041
        transport_path = 'quack'
2302
3042
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3043
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3044
        token = repo.lock_write().repository_token
2305
3045
        self.assertEqual(
2306
3046
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3047
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3048
        self.assertEqual('a token', token)
2309
3049
 
2310
3050
    def test_lock_write_already_locked(self):
2311
3051
        transport_path = 'quack'
2326
3066
            client._calls)
2327
3067
 
2328
3068
 
 
3069
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3070
 
 
3071
    def test_start_write_group(self):
 
3072
        transport_path = 'quack'
 
3073
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3074
        client.add_expected_call(
 
3075
            'Repository.lock_write', ('quack/', ''),
 
3076
            'success', ('ok', 'a token'))
 
3077
        client.add_expected_call(
 
3078
            'Repository.start_write_group', ('quack/', 'a token'),
 
3079
            'success', ('ok', ('token1', )))
 
3080
        repo.lock_write()
 
3081
        repo.start_write_group()
 
3082
 
 
3083
    def test_start_write_group_unsuspendable(self):
 
3084
        # Some repositories do not support suspending write
 
3085
        # groups. For those, fall back to the "real" repository.
 
3086
        transport_path = 'quack'
 
3087
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3088
        def stub_ensure_real():
 
3089
            client._calls.append(('_ensure_real',))
 
3090
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3091
        repo._ensure_real = stub_ensure_real
 
3092
        client.add_expected_call(
 
3093
            'Repository.lock_write', ('quack/', ''),
 
3094
            'success', ('ok', 'a token'))
 
3095
        client.add_expected_call(
 
3096
            'Repository.start_write_group', ('quack/', 'a token'),
 
3097
            'error', ('UnsuspendableWriteGroup',))
 
3098
        repo.lock_write()
 
3099
        repo.start_write_group()
 
3100
        self.assertEquals(client._calls[-2:], [ 
 
3101
            ('_ensure_real',),
 
3102
            ('start_write_group',)])
 
3103
 
 
3104
    def test_commit_write_group(self):
 
3105
        transport_path = 'quack'
 
3106
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3107
        client.add_expected_call(
 
3108
            'Repository.lock_write', ('quack/', ''),
 
3109
            'success', ('ok', 'a token'))
 
3110
        client.add_expected_call(
 
3111
            'Repository.start_write_group', ('quack/', 'a token'),
 
3112
            'success', ('ok', ['token1']))
 
3113
        client.add_expected_call(
 
3114
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3115
            'success', ('ok',))
 
3116
        repo.lock_write()
 
3117
        repo.start_write_group()
 
3118
        repo.commit_write_group()
 
3119
 
 
3120
    def test_abort_write_group(self):
 
3121
        transport_path = 'quack'
 
3122
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3123
        client.add_expected_call(
 
3124
            'Repository.lock_write', ('quack/', ''),
 
3125
            'success', ('ok', 'a token'))
 
3126
        client.add_expected_call(
 
3127
            'Repository.start_write_group', ('quack/', 'a token'),
 
3128
            'success', ('ok', ['token1']))
 
3129
        client.add_expected_call(
 
3130
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3131
            'success', ('ok',))
 
3132
        repo.lock_write()
 
3133
        repo.start_write_group()
 
3134
        repo.abort_write_group(False)
 
3135
 
 
3136
    def test_suspend_write_group(self):
 
3137
        transport_path = 'quack'
 
3138
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3139
        self.assertEquals([], repo.suspend_write_group())
 
3140
 
 
3141
    def test_resume_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.check_write_group', ('quack/', 'a token', ['token1']),
 
3149
            'success', ('ok',))
 
3150
        repo.lock_write()
 
3151
        repo.resume_write_group(['token1'])
 
3152
 
 
3153
 
2329
3154
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3155
 
2331
3156
    def test_backwards_compat(self):
2390
3215
        self.assertEqual([], client._calls)
2391
3216
 
2392
3217
 
 
3218
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3219
    """Test Repository.iter_file_bytes."""
 
3220
 
 
3221
    def test_single(self):
 
3222
        transport_path = 'quack'
 
3223
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3224
        client.add_expected_call(
 
3225
            'Repository.iter_files_bytes', ('quack/', ),
 
3226
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3227
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3228
                "somerev", "myid")]):
 
3229
            self.assertEquals("myid", identifier)
 
3230
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3231
 
 
3232
    def test_missing(self):
 
3233
        transport_path = 'quack'
 
3234
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3235
        client.add_expected_call(
 
3236
            'Repository.iter_files_bytes',
 
3237
                ('quack/', ),
 
3238
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3239
            iter(["absent\0somefile\0somerev\n"]))
 
3240
        self.assertRaises(errors.RevisionNotPresent, list,
 
3241
                repo.iter_files_bytes(
 
3242
                [("somefile", "somerev", "myid")]))
 
3243
 
 
3244
 
2393
3245
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3246
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3247
    tests.
2402
3254
        the client is finished.
2403
3255
        """
2404
3256
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3257
        fmt = repository.format_registry.get_default()
2406
3258
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3259
        self.assertEqual([], resume_tokens)
2408
3260
        self.assertEqual(set(), missing_keys)
2508
3360
                return True
2509
3361
        repo._real_repository = FakeRealRepository()
2510
3362
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3363
        fmt = repository.format_registry.get_default()
2512
3364
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3365
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3366
        # Every record from the first inventory delta should have been sent to
2670
3522
        self.calls = calls
2671
3523
        self._pack_collection = _StubPackCollection(calls)
2672
3524
 
 
3525
    def start_write_group(self):
 
3526
        self.calls.append(('start_write_group',))
 
3527
 
2673
3528
    def is_in_write_group(self):
2674
3529
        return False
2675
3530
 
2734
3589
             ('pack collection autopack',)],
2735
3590
            client._calls)
2736
3591
 
 
3592
    def test_oom_error_reporting(self):
 
3593
        """An out-of-memory condition on the server is reported clearly"""
 
3594
        transport_path = 'quack'
 
3595
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3596
        client.add_expected_call(
 
3597
            'PackRepository.autopack', ('quack/',),
 
3598
            'error', ('MemoryError',))
 
3599
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3600
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3601
 
2737
3602
 
2738
3603
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3604
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3677
            detail='extra detail')
2813
3678
        self.assertEqual(expected_error, translated_error)
2814
3679
 
 
3680
    def test_norepository(self):
 
3681
        bzrdir = self.make_bzrdir('')
 
3682
        translated_error = self.translateTuple(('norepository',),
 
3683
            bzrdir=bzrdir)
 
3684
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3685
        self.assertEqual(expected_error, translated_error)
 
3686
 
2815
3687
    def test_LockContention(self):
2816
3688
        translated_error = self.translateTuple(('LockContention',))
2817
3689
        expected_error = errors.LockContention('(remote lock)')
2845
3717
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3718
        self.assertEqual(expected_error, translated_error)
2847
3719
 
 
3720
    def test_NotStacked(self):
 
3721
        branch = self.make_branch('')
 
3722
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3723
        expected_error = errors.NotStacked(branch)
 
3724
        self.assertEqual(expected_error, translated_error)
 
3725
 
2848
3726
    def test_ReadError_no_args(self):
2849
3727
        path = 'a path'
2850
3728
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3744
 
2867
3745
    def test_PermissionDenied_no_args(self):
2868
3746
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3747
        translated_error = self.translateTuple(('PermissionDenied',),
 
3748
            path=path)
2870
3749
        expected_error = errors.PermissionDenied(path)
2871
3750
        self.assertEqual(expected_error, translated_error)
2872
3751
 
2895
3774
        expected_error = errors.PermissionDenied(path, extra)
2896
3775
        self.assertEqual(expected_error, translated_error)
2897
3776
 
 
3777
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3778
 
 
3779
    def test_NoSuchFile_context_path(self):
 
3780
        local_path = "local path"
 
3781
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3782
            path=local_path)
 
3783
        expected_error = errors.ReadError(local_path)
 
3784
        self.assertEqual(expected_error, translated_error)
 
3785
 
 
3786
    def test_NoSuchFile_without_context(self):
 
3787
        remote_path = "remote path"
 
3788
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3789
        expected_error = errors.ReadError(remote_path)
 
3790
        self.assertEqual(expected_error, translated_error)
 
3791
 
 
3792
    def test_ReadOnlyError(self):
 
3793
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3794
        expected_error = errors.TransportNotPossible("readonly transport")
 
3795
        self.assertEqual(expected_error, translated_error)
 
3796
 
 
3797
    def test_MemoryError(self):
 
3798
        translated_error = self.translateTuple(('MemoryError',))
 
3799
        self.assertStartsWith(str(translated_error),
 
3800
            "remote server out of memory")
 
3801
 
 
3802
    def test_generic_IndexError_no_classname(self):
 
3803
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3804
        translated_error = self.translateErrorFromSmartServer(err)
 
3805
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3806
        self.assertEqual(expected_error, translated_error)
 
3807
 
 
3808
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3809
 
 
3810
    def test_generic_KeyError(self):
 
3811
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3812
        translated_error = self.translateErrorFromSmartServer(err)
 
3813
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3814
        self.assertEqual(expected_error, translated_error)
 
3815
 
2898
3816
 
2899
3817
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3818
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3963
        _, stacked = branch_factory()
3046
3964
        source = stacked.repository._get_source(target_repository_format)
3047
3965
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3966
        stacked.repository._ensure_real()
 
3967
        graph = stacked.repository.get_graph()
 
3968
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3969
                if r != NULL_REVISION]
 
3970
        revs.reverse()
 
3971
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3972
        self.reset_smart_call_log()
3051
3973
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3974
        # We trust that if a revision is in the stream the rest of the new
3055
3975
        # content for it is too, as per our main fetch tests; here we are
3056
3976
        # checking that the revisions are actually included at all, and their
3095
4015
        self.assertEqual(expected_revs, rev_ord)
3096
4016
        # Getting topological sort requires VFS calls still - one of which is
3097
4017
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4018
        self.assertLength(14, self.hpss_calls)
3099
4019
 
3100
4020
    def test_stacked_get_stream_groupcompress(self):
3101
4021
        # Repository._get_source.get_stream() from a stacked repository with
3142
4062
 
3143
4063
    def test_copy_content_into_avoids_revision_history(self):
3144
4064
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4065
        builder = self.make_branch_builder('remote')
 
4066
        builder.build_commit(message="Commit.")
3147
4067
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4068
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4069
        local.repository.fetch(remote_branch.repository)
3150
4070
        self.hpss_calls = []
3151
4071
        remote_branch.copy_content_into(local)
3152
4072
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4073
 
 
4074
    def test_fetch_everything_needs_just_one_call(self):
 
4075
        local = self.make_branch('local')
 
4076
        builder = self.make_branch_builder('remote')
 
4077
        builder.build_commit(message="Commit.")
 
4078
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4079
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4080
        self.hpss_calls = []
 
4081
        local.repository.fetch(
 
4082
            remote_branch.repository,
 
4083
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4084
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4085
 
 
4086
    def override_verb(self, verb_name, verb):
 
4087
        request_handlers = request.request_handlers
 
4088
        orig_verb = request_handlers.get(verb_name)
 
4089
        orig_info = request_handlers.get_info(verb_name)
 
4090
        request_handlers.register(verb_name, verb, override_existing=True)
 
4091
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4092
                override_existing=True, info=orig_info)
 
4093
 
 
4094
    def test_fetch_everything_backwards_compat(self):
 
4095
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4096
        
 
4097
        Pre-2.4 do not support 'everything' searches with the
 
4098
        Repository.get_stream_1.19 verb.
 
4099
        """
 
4100
        verb_log = []
 
4101
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4102
            """A version of the Repository.get_stream_1.19 verb patched to
 
4103
            reject 'everything' searches the way 2.3 and earlier do.
 
4104
            """
 
4105
            def recreate_search(self, repository, search_bytes,
 
4106
                                discard_excess=False):
 
4107
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4108
                if search_bytes == 'everything':
 
4109
                    return (None,
 
4110
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4111
                return super(OldGetStreamVerb,
 
4112
                        self).recreate_search(repository, search_bytes,
 
4113
                            discard_excess=discard_excess)
 
4114
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4115
        local = self.make_branch('local')
 
4116
        builder = self.make_branch_builder('remote')
 
4117
        builder.build_commit(message="Commit.")
 
4118
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4119
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4120
        self.hpss_calls = []
 
4121
        local.repository.fetch(
 
4122
            remote_branch.repository,
 
4123
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4124
        # make sure the overridden verb was used
 
4125
        self.assertLength(1, verb_log)
 
4126
        # more than one HPSS call is needed, but because it's a VFS callback
 
4127
        # its hard to predict exactly how many.
 
4128
        self.assertTrue(len(self.hpss_calls) > 1)
 
4129
 
 
4130
 
 
4131
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4132
    tests.TestCaseWithTransport):
 
4133
    """Ensure correct handling of bound_location modifications.
 
4134
 
 
4135
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4136
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4137
    happen in this context.
 
4138
    """
 
4139
 
 
4140
    def setUp(self):
 
4141
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4142
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4143
 
 
4144
    def make_master_and_checkout(self, master_name, checkout_name):
 
4145
        # Create the master branch and its associated checkout
 
4146
        self.master = self.make_branch_and_tree(master_name)
 
4147
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4148
        # Modify the master branch so there is something to update
 
4149
        self.master.commit('add stuff')
 
4150
        self.last_revid = self.master.commit('even more stuff')
 
4151
        self.bound_location = self.checkout.branch.get_bound_location()
 
4152
 
 
4153
    def assertUpdateSucceeds(self, new_location):
 
4154
        self.checkout.lock_write()
 
4155
        try:
 
4156
            self.checkout.branch.set_bound_location(new_location)
 
4157
            self.checkout.update()
 
4158
        finally:
 
4159
            self.checkout.unlock()
 
4160
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4161
 
 
4162
    def test_without_final_slash(self):
 
4163
        self.make_master_and_checkout('master', 'checkout')
 
4164
        # For unclear reasons some users have a bound_location without a final
 
4165
        # '/', simulate that by forcing such a value
 
4166
        self.assertEndsWith(self.bound_location, '/')
 
4167
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4168
 
 
4169
    def test_plus_sign(self):
 
4170
        self.make_master_and_checkout('+master', 'checkout')
 
4171
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4172
 
 
4173
    def test_tilda(self):
 
4174
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4175
        # interpretation
 
4176
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4177
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4178
 
 
4179
 
 
4180
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4181
 
 
4182
    def test_no_context(self):
 
4183
        class OutOfCoffee(errors.BzrError):
 
4184
            """A dummy exception for testing."""
 
4185
 
 
4186
            def __init__(self, urgency):
 
4187
                self.urgency = urgency
 
4188
        remote.no_context_error_translators.register("OutOfCoffee",
 
4189
            lambda err: OutOfCoffee(err.error_args[0]))
 
4190
        transport = MemoryTransport()
 
4191
        client = FakeClient(transport.base)
 
4192
        client.add_expected_call(
 
4193
            'Branch.get_stacked_on_url', ('quack/',),
 
4194
            'error', ('NotStacked',))
 
4195
        client.add_expected_call(
 
4196
            'Branch.last_revision_info',
 
4197
            ('quack/',),
 
4198
            'error', ('OutOfCoffee', 'low'))
 
4199
        transport.mkdir('quack')
 
4200
        transport = transport.clone('quack')
 
4201
        branch = self.make_remote_branch(transport, client)
 
4202
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4203
        self.assertFinished(client)
 
4204
 
 
4205
    def test_with_context(self):
 
4206
        class OutOfTea(errors.BzrError):
 
4207
            def __init__(self, branch, urgency):
 
4208
                self.branch = branch
 
4209
                self.urgency = urgency
 
4210
        remote.error_translators.register("OutOfTea",
 
4211
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4212
                find("branch")))
 
4213
        transport = MemoryTransport()
 
4214
        client = FakeClient(transport.base)
 
4215
        client.add_expected_call(
 
4216
            'Branch.get_stacked_on_url', ('quack/',),
 
4217
            'error', ('NotStacked',))
 
4218
        client.add_expected_call(
 
4219
            'Branch.last_revision_info',
 
4220
            ('quack/',),
 
4221
            'error', ('OutOfTea', 'low'))
 
4222
        transport.mkdir('quack')
 
4223
        transport = transport.clone('quack')
 
4224
        branch = self.make_remote_branch(transport, client)
 
4225
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4226
        self.assertFinished(client)
 
4227
 
 
4228
 
 
4229
class TestRepositoryPack(TestRemoteRepository):
 
4230
 
 
4231
    def test_pack(self):
 
4232
        transport_path = 'quack'
 
4233
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4234
        client.add_expected_call(
 
4235
            'Repository.lock_write', ('quack/', ''),
 
4236
            'success', ('ok', 'token'))
 
4237
        client.add_expected_call(
 
4238
            'Repository.pack', ('quack/', 'token', 'False'),
 
4239
            'success', ('ok',), )
 
4240
        client.add_expected_call(
 
4241
            'Repository.unlock', ('quack/', 'token'),
 
4242
            'success', ('ok', ))
 
4243
        repo.pack()
 
4244
 
 
4245
    def test_pack_with_hint(self):
 
4246
        transport_path = 'quack'
 
4247
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4248
        client.add_expected_call(
 
4249
            'Repository.lock_write', ('quack/', ''),
 
4250
            'success', ('ok', 'token'))
 
4251
        client.add_expected_call(
 
4252
            'Repository.pack', ('quack/', 'token', 'False'),
 
4253
            'success', ('ok',), )
 
4254
        client.add_expected_call(
 
4255
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4256
            'success', ('ok', ))
 
4257
        repo.pack(['hinta', 'hintb'])
 
4258
 
 
4259
 
 
4260
class TestRepositoryIterInventories(TestRemoteRepository):
 
4261
    """Test Repository.iter_inventories."""
 
4262
 
 
4263
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4264
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4265
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4266
 
 
4267
    def test_single_empty(self):
 
4268
        transport_path = 'quack'
 
4269
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4270
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4271
        repo._format = fmt
 
4272
        stream = [('inventory-deltas', [
 
4273
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4274
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4275
        client.add_expected_call(
 
4276
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4277
            'success', ('ok', ),
 
4278
            _stream_to_byte_stream(stream, fmt))
 
4279
        ret = list(repo.iter_inventories(["somerevid"]))
 
4280
        self.assertLength(1, ret)
 
4281
        inv = ret[0]
 
4282
        self.assertEquals("somerevid", inv.revision_id)
 
4283
 
 
4284
    def test_empty(self):
 
4285
        transport_path = 'quack'
 
4286
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4287
        ret = list(repo.iter_inventories([]))
 
4288
        self.assertEquals(ret, [])
 
4289
 
 
4290
    def test_missing(self):
 
4291
        transport_path = 'quack'
 
4292
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4293
        client.add_expected_call(
 
4294
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4295
            'success', ('ok', ), iter([]))
 
4296
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4297
            ["somerevid"]))