~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-27 16:27:26 UTC
  • mto: This revision was merged to the branch mainline in revision 6449.
  • Revision ID: jelmer@samba.org-20120127162726-f3qlvm7xkfg460ck
Run subtree tests with development-subtree rather than deprecated dirstate-with-subtree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
 
26
26
import bz2
27
27
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
30
from bzrlib import (
30
31
    branch,
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):
1062
1274
        verb = 'Branch.set_parent_location'
1063
1275
        self.disable_verb(verb)
1064
1276
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1277
        self.assertLength(13, self.hpss_calls)
1066
1278
 
1067
1279
 
1068
1280
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1143
1355
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1356
 
1145
1357
 
 
1358
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1359
 
 
1360
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1361
        transport = MemoryTransport()
 
1362
        client = FakeClient(transport.base)
 
1363
        client.add_expected_call(
 
1364
            'Branch.get_stacked_on_url', ('quack/',),
 
1365
            'error', ('NotStacked',))
 
1366
        client.add_expected_call(
 
1367
            'Branch.last_revision_info', ('quack/',),
 
1368
            'success', ('ok', '1', 'rev-tip'))
 
1369
        client.add_expected_call(
 
1370
            'Branch.get_config_file', ('quack/',),
 
1371
            'success', ('ok',), '')
 
1372
        transport.mkdir('quack')
 
1373
        transport = transport.clone('quack')
 
1374
        branch = self.make_remote_branch(transport, client)
 
1375
        result = branch.heads_to_fetch()
 
1376
        self.assertFinished(client)
 
1377
        self.assertEqual((set(['rev-tip']), set()), result)
 
1378
 
 
1379
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1380
        transport = MemoryTransport()
 
1381
        client = FakeClient(transport.base)
 
1382
        client.add_expected_call(
 
1383
            'Branch.get_stacked_on_url', ('quack/',),
 
1384
            'error', ('NotStacked',))
 
1385
        client.add_expected_call(
 
1386
            'Branch.last_revision_info', ('quack/',),
 
1387
            'success', ('ok', '1', 'rev-tip'))
 
1388
        client.add_expected_call(
 
1389
            'Branch.get_config_file', ('quack/',),
 
1390
            'success', ('ok',), 'branch.fetch_tags = True')
 
1391
        # XXX: this will break if the default format's serialization of tags
 
1392
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1393
        client.add_expected_call(
 
1394
            'Branch.get_tags_bytes', ('quack/',),
 
1395
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1396
        transport.mkdir('quack')
 
1397
        transport = transport.clone('quack')
 
1398
        branch = self.make_remote_branch(transport, client)
 
1399
        result = branch.heads_to_fetch()
 
1400
        self.assertFinished(client)
 
1401
        self.assertEqual(
 
1402
            (set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
 
1403
 
 
1404
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1405
        transport = MemoryTransport()
 
1406
        client = FakeClient(transport.base)
 
1407
        client.add_expected_call(
 
1408
            'Branch.get_stacked_on_url', ('quack/',),
 
1409
            'error', ('NotStacked',))
 
1410
        client.add_expected_call(
 
1411
            'Branch.heads_to_fetch', ('quack/',),
 
1412
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1413
        transport.mkdir('quack')
 
1414
        transport = transport.clone('quack')
 
1415
        branch = self.make_remote_branch(transport, client)
 
1416
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1417
        result = branch.heads_to_fetch()
 
1418
        self.assertFinished(client)
 
1419
        self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
 
1420
 
 
1421
    def make_branch_with_tags(self):
 
1422
        self.setup_smart_server_with_call_log()
 
1423
        # Make a branch with a single revision.
 
1424
        builder = self.make_branch_builder('foo')
 
1425
        builder.start_series()
 
1426
        builder.build_snapshot('tip', None, [
 
1427
            ('add', ('', 'root-id', 'directory', ''))])
 
1428
        builder.finish_series()
 
1429
        branch = builder.get_branch()
 
1430
        # Add two tags to that branch
 
1431
        branch.tags.set_tag('tag-1', 'rev-1')
 
1432
        branch.tags.set_tag('tag-2', 'rev-2')
 
1433
        return branch
 
1434
 
 
1435
    def test_backwards_compatible(self):
 
1436
        branch = self.make_branch_with_tags()
 
1437
        c = branch.get_config_stack()
 
1438
        c.set('branch.fetch_tags', True)
 
1439
        self.addCleanup(branch.lock_read().unlock)
 
1440
        # Disable the heads_to_fetch verb
 
1441
        verb = 'Branch.heads_to_fetch'
 
1442
        self.disable_verb(verb)
 
1443
        self.reset_smart_call_log()
 
1444
        result = branch.heads_to_fetch()
 
1445
        self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
 
1446
        self.assertEqual(
 
1447
            ['Branch.last_revision_info', 'Branch.get_config_file',
 
1448
             'Branch.get_tags_bytes'],
 
1449
            [call.call.method for call in self.hpss_calls])
 
1450
 
 
1451
    def test_backwards_compatible_no_tags(self):
 
1452
        branch = self.make_branch_with_tags()
 
1453
        c = branch.get_config_stack()
 
1454
        c.set('branch.fetch_tags', False)
 
1455
        self.addCleanup(branch.lock_read().unlock)
 
1456
        # Disable the heads_to_fetch verb
 
1457
        verb = 'Branch.heads_to_fetch'
 
1458
        self.disable_verb(verb)
 
1459
        self.reset_smart_call_log()
 
1460
        result = branch.heads_to_fetch()
 
1461
        self.assertEqual((set(['tip']), set()), result)
 
1462
        self.assertEqual(
 
1463
            ['Branch.last_revision_info', 'Branch.get_config_file'],
 
1464
            [call.call.method for call in self.hpss_calls])
 
1465
 
 
1466
 
1146
1467
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1468
 
1148
1469
    def test_empty_branch(self):
1203
1524
        client.add_expected_call(
1204
1525
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1526
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1527
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1528
            _client=client)
1208
1529
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1530
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1557
        # this will also do vfs access, but that goes direct to the transport
1237
1558
        # and isn't seen by the FakeClient.
1238
1559
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1560
            RemoteBzrDirFormat(), _client=client)
1240
1561
        branch = bzrdir.open_branch()
1241
1562
        result = branch.get_stacked_on_url()
1242
1563
        self.assertEqual('../base', result)
1269
1590
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1591
            'success', ('ok', '../base'))
1271
1592
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1593
            RemoteBzrDirFormat(), _client=client)
1273
1594
        branch = bzrdir.open_branch()
1274
1595
        result = branch.get_stacked_on_url()
1275
1596
        self.assertEqual('../base', result)
1283
1604
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1605
 
1285
1606
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1607
        # _set_last_revision_info('null:') is translated to calling
1287
1608
        # Branch.set_last_revision(path, '') on the wire.
1288
1609
        transport = MemoryTransport()
1289
1610
        transport.mkdir('branch')
1307
1628
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1629
            'success', ('ok',))
1309
1630
        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
1631
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1632
        result = branch._set_last_revision(NULL_REVISION)
1315
1633
        branch.unlock()
1316
1634
        self.assertEqual(None, result)
1317
1635
        self.assertFinished(client)
1318
1636
 
1319
1637
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1638
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1639
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1640
        transport = MemoryTransport()
1323
1641
        transport.mkdir('branch')
1344
1662
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1663
            'success', ('ok',))
1346
1664
        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
1665
        # Lock the branch, reset the record of remote calls.
1351
1666
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1667
        result = branch._set_last_revision('rev-id2')
1353
1668
        branch.unlock()
1354
1669
        self.assertEqual(None, result)
1355
1670
        self.assertFinished(client)
1385
1700
        branch = self.make_remote_branch(transport, client)
1386
1701
        branch.lock_write()
1387
1702
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1703
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1704
        branch.unlock()
1390
1705
        self.assertFinished(client)
1391
1706
 
1419
1734
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1735
            'success', ('ok',))
1421
1736
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1737
        branch.lock_write()
1424
1738
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1739
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1740
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1741
            errors.TipChangeRejected,
 
1742
            branch._set_last_revision, 'rev-id')
1428
1743
        # The UTF-8 message from the response has been decoded into a unicode
1429
1744
        # object.
1430
1745
        self.assertIsInstance(err.msg, unicode)
1618
1933
    def test_get_multi_line_branch_conf(self):
1619
1934
        # Make sure that multiple-line branch.conf files are supported
1620
1935
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1936
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1937
        client = FakeClient()
1623
1938
        client.add_expected_call(
1624
1939
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1967
        branch.unlock()
1653
1968
        self.assertFinished(client)
1654
1969
 
 
1970
    def test_set_option_with_dict(self):
 
1971
        client = FakeClient()
 
1972
        client.add_expected_call(
 
1973
            'Branch.get_stacked_on_url', ('memory:///',),
 
1974
            'error', ('NotStacked',),)
 
1975
        client.add_expected_call(
 
1976
            'Branch.lock_write', ('memory:///', '', ''),
 
1977
            'success', ('ok', 'branch token', 'repo token'))
 
1978
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1979
        client.add_expected_call(
 
1980
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1981
            'repo token', encoded_dict_value, 'foo', ''),
 
1982
            'success', ())
 
1983
        client.add_expected_call(
 
1984
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
1985
            'success', ('ok',))
 
1986
        transport = MemoryTransport()
 
1987
        branch = self.make_remote_branch(transport, client)
 
1988
        branch.lock_write()
 
1989
        config = branch._get_config()
 
1990
        config.set_option(
 
1991
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
1992
            'foo')
 
1993
        branch.unlock()
 
1994
        self.assertFinished(client)
 
1995
 
1655
1996
    def test_backwards_compat_set_option(self):
1656
1997
        self.setup_smart_server_with_call_log()
1657
1998
        branch = self.make_branch('.')
1661
2002
        self.addCleanup(branch.unlock)
1662
2003
        self.reset_smart_call_log()
1663
2004
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2005
        self.assertLength(11, self.hpss_calls)
1665
2006
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2007
 
 
2008
    def test_backwards_compat_set_option_with_dict(self):
 
2009
        self.setup_smart_server_with_call_log()
 
2010
        branch = self.make_branch('.')
 
2011
        verb = 'Branch.set_config_option_dict'
 
2012
        self.disable_verb(verb)
 
2013
        branch.lock_write()
 
2014
        self.addCleanup(branch.unlock)
 
2015
        self.reset_smart_call_log()
 
2016
        config = branch._get_config()
 
2017
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2018
        config.set_option(value_dict, 'name')
 
2019
        self.assertLength(11, self.hpss_calls)
 
2020
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2021
 
 
2022
 
 
2023
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2024
 
 
2025
    def test_get_branch_conf(self):
 
2026
        # in an empty branch we decode the response properly
 
2027
        client = FakeClient()
 
2028
        client.add_expected_call(
 
2029
            'Branch.get_stacked_on_url', ('memory:///',),
 
2030
            'error', ('NotStacked',),)
 
2031
        client.add_success_response_with_body('# config file body', 'ok')
 
2032
        transport = MemoryTransport()
 
2033
        branch = self.make_remote_branch(transport, client)
 
2034
        config = branch.get_config_stack()
 
2035
        config.get("email")
 
2036
        config.get("log_format")
 
2037
        self.assertEqual(
 
2038
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2039
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2040
            client._calls)
 
2041
 
 
2042
    def test_set_branch_conf(self):
 
2043
        client = FakeClient()
 
2044
        client.add_expected_call(
 
2045
            'Branch.get_stacked_on_url', ('memory:///',),
 
2046
            'error', ('NotStacked',),)
 
2047
        client.add_expected_call(
 
2048
            'Branch.lock_write', ('memory:///', '', ''),
 
2049
            'success', ('ok', 'branch token', 'repo token'))
 
2050
        client.add_expected_call(
 
2051
            'Branch.get_config_file', ('memory:///', ),
 
2052
            'success', ('ok', ), "# line 1\n")
 
2053
        client.add_expected_call(
 
2054
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2055
            'repo token'),
 
2056
            'success', ('ok',))
 
2057
        client.add_expected_call(
 
2058
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2059
            'success', ('ok',))
 
2060
        transport = MemoryTransport()
 
2061
        branch = self.make_remote_branch(transport, client)
 
2062
        branch.lock_write()
 
2063
        config = branch.get_config_stack()
 
2064
        config.set('email', 'The Dude <lebowski@example.com>')
 
2065
        branch.unlock()
 
2066
        self.assertFinished(client)
 
2067
        self.assertEqual(
 
2068
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2069
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2070
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2071
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2072
                 ('memory:///', 'branch token', 'repo token'),
 
2073
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2074
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2075
            client._calls)
 
2076
 
1667
2077
 
1668
2078
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2079
 
1683
2093
        self.assertFinished(client)
1684
2094
 
1685
2095
 
 
2096
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2097
 
 
2098
    def test_simple(self):
 
2099
        transport = MemoryTransport()
 
2100
        client = FakeClient(transport.base)
 
2101
        client.add_expected_call(
 
2102
            'Branch.get_stacked_on_url', ('quack/',),
 
2103
            'error', ('NotStacked',),)
 
2104
        client.add_expected_call(
 
2105
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2106
            'success', ('ok', '0',),)
 
2107
        client.add_expected_call(
 
2108
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2109
            'error', ('NoSuchRevision', 'unknown',),)
 
2110
        transport.mkdir('quack')
 
2111
        transport = transport.clone('quack')
 
2112
        branch = self.make_remote_branch(transport, client)
 
2113
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2114
        self.assertRaises(errors.NoSuchRevision,
 
2115
            branch.revision_id_to_revno, 'unknown')
 
2116
        self.assertFinished(client)
 
2117
 
 
2118
    def test_dotted(self):
 
2119
        transport = MemoryTransport()
 
2120
        client = FakeClient(transport.base)
 
2121
        client.add_expected_call(
 
2122
            'Branch.get_stacked_on_url', ('quack/',),
 
2123
            'error', ('NotStacked',),)
 
2124
        client.add_expected_call(
 
2125
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2126
            'success', ('ok', '0',),)
 
2127
        client.add_expected_call(
 
2128
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2129
            'error', ('NoSuchRevision', 'unknown',),)
 
2130
        transport.mkdir('quack')
 
2131
        transport = transport.clone('quack')
 
2132
        branch = self.make_remote_branch(transport, client)
 
2133
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2134
        self.assertRaises(errors.NoSuchRevision,
 
2135
            branch.revision_id_to_dotted_revno, 'unknown')
 
2136
        self.assertFinished(client)
 
2137
 
 
2138
    def test_dotted_no_smart_verb(self):
 
2139
        self.setup_smart_server_with_call_log()
 
2140
        branch = self.make_branch('.')
 
2141
        self.disable_verb('Branch.revision_id_to_revno')
 
2142
        self.reset_smart_call_log()
 
2143
        self.assertEquals((0, ),
 
2144
            branch.revision_id_to_dotted_revno('null:'))
 
2145
        self.assertLength(8, self.hpss_calls)
 
2146
 
 
2147
 
1686
2148
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2149
 
1688
2150
    def test__get_config(self):
1702
2164
        self.reset_smart_call_log()
1703
2165
        config = bzrdir.get_config()
1704
2166
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2167
        self.assertLength(4, self.hpss_calls)
1706
2168
 
1707
2169
    def test_backwards_compat_get_option(self):
1708
2170
        self.setup_smart_server_with_call_log()
1712
2174
        self.reset_smart_call_log()
1713
2175
        self.assertEqual(None,
1714
2176
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2177
        self.assertLength(4, self.hpss_calls)
1716
2178
 
1717
2179
 
1718
2180
class TestTransportIsReadonly(tests.TestCase):
1805
2267
        client = FakeClient(transport.base)
1806
2268
        transport = transport.clone(transport_path)
1807
2269
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2270
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2271
            _client=False)
1810
2272
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2273
        return repo, client
1819
2281
 
1820
2282
    def test_get_format_description(self):
1821
2283
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2284
        real_format = branch.format_registry.get_default()
1823
2285
        remote_format._network_name = real_format.network_name()
1824
2286
        self.assertEqual(remoted_description(real_format),
1825
2287
            remote_format.get_format_description())
1828
2290
class TestRepositoryFormat(TestRemoteRepository):
1829
2291
 
1830
2292
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2293
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2294
        true_format = RemoteRepositoryFormat()
1833
2295
        true_format._network_name = true_name
1834
2296
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2297
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2298
        false_format = RemoteRepositoryFormat()
1837
2299
        false_format._network_name = false_name
1838
2300
        self.assertEqual(False, false_format.fast_deltas)
1839
2301
 
1840
2302
    def test_get_format_description(self):
1841
2303
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2304
        real_format = repository.format_registry.get_default()
1843
2305
        remote_repo_format._network_name = real_format.network_name()
1844
2306
        self.assertEqual(remoted_description(real_format),
1845
2307
            remote_repo_format.get_format_description())
1846
2308
 
1847
2309
 
 
2310
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2311
 
 
2312
    def test_empty(self):
 
2313
        transport_path = 'quack'
 
2314
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2315
        client.add_success_response_with_body('', 'ok')
 
2316
        self.assertEquals([], repo.all_revision_ids())
 
2317
        self.assertEqual(
 
2318
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2319
             ('quack/',))],
 
2320
            client._calls)
 
2321
 
 
2322
    def test_with_some_content(self):
 
2323
        transport_path = 'quack'
 
2324
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2325
        client.add_success_response_with_body(
 
2326
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2327
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2328
            repo.all_revision_ids())
 
2329
        self.assertEqual(
 
2330
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2331
             ('quack/',))],
 
2332
            client._calls)
 
2333
 
 
2334
 
1848
2335
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2336
 
1850
2337
    def test_revid_none(self):
1903
2390
                         result)
1904
2391
 
1905
2392
 
 
2393
class TestRepositoryBreakLock(TestRemoteRepository):
 
2394
 
 
2395
    def test_break_lock(self):
 
2396
        transport_path = 'quack'
 
2397
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2398
        client.add_success_response('ok')
 
2399
        repo.break_lock()
 
2400
        self.assertEqual(
 
2401
            [('call', 'Repository.break_lock', ('quack/',))],
 
2402
            client._calls)
 
2403
 
 
2404
 
 
2405
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2406
 
 
2407
    def test_get_serializer_format(self):
 
2408
        transport_path = 'hill'
 
2409
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2410
        client.add_success_response('ok', '7')
 
2411
        self.assertEquals('7', repo.get_serializer_format())
 
2412
        self.assertEqual(
 
2413
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2414
              ('hill/', ))],
 
2415
            client._calls)
 
2416
 
 
2417
 
 
2418
class TestRepositoryReconcile(TestRemoteRepository):
 
2419
 
 
2420
    def test_reconcile(self):
 
2421
        transport_path = 'hill'
 
2422
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2423
        body = ("garbage_inventories: 2\n"
 
2424
                "inconsistent_parents: 3\n")
 
2425
        client.add_expected_call(
 
2426
            'Repository.lock_write', ('hill/', ''),
 
2427
            'success', ('ok', 'a token'))
 
2428
        client.add_success_response_with_body(body, 'ok')
 
2429
        reconciler = repo.reconcile()
 
2430
        self.assertEqual(
 
2431
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2432
             ('call_expecting_body', 'Repository.reconcile',
 
2433
                ('hill/', 'a token'))],
 
2434
            client._calls)
 
2435
        self.assertEquals(2, reconciler.garbage_inventories)
 
2436
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2437
 
 
2438
 
 
2439
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2440
 
 
2441
    def test_text(self):
 
2442
        # ('ok',), body with signature text
 
2443
        transport_path = 'quack'
 
2444
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2445
        client.add_success_response_with_body(
 
2446
            'THETEXT', 'ok')
 
2447
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2448
        self.assertEqual(
 
2449
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2450
             ('quack/', 'revid'))],
 
2451
            client._calls)
 
2452
 
 
2453
    def test_no_signature(self):
 
2454
        transport_path = 'quick'
 
2455
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2456
        client.add_error_response('nosuchrevision', 'unknown')
 
2457
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2458
                "unknown")
 
2459
        self.assertEqual(
 
2460
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2461
              ('quick/', 'unknown'))],
 
2462
            client._calls)
 
2463
 
 
2464
 
1906
2465
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2466
 
1908
2467
    def test_get_graph(self):
1913
2472
        self.assertNotEqual(graph._parents_provider, repo)
1914
2473
 
1915
2474
 
 
2475
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2476
 
 
2477
    def test_add_signature_text(self):
 
2478
        transport_path = 'quack'
 
2479
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2480
        client.add_expected_call(
 
2481
            'Repository.lock_write', ('quack/', ''),
 
2482
            'success', ('ok', 'a token'))
 
2483
        client.add_expected_call(
 
2484
            'Repository.start_write_group', ('quack/', 'a token'),
 
2485
            'success', ('ok', ('token1', )))
 
2486
        client.add_expected_call(
 
2487
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2488
                'token1'),
 
2489
            'success', ('ok', ), None)
 
2490
        repo.lock_write()
 
2491
        repo.start_write_group()
 
2492
        self.assertIs(None,
 
2493
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2494
        self.assertEqual(
 
2495
            ('call_with_body_bytes_expecting_body',
 
2496
              'Repository.add_signature_text',
 
2497
                ('quack/', 'a token', 'rev1', 'token1'),
 
2498
              'every bloody emperor'),
 
2499
            client._calls[-1])
 
2500
 
 
2501
 
1916
2502
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2503
 
1918
2504
    def test_get_parent_map_caching(self):
1968
2554
        parents = repo.get_parent_map([rev_id])
1969
2555
        self.assertEqual(
1970
2556
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2557
              'Repository.get_parent_map',
 
2558
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2559
             ('disconnect medium',),
1974
2560
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2561
              ('quack/', ''))],
2095
2681
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2682
        self.assertLength(0, self.hpss_calls)
2097
2683
 
 
2684
    def test_exposes_get_cached_parent_map(self):
 
2685
        """RemoteRepository exposes get_cached_parent_map from
 
2686
        _unstacked_provider
 
2687
        """
 
2688
        r1 = u'\u0e33'.encode('utf8')
 
2689
        r2 = u'\u0dab'.encode('utf8')
 
2690
        lines = [' '.join([r2, r1]), r1]
 
2691
        encoded_body = bz2.compress('\n'.join(lines))
 
2692
 
 
2693
        transport_path = 'quack'
 
2694
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2695
        client.add_success_response_with_body(encoded_body, 'ok')
 
2696
        repo.lock_read()
 
2697
        # get_cached_parent_map should *not* trigger an RPC
 
2698
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2699
        self.assertEqual([], client._calls)
 
2700
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2701
        self.assertEqual({r1: (NULL_REVISION,)},
 
2702
            repo.get_cached_parent_map([r1]))
 
2703
        self.assertEqual(
 
2704
            [('call_with_body_bytes_expecting_body',
 
2705
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2706
              '\n\n0')],
 
2707
            client._calls)
 
2708
        repo.unlock()
 
2709
 
2098
2710
 
2099
2711
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2712
 
2115
2727
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2728
 
2117
2729
 
 
2730
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2731
 
 
2732
    def test_hpss_missing_revision(self):
 
2733
        transport_path = 'quack'
 
2734
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2735
        client.add_success_response_with_body(
 
2736
            '', 'ok', '10')
 
2737
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2738
            ['somerev1', 'anotherrev2'])
 
2739
        self.assertEqual(
 
2740
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2741
             ('quack/', ), "somerev1\nanotherrev2")],
 
2742
            client._calls)
 
2743
 
 
2744
    def test_hpss_get_single_revision(self):
 
2745
        transport_path = 'quack'
 
2746
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2747
        somerev1 = Revision("somerev1")
 
2748
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2749
        somerev1.timestamp = 1321828927
 
2750
        somerev1.timezone = -60
 
2751
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2752
        somerev1.message = "Message"
 
2753
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2754
            somerev1))
 
2755
        # Split up body into two bits to make sure the zlib compression object
 
2756
        # gets data fed twice.
 
2757
        client.add_success_response_with_body(
 
2758
                [body[:10], body[10:]], 'ok', '10')
 
2759
        revs = repo.get_revisions(['somerev1'])
 
2760
        self.assertEquals(revs, [somerev1])
 
2761
        self.assertEqual(
 
2762
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2763
             ('quack/', ), "somerev1")],
 
2764
            client._calls)
 
2765
 
 
2766
 
2118
2767
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2768
 
2120
2769
    def test_null_revision(self):
2257
2906
        self.setup_smart_server_with_call_log()
2258
2907
        tree = self.make_branch_and_memory_tree('.')
2259
2908
        tree.lock_write()
 
2909
        tree.add('')
2260
2910
        rev1 = tree.commit('First')
2261
2911
        rev2 = tree.commit('Second')
2262
2912
        tree.unlock()
2270
2920
                              call.call.method == verb])
2271
2921
 
2272
2922
 
 
2923
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2924
 
 
2925
    def test_has_signature_for_revision_id(self):
 
2926
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2927
        transport_path = 'quack'
 
2928
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2929
        client.add_success_response('yes')
 
2930
        result = repo.has_signature_for_revision_id('A')
 
2931
        self.assertEqual(
 
2932
            [('call', 'Repository.has_signature_for_revision_id',
 
2933
              ('quack/', 'A'))],
 
2934
            client._calls)
 
2935
        self.assertEqual(True, result)
 
2936
 
 
2937
    def test_is_not_shared(self):
 
2938
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2939
        transport_path = 'qwack'
 
2940
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2941
        client.add_success_response('no')
 
2942
        result = repo.has_signature_for_revision_id('A')
 
2943
        self.assertEqual(
 
2944
            [('call', 'Repository.has_signature_for_revision_id',
 
2945
              ('qwack/', 'A'))],
 
2946
            client._calls)
 
2947
        self.assertEqual(False, result)
 
2948
 
 
2949
 
 
2950
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2951
 
 
2952
    def test_get_physical_lock_status_yes(self):
 
2953
        transport_path = 'qwack'
 
2954
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2955
        client.add_success_response('yes')
 
2956
        result = repo.get_physical_lock_status()
 
2957
        self.assertEqual(
 
2958
            [('call', 'Repository.get_physical_lock_status',
 
2959
              ('qwack/', ))],
 
2960
            client._calls)
 
2961
        self.assertEqual(True, result)
 
2962
 
 
2963
    def test_get_physical_lock_status_no(self):
 
2964
        transport_path = 'qwack'
 
2965
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2966
        client.add_success_response('no')
 
2967
        result = repo.get_physical_lock_status()
 
2968
        self.assertEqual(
 
2969
            [('call', 'Repository.get_physical_lock_status',
 
2970
              ('qwack/', ))],
 
2971
            client._calls)
 
2972
        self.assertEqual(False, result)
 
2973
 
 
2974
 
2273
2975
class TestRepositoryIsShared(TestRemoteRepository):
2274
2976
 
2275
2977
    def test_is_shared(self):
2295
2997
        self.assertEqual(False, result)
2296
2998
 
2297
2999
 
 
3000
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3001
 
 
3002
    def test_make_working_trees(self):
 
3003
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3004
        transport_path = 'quack'
 
3005
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3006
        client.add_success_response('yes')
 
3007
        result = repo.make_working_trees()
 
3008
        self.assertEqual(
 
3009
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3010
            client._calls)
 
3011
        self.assertEqual(True, result)
 
3012
 
 
3013
    def test_no_working_trees(self):
 
3014
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3015
        transport_path = 'qwack'
 
3016
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3017
        client.add_success_response('no')
 
3018
        result = repo.make_working_trees()
 
3019
        self.assertEqual(
 
3020
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3021
            client._calls)
 
3022
        self.assertEqual(False, result)
 
3023
 
 
3024
 
2298
3025
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3026
 
2300
3027
    def test_lock_write(self):
2301
3028
        transport_path = 'quack'
2302
3029
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3030
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3031
        token = repo.lock_write().repository_token
2305
3032
        self.assertEqual(
2306
3033
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3034
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3035
        self.assertEqual('a token', token)
2309
3036
 
2310
3037
    def test_lock_write_already_locked(self):
2311
3038
        transport_path = 'quack'
2326
3053
            client._calls)
2327
3054
 
2328
3055
 
 
3056
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3057
 
 
3058
    def test_start_write_group(self):
 
3059
        transport_path = 'quack'
 
3060
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3061
        client.add_expected_call(
 
3062
            'Repository.lock_write', ('quack/', ''),
 
3063
            'success', ('ok', 'a token'))
 
3064
        client.add_expected_call(
 
3065
            'Repository.start_write_group', ('quack/', 'a token'),
 
3066
            'success', ('ok', ('token1', )))
 
3067
        repo.lock_write()
 
3068
        repo.start_write_group()
 
3069
 
 
3070
    def test_start_write_group_unsuspendable(self):
 
3071
        # Some repositories do not support suspending write
 
3072
        # groups. For those, fall back to the "real" repository.
 
3073
        transport_path = 'quack'
 
3074
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3075
        def stub_ensure_real():
 
3076
            client._calls.append(('_ensure_real',))
 
3077
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3078
        repo._ensure_real = stub_ensure_real
 
3079
        client.add_expected_call(
 
3080
            'Repository.lock_write', ('quack/', ''),
 
3081
            'success', ('ok', 'a token'))
 
3082
        client.add_expected_call(
 
3083
            'Repository.start_write_group', ('quack/', 'a token'),
 
3084
            'error', ('UnsuspendableWriteGroup',))
 
3085
        repo.lock_write()
 
3086
        repo.start_write_group()
 
3087
        self.assertEquals(client._calls[-2:], [ 
 
3088
            ('_ensure_real',),
 
3089
            ('start_write_group',)])
 
3090
 
 
3091
    def test_commit_write_group(self):
 
3092
        transport_path = 'quack'
 
3093
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3094
        client.add_expected_call(
 
3095
            'Repository.lock_write', ('quack/', ''),
 
3096
            'success', ('ok', 'a token'))
 
3097
        client.add_expected_call(
 
3098
            'Repository.start_write_group', ('quack/', 'a token'),
 
3099
            'success', ('ok', ['token1']))
 
3100
        client.add_expected_call(
 
3101
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3102
            'success', ('ok',))
 
3103
        repo.lock_write()
 
3104
        repo.start_write_group()
 
3105
        repo.commit_write_group()
 
3106
 
 
3107
    def test_abort_write_group(self):
 
3108
        transport_path = 'quack'
 
3109
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3110
        client.add_expected_call(
 
3111
            'Repository.lock_write', ('quack/', ''),
 
3112
            'success', ('ok', 'a token'))
 
3113
        client.add_expected_call(
 
3114
            'Repository.start_write_group', ('quack/', 'a token'),
 
3115
            'success', ('ok', ['token1']))
 
3116
        client.add_expected_call(
 
3117
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3118
            'success', ('ok',))
 
3119
        repo.lock_write()
 
3120
        repo.start_write_group()
 
3121
        repo.abort_write_group(False)
 
3122
 
 
3123
    def test_suspend_write_group(self):
 
3124
        transport_path = 'quack'
 
3125
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3126
        self.assertEquals([], repo.suspend_write_group())
 
3127
 
 
3128
    def test_resume_write_group(self):
 
3129
        transport_path = 'quack'
 
3130
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3131
        client.add_expected_call(
 
3132
            'Repository.lock_write', ('quack/', ''),
 
3133
            'success', ('ok', 'a token'))
 
3134
        client.add_expected_call(
 
3135
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3136
            'success', ('ok',))
 
3137
        repo.lock_write()
 
3138
        repo.resume_write_group(['token1'])
 
3139
 
 
3140
 
2329
3141
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3142
 
2331
3143
    def test_backwards_compat(self):
2390
3202
        self.assertEqual([], client._calls)
2391
3203
 
2392
3204
 
 
3205
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3206
    """Test Repository.iter_file_bytes."""
 
3207
 
 
3208
    def test_single(self):
 
3209
        transport_path = 'quack'
 
3210
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3211
        client.add_expected_call(
 
3212
            'Repository.iter_files_bytes', ('quack/', ),
 
3213
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3214
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3215
                "somerev", "myid")]):
 
3216
            self.assertEquals("myid", identifier)
 
3217
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3218
 
 
3219
    def test_missing(self):
 
3220
        transport_path = 'quack'
 
3221
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3222
        client.add_expected_call(
 
3223
            'Repository.iter_files_bytes',
 
3224
                ('quack/', ),
 
3225
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3226
            iter(["absent\0somefile\0somerev\n"]))
 
3227
        self.assertRaises(errors.RevisionNotPresent, list,
 
3228
                repo.iter_files_bytes(
 
3229
                [("somefile", "somerev", "myid")]))
 
3230
 
 
3231
 
2393
3232
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3233
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3234
    tests.
2402
3241
        the client is finished.
2403
3242
        """
2404
3243
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3244
        fmt = repository.format_registry.get_default()
2406
3245
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3246
        self.assertEqual([], resume_tokens)
2408
3247
        self.assertEqual(set(), missing_keys)
2508
3347
                return True
2509
3348
        repo._real_repository = FakeRealRepository()
2510
3349
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3350
        fmt = repository.format_registry.get_default()
2512
3351
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3352
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3353
        # Every record from the first inventory delta should have been sent to
2670
3509
        self.calls = calls
2671
3510
        self._pack_collection = _StubPackCollection(calls)
2672
3511
 
 
3512
    def start_write_group(self):
 
3513
        self.calls.append(('start_write_group',))
 
3514
 
2673
3515
    def is_in_write_group(self):
2674
3516
        return False
2675
3517
 
2734
3576
             ('pack collection autopack',)],
2735
3577
            client._calls)
2736
3578
 
 
3579
    def test_oom_error_reporting(self):
 
3580
        """An out-of-memory condition on the server is reported clearly"""
 
3581
        transport_path = 'quack'
 
3582
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3583
        client.add_expected_call(
 
3584
            'PackRepository.autopack', ('quack/',),
 
3585
            'error', ('MemoryError',))
 
3586
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3587
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3588
 
2737
3589
 
2738
3590
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3591
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3664
            detail='extra detail')
2813
3665
        self.assertEqual(expected_error, translated_error)
2814
3666
 
 
3667
    def test_norepository(self):
 
3668
        bzrdir = self.make_bzrdir('')
 
3669
        translated_error = self.translateTuple(('norepository',),
 
3670
            bzrdir=bzrdir)
 
3671
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3672
        self.assertEqual(expected_error, translated_error)
 
3673
 
2815
3674
    def test_LockContention(self):
2816
3675
        translated_error = self.translateTuple(('LockContention',))
2817
3676
        expected_error = errors.LockContention('(remote lock)')
2845
3704
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3705
        self.assertEqual(expected_error, translated_error)
2847
3706
 
 
3707
    def test_NotStacked(self):
 
3708
        branch = self.make_branch('')
 
3709
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3710
        expected_error = errors.NotStacked(branch)
 
3711
        self.assertEqual(expected_error, translated_error)
 
3712
 
2848
3713
    def test_ReadError_no_args(self):
2849
3714
        path = 'a path'
2850
3715
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3731
 
2867
3732
    def test_PermissionDenied_no_args(self):
2868
3733
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3734
        translated_error = self.translateTuple(('PermissionDenied',),
 
3735
            path=path)
2870
3736
        expected_error = errors.PermissionDenied(path)
2871
3737
        self.assertEqual(expected_error, translated_error)
2872
3738
 
2895
3761
        expected_error = errors.PermissionDenied(path, extra)
2896
3762
        self.assertEqual(expected_error, translated_error)
2897
3763
 
 
3764
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3765
 
 
3766
    def test_NoSuchFile_context_path(self):
 
3767
        local_path = "local path"
 
3768
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3769
            path=local_path)
 
3770
        expected_error = errors.ReadError(local_path)
 
3771
        self.assertEqual(expected_error, translated_error)
 
3772
 
 
3773
    def test_NoSuchFile_without_context(self):
 
3774
        remote_path = "remote path"
 
3775
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3776
        expected_error = errors.ReadError(remote_path)
 
3777
        self.assertEqual(expected_error, translated_error)
 
3778
 
 
3779
    def test_ReadOnlyError(self):
 
3780
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3781
        expected_error = errors.TransportNotPossible("readonly transport")
 
3782
        self.assertEqual(expected_error, translated_error)
 
3783
 
 
3784
    def test_MemoryError(self):
 
3785
        translated_error = self.translateTuple(('MemoryError',))
 
3786
        self.assertStartsWith(str(translated_error),
 
3787
            "remote server out of memory")
 
3788
 
 
3789
    def test_generic_IndexError_no_classname(self):
 
3790
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3791
        translated_error = self.translateErrorFromSmartServer(err)
 
3792
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3793
        self.assertEqual(expected_error, translated_error)
 
3794
 
 
3795
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3796
 
 
3797
    def test_generic_KeyError(self):
 
3798
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3799
        translated_error = self.translateErrorFromSmartServer(err)
 
3800
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3801
        self.assertEqual(expected_error, translated_error)
 
3802
 
2898
3803
 
2899
3804
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3805
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3950
        _, stacked = branch_factory()
3046
3951
        source = stacked.repository._get_source(target_repository_format)
3047
3952
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3953
        stacked.repository._ensure_real()
 
3954
        graph = stacked.repository.get_graph()
 
3955
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3956
                if r != NULL_REVISION]
 
3957
        revs.reverse()
 
3958
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3959
        self.reset_smart_call_log()
3051
3960
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3961
        # We trust that if a revision is in the stream the rest of the new
3055
3962
        # content for it is too, as per our main fetch tests; here we are
3056
3963
        # checking that the revisions are actually included at all, and their
3095
4002
        self.assertEqual(expected_revs, rev_ord)
3096
4003
        # Getting topological sort requires VFS calls still - one of which is
3097
4004
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4005
        self.assertLength(14, self.hpss_calls)
3099
4006
 
3100
4007
    def test_stacked_get_stream_groupcompress(self):
3101
4008
        # Repository._get_source.get_stream() from a stacked repository with
3142
4049
 
3143
4050
    def test_copy_content_into_avoids_revision_history(self):
3144
4051
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4052
        builder = self.make_branch_builder('remote')
 
4053
        builder.build_commit(message="Commit.")
3147
4054
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4055
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4056
        local.repository.fetch(remote_branch.repository)
3150
4057
        self.hpss_calls = []
3151
4058
        remote_branch.copy_content_into(local)
3152
4059
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4060
 
 
4061
    def test_fetch_everything_needs_just_one_call(self):
 
4062
        local = self.make_branch('local')
 
4063
        builder = self.make_branch_builder('remote')
 
4064
        builder.build_commit(message="Commit.")
 
4065
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4066
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4067
        self.hpss_calls = []
 
4068
        local.repository.fetch(
 
4069
            remote_branch.repository,
 
4070
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4071
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4072
 
 
4073
    def override_verb(self, verb_name, verb):
 
4074
        request_handlers = request.request_handlers
 
4075
        orig_verb = request_handlers.get(verb_name)
 
4076
        orig_info = request_handlers.get_info(verb_name)
 
4077
        request_handlers.register(verb_name, verb, override_existing=True)
 
4078
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4079
                override_existing=True, info=orig_info)
 
4080
 
 
4081
    def test_fetch_everything_backwards_compat(self):
 
4082
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4083
        
 
4084
        Pre-2.4 do not support 'everything' searches with the
 
4085
        Repository.get_stream_1.19 verb.
 
4086
        """
 
4087
        verb_log = []
 
4088
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4089
            """A version of the Repository.get_stream_1.19 verb patched to
 
4090
            reject 'everything' searches the way 2.3 and earlier do.
 
4091
            """
 
4092
            def recreate_search(self, repository, search_bytes,
 
4093
                                discard_excess=False):
 
4094
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4095
                if search_bytes == 'everything':
 
4096
                    return (None,
 
4097
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4098
                return super(OldGetStreamVerb,
 
4099
                        self).recreate_search(repository, search_bytes,
 
4100
                            discard_excess=discard_excess)
 
4101
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4102
        local = self.make_branch('local')
 
4103
        builder = self.make_branch_builder('remote')
 
4104
        builder.build_commit(message="Commit.")
 
4105
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4106
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4107
        self.hpss_calls = []
 
4108
        local.repository.fetch(
 
4109
            remote_branch.repository,
 
4110
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4111
        # make sure the overridden verb was used
 
4112
        self.assertLength(1, verb_log)
 
4113
        # more than one HPSS call is needed, but because it's a VFS callback
 
4114
        # its hard to predict exactly how many.
 
4115
        self.assertTrue(len(self.hpss_calls) > 1)
 
4116
 
 
4117
 
 
4118
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4119
    tests.TestCaseWithTransport):
 
4120
    """Ensure correct handling of bound_location modifications.
 
4121
 
 
4122
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4123
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4124
    happen in this context.
 
4125
    """
 
4126
 
 
4127
    def setUp(self):
 
4128
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4129
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4130
 
 
4131
    def make_master_and_checkout(self, master_name, checkout_name):
 
4132
        # Create the master branch and its associated checkout
 
4133
        self.master = self.make_branch_and_tree(master_name)
 
4134
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4135
        # Modify the master branch so there is something to update
 
4136
        self.master.commit('add stuff')
 
4137
        self.last_revid = self.master.commit('even more stuff')
 
4138
        self.bound_location = self.checkout.branch.get_bound_location()
 
4139
 
 
4140
    def assertUpdateSucceeds(self, new_location):
 
4141
        self.checkout.branch.set_bound_location(new_location)
 
4142
        self.checkout.update()
 
4143
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4144
 
 
4145
    def test_without_final_slash(self):
 
4146
        self.make_master_and_checkout('master', 'checkout')
 
4147
        # For unclear reasons some users have a bound_location without a final
 
4148
        # '/', simulate that by forcing such a value
 
4149
        self.assertEndsWith(self.bound_location, '/')
 
4150
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4151
 
 
4152
    def test_plus_sign(self):
 
4153
        self.make_master_and_checkout('+master', 'checkout')
 
4154
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4155
 
 
4156
    def test_tilda(self):
 
4157
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4158
        # interpretation
 
4159
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4160
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4161
 
 
4162
 
 
4163
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4164
 
 
4165
    def test_no_context(self):
 
4166
        class OutOfCoffee(errors.BzrError):
 
4167
            """A dummy exception for testing."""
 
4168
 
 
4169
            def __init__(self, urgency):
 
4170
                self.urgency = urgency
 
4171
        remote.no_context_error_translators.register("OutOfCoffee",
 
4172
            lambda err: OutOfCoffee(err.error_args[0]))
 
4173
        transport = MemoryTransport()
 
4174
        client = FakeClient(transport.base)
 
4175
        client.add_expected_call(
 
4176
            'Branch.get_stacked_on_url', ('quack/',),
 
4177
            'error', ('NotStacked',))
 
4178
        client.add_expected_call(
 
4179
            'Branch.last_revision_info',
 
4180
            ('quack/',),
 
4181
            'error', ('OutOfCoffee', 'low'))
 
4182
        transport.mkdir('quack')
 
4183
        transport = transport.clone('quack')
 
4184
        branch = self.make_remote_branch(transport, client)
 
4185
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4186
        self.assertFinished(client)
 
4187
 
 
4188
    def test_with_context(self):
 
4189
        class OutOfTea(errors.BzrError):
 
4190
            def __init__(self, branch, urgency):
 
4191
                self.branch = branch
 
4192
                self.urgency = urgency
 
4193
        remote.error_translators.register("OutOfTea",
 
4194
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4195
                find("branch")))
 
4196
        transport = MemoryTransport()
 
4197
        client = FakeClient(transport.base)
 
4198
        client.add_expected_call(
 
4199
            'Branch.get_stacked_on_url', ('quack/',),
 
4200
            'error', ('NotStacked',))
 
4201
        client.add_expected_call(
 
4202
            'Branch.last_revision_info',
 
4203
            ('quack/',),
 
4204
            'error', ('OutOfTea', 'low'))
 
4205
        transport.mkdir('quack')
 
4206
        transport = transport.clone('quack')
 
4207
        branch = self.make_remote_branch(transport, client)
 
4208
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4209
        self.assertFinished(client)
 
4210
 
 
4211
 
 
4212
class TestRepositoryPack(TestRemoteRepository):
 
4213
 
 
4214
    def test_pack(self):
 
4215
        transport_path = 'quack'
 
4216
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4217
        client.add_expected_call(
 
4218
            'Repository.lock_write', ('quack/', ''),
 
4219
            'success', ('ok', 'token'))
 
4220
        client.add_expected_call(
 
4221
            'Repository.pack', ('quack/', 'token', 'False'),
 
4222
            'success', ('ok',), )
 
4223
        client.add_expected_call(
 
4224
            'Repository.unlock', ('quack/', 'token'),
 
4225
            'success', ('ok', ))
 
4226
        repo.pack()
 
4227
 
 
4228
    def test_pack_with_hint(self):
 
4229
        transport_path = 'quack'
 
4230
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4231
        client.add_expected_call(
 
4232
            'Repository.lock_write', ('quack/', ''),
 
4233
            'success', ('ok', 'token'))
 
4234
        client.add_expected_call(
 
4235
            'Repository.pack', ('quack/', 'token', 'False'),
 
4236
            'success', ('ok',), )
 
4237
        client.add_expected_call(
 
4238
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4239
            'success', ('ok', ))
 
4240
        repo.pack(['hinta', 'hintb'])
 
4241
 
 
4242
 
 
4243
class TestRepositoryIterInventories(TestRemoteRepository):
 
4244
    """Test Repository.iter_inventories."""
 
4245
 
 
4246
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4247
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4248
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4249
 
 
4250
    def test_single_empty(self):
 
4251
        transport_path = 'quack'
 
4252
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4253
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4254
        repo._format = fmt
 
4255
        stream = [('inventory-deltas', [
 
4256
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4257
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4258
        client.add_expected_call(
 
4259
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4260
            'success', ('ok', ),
 
4261
            _stream_to_byte_stream(stream, fmt))
 
4262
        ret = list(repo.iter_inventories(["somerevid"]))
 
4263
        self.assertLength(1, ret)
 
4264
        inv = ret[0]
 
4265
        self.assertEquals("somerevid", inv.revision_id)
 
4266
 
 
4267
    def test_empty(self):
 
4268
        transport_path = 'quack'
 
4269
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4270
        ret = list(repo.iter_inventories([]))
 
4271
        self.assertEquals(ret, [])
 
4272
 
 
4273
    def test_missing(self):
 
4274
        transport_path = 'quack'
 
4275
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4276
        client.add_expected_call(
 
4277
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4278
            'success', ('ok', ), iter([]))
 
4279
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4280
            ["somerevid"]))