/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-05 14:26:58 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120105142658-vek3v6pzlxb751s2
Tests passing for a first rough version of a cached branch config store. The changes here are too invasive and several parallel proposals have been made. 

@only_raises is evil and gave a hard time since any exception during
save_changes() was swallowed.

Possible improvements: 

- add some needs_write_lock decorators to crucial
  methods (_set_config_location ?) but keep locking the branch at higher levels

- decorate branch.unlock to call stack.save if last_lock() it True
  outside of @only_raises scope (evil decorator)

- add @needs_write_lock to stack.set and stack.remove (will probably get
  rid of most testing issues) we probably need a specialized decorator
  that can relay to the store and from there to the branch or whatever is
  needed. This will also helps bzr config to get it right. The
  get_mutable_section trick should not be needed anymore either.

- decorate branch.unlock to call stack.save if last_lock() it True outside
  of @only_raises scope (evil decorator)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
25
25
 
26
26
import bz2
27
27
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
30
from bzrlib import (
30
31
    branch,
31
32
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    graph as _mod_graph,
35
37
    inventory,
36
38
    inventory_delta,
37
 
    pack,
38
39
    remote,
39
40
    repository,
40
41
    tests,
 
42
    transport,
41
43
    treebuilder,
42
 
    urlutils,
43
44
    versionedfile,
 
45
    vf_search,
44
46
    )
45
47
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
 
48
from bzrlib.bzrdir import (
 
49
    BzrDir,
 
50
    BzrDirFormat,
 
51
    RemoteBzrProber,
 
52
    )
 
53
from bzrlib.chk_serializer import chk_bencode_serializer
47
54
from bzrlib.remote import (
48
55
    RemoteBranch,
49
56
    RemoteBranchFormat,
52
59
    RemoteRepository,
53
60
    RemoteRepositoryFormat,
54
61
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import medium
 
62
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
 
63
from bzrlib.revision import (
 
64
    NULL_REVISION,
 
65
    Revision,
 
66
    )
 
67
from bzrlib.smart import medium, request
58
68
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
 
69
from bzrlib.smart.repository import (
 
70
    SmartServerRepositoryGetParentMap,
 
71
    SmartServerRepositoryGetStream_1_19,
 
72
    _stream_to_byte_stream,
 
73
    )
 
74
from bzrlib.symbol_versioning import deprecated_in
60
75
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
64
76
    test_server,
65
77
    )
66
 
from bzrlib.transport import get_transport
 
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
79
from bzrlib.transport.memory import MemoryTransport
68
80
from bzrlib.transport.remote import (
69
81
    RemoteTransport,
70
82
    RemoteSSHTransport,
71
83
    RemoteTCPTransport,
72
 
)
73
 
 
74
 
def load_tests(standard_tests, module, loader):
75
 
    to_adapt, result = split_suite_by_condition(
76
 
        standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
 
    smart_server_version_scenarios = [
 
84
    )
 
85
 
 
86
 
 
87
load_tests = load_tests_apply_scenarios
 
88
 
 
89
 
 
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
91
 
 
92
    scenarios = [
78
93
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
94
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
95
        ('HPSS-v3',
81
 
         {'transport_server': test_server.SmartTCPServer_for_testing})]
82
 
    return multiply_tests(to_adapt, smart_server_version_scenarios, result)
83
 
 
84
 
 
85
 
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
96
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
97
 
86
98
 
87
99
    def setUp(self):
88
100
        super(BasicRemoteObjectTests, self).setUp()
89
101
        self.transport = self.get_transport()
90
102
        # make a branch that can be opened over the smart transport
91
103
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
104
        self.addCleanup(self.transport.disconnect)
96
105
 
97
106
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
107
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
108
        self.assertIsInstance(b, BzrDir)
100
109
 
101
110
    def test_open_remote_branch(self):
102
111
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
112
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
113
        branch = b.open_branch()
105
114
        self.assertIsInstance(branch, Branch)
106
115
 
114
123
 
115
124
    def test_remote_branch_revision_history(self):
116
125
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
 
126
        self.assertEqual([],
 
127
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
128
        r1 = self.local_wt.commit('1st commit')
119
129
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
 
130
        self.assertEqual([r1, r2],
 
131
            self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
121
132
 
122
133
    def test_find_correct_format(self):
123
134
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
135
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
136
        self.assertTrue(bzrdir.RemoteBzrProber
 
137
                        in controldir.ControlDirFormat._server_probers)
 
138
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
139
 
129
140
    def test_open_detected_smart_format(self):
130
141
        fmt = BzrDirFormat.find_format(self.transport)
164
175
    def test_remote_branch_set_append_revisions_only(self):
165
176
        # Make a format 1.9 branch, which supports append_revisions_only
166
177
        branch = self.make_branch('branch', format='1.9')
167
 
        config = branch.get_config()
168
178
        branch.set_append_revisions_only(True)
 
179
        config = branch.get_config_stack()
169
180
        self.assertEqual(
170
 
            'True', config.get_user_option('append_revisions_only'))
 
181
            True, config.get('append_revisions_only'))
171
182
        branch.set_append_revisions_only(False)
 
183
        config = branch.get_config_stack()
172
184
        self.assertEqual(
173
 
            'False', config.get_user_option('append_revisions_only'))
 
185
            False, config.get('append_revisions_only'))
174
186
 
175
187
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
176
188
        branch = self.make_branch('branch', format='knit')
177
 
        config = branch.get_config()
178
189
        self.assertRaises(
179
190
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
180
191
 
359
370
        a given client_base and transport_base.
360
371
        """
361
372
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
373
        t = transport.get_transport(transport_base)
 
374
        result = client_medium.remote_path_from_transport(t)
364
375
        self.assertEqual(expected, result)
365
376
 
366
377
    def test_remote_path_from_transport(self):
377
388
        a given transport_base and relpath of that transport.  (Note that
378
389
        HttpTransportBase is a subclass of SmartClientMedium)
379
390
        """
380
 
        base_transport = get_transport(transport_base)
 
391
        base_transport = transport.get_transport(transport_base)
381
392
        client_medium = base_transport.get_smart_medium()
382
393
        cloned_transport = base_transport.clone(relpath)
383
394
        result = client_medium.remote_path_from_transport(cloned_transport)
450
461
        client.add_expected_call(
451
462
            'BzrDir.open_branchV3', ('quack/',),
452
463
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
464
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
465
            _client=client)
455
466
        result = a_bzrdir.cloning_metadir()
456
467
        # We should have got a control dir matching the referenced branch.
469
480
        client.add_expected_call(
470
481
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
482
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
483
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
484
            _client=client)
474
485
        result = a_bzrdir.cloning_metadir()
475
486
        # We should have got a reference control dir with default branch and
480
491
        self.assertEqual(None, result._branch_format)
481
492
        self.assertFinished(client)
482
493
 
 
494
    def test_unknown(self):
 
495
        transport = self.get_transport('quack')
 
496
        referenced = self.make_branch('referenced')
 
497
        expected = referenced.bzrdir.cloning_metadir()
 
498
        client = FakeClient(transport.base)
 
499
        client.add_expected_call(
 
500
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
501
            'success', ('unknown', 'unknown', ('branch', ''))),
 
502
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
503
            _client=client)
 
504
        self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
 
505
 
 
506
 
 
507
class TestBzrDirCheckoutMetaDir(TestRemote):
 
508
 
 
509
    def test__get_checkout_format(self):
 
510
        transport = MemoryTransport()
 
511
        client = FakeClient(transport.base)
 
512
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
513
        control_name = reference_bzrdir_format.network_name()
 
514
        client.add_expected_call(
 
515
            'BzrDir.checkout_metadir', ('quack/', ),
 
516
            'success', (control_name, '', ''))
 
517
        transport.mkdir('quack')
 
518
        transport = transport.clone('quack')
 
519
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
520
            _client=client)
 
521
        result = a_bzrdir.checkout_metadir()
 
522
        # We should have got a reference control dir with default branch and
 
523
        # repository formats.
 
524
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
525
        self.assertEqual(None, result._repository_format)
 
526
        self.assertEqual(None, result._branch_format)
 
527
        self.assertFinished(client)
 
528
 
 
529
    def test_unknown_format(self):
 
530
        transport = MemoryTransport()
 
531
        client = FakeClient(transport.base)
 
532
        client.add_expected_call(
 
533
            'BzrDir.checkout_metadir', ('quack/',),
 
534
            'success', ('dontknow', '', ''))
 
535
        transport.mkdir('quack')
 
536
        transport = transport.clone('quack')
 
537
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
538
            _client=client)
 
539
        self.assertRaises(errors.UnknownFormatError,
 
540
            a_bzrdir.checkout_metadir)
 
541
        self.assertFinished(client)
 
542
 
 
543
 
 
544
class TestBzrDirDestroyBranch(TestRemote):
 
545
 
 
546
    def test_destroy_default(self):
 
547
        transport = self.get_transport('quack')
 
548
        referenced = self.make_branch('referenced')
 
549
        client = FakeClient(transport.base)
 
550
        client.add_expected_call(
 
551
            'BzrDir.destroy_branch', ('quack/', ),
 
552
            'success', ('ok',)),
 
553
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
554
            _client=client)
 
555
        a_bzrdir.destroy_branch()
 
556
        self.assertFinished(client)
 
557
 
 
558
    def test_destroy_named(self):
 
559
        transport = self.get_transport('quack')
 
560
        referenced = self.make_branch('referenced')
 
561
        client = FakeClient(transport.base)
 
562
        client.add_expected_call(
 
563
            'BzrDir.destroy_branch', ('quack/', "foo"),
 
564
            'success', ('ok',)),
 
565
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
566
            _client=client)
 
567
        a_bzrdir.destroy_branch("foo")
 
568
        self.assertFinished(client)
 
569
 
 
570
 
 
571
class TestBzrDirHasWorkingTree(TestRemote):
 
572
 
 
573
    def test_has_workingtree(self):
 
574
        transport = self.get_transport('quack')
 
575
        client = FakeClient(transport.base)
 
576
        client.add_expected_call(
 
577
            'BzrDir.has_workingtree', ('quack/',),
 
578
            'success', ('yes',)),
 
579
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
580
            _client=client)
 
581
        self.assertTrue(a_bzrdir.has_workingtree())
 
582
        self.assertFinished(client)
 
583
 
 
584
    def test_no_workingtree(self):
 
585
        transport = self.get_transport('quack')
 
586
        client = FakeClient(transport.base)
 
587
        client.add_expected_call(
 
588
            'BzrDir.has_workingtree', ('quack/',),
 
589
            'success', ('no',)),
 
590
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
591
            _client=client)
 
592
        self.assertFalse(a_bzrdir.has_workingtree())
 
593
        self.assertFinished(client)
 
594
 
 
595
 
 
596
class TestBzrDirDestroyRepository(TestRemote):
 
597
 
 
598
    def test_destroy_repository(self):
 
599
        transport = self.get_transport('quack')
 
600
        client = FakeClient(transport.base)
 
601
        client.add_expected_call(
 
602
            'BzrDir.destroy_repository', ('quack/',),
 
603
            'success', ('ok',)),
 
604
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
605
            _client=client)
 
606
        a_bzrdir.destroy_repository()
 
607
        self.assertFinished(client)
 
608
 
483
609
 
484
610
class TestBzrDirOpen(TestRemote):
485
611
 
495
621
        client.add_expected_call(
496
622
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
623
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
624
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
625
        self.assertFinished(client)
500
626
 
501
627
    def test_present_without_workingtree(self):
502
628
        client, transport = self.make_fake_client_and_transport()
503
629
        client.add_expected_call(
504
630
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
631
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
632
            _client=client, _force_probe=True)
507
633
        self.assertIsInstance(bd, RemoteBzrDir)
508
634
        self.assertFalse(bd.has_workingtree())
513
639
        client, transport = self.make_fake_client_and_transport()
514
640
        client.add_expected_call(
515
641
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
642
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
643
            _client=client, _force_probe=True)
518
644
        self.assertIsInstance(bd, RemoteBzrDir)
519
645
        self.assertTrue(bd.has_workingtree())
526
652
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
653
        client.add_expected_call(
528
654
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
655
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
656
            _client=client, _force_probe=True)
531
657
        self.assertIsInstance(bd, RemoteBzrDir)
532
658
        self.assertFinished(client)
548
674
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
675
        client.add_expected_call(
550
676
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
677
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
678
            _client=client, _force_probe=True)
553
679
        self.assertIsInstance(bd, RemoteBzrDir)
554
680
        self.assertFinished(client)
585
711
        client.add_expected_call(
586
712
            'Branch.get_stacked_on_url', ('quack/',),
587
713
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
714
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
715
            _client=client)
590
716
        result = bzrdir.open_branch()
591
717
        self.assertIsInstance(result, RemoteBranch)
598
724
        transport = transport.clone('quack')
599
725
        client = FakeClient(transport.base)
600
726
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
727
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
728
            _client=client)
603
729
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
730
        self.assertEqual(
609
735
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
736
        # branch opening, not any other network requests.
611
737
        calls = []
612
 
        def open_branch():
 
738
        def open_branch(name=None, possible_transports=None):
613
739
            calls.append("Called")
614
740
            return "a-branch"
615
741
        transport = MemoryTransport()
616
742
        # no requests on the network - catches other api calls being made.
617
743
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
744
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
745
            _client=client)
620
746
        # patch the open_branch call to record that it was called.
621
747
        bzrdir.open_branch = open_branch
640
766
        client.add_expected_call(
641
767
            'Branch.get_stacked_on_url', ('~hello/',),
642
768
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
769
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
770
            _client=client)
645
771
        result = bzrdir.open_branch()
646
772
        self.assertFinished(client)
663
789
        client.add_success_response(
664
790
            'ok', '', rich_response, subtree_response, external_lookup,
665
791
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
792
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
793
            _client=client)
668
794
        result = bzrdir.open_repository()
669
795
        self.assertEqual(
686
812
        old.
687
813
        """
688
814
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
815
            RemoteBzrProber.probe_transport, OldServerTransport())
690
816
 
691
817
 
692
818
class TestBzrDirCreateBranch(TestRemote):
715
841
            'BzrDir.create_branch', ('quack/', network_name),
716
842
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
843
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
844
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
719
845
            _client=client)
720
846
        branch = a_bzrdir.create_branch()
721
847
        # We should have got a remote branch
724
850
        format = branch._format
725
851
        self.assertEqual(network_name, format.network_name())
726
852
 
 
853
    def test_already_open_repo_and_reused_medium(self):
 
854
        """Bug 726584: create_branch(..., repository=repo) should work
 
855
        regardless of what the smart medium's base URL is.
 
856
        """
 
857
        self.transport_server = test_server.SmartTCPServer_for_testing
 
858
        transport = self.get_transport('.')
 
859
        repo = self.make_repository('quack')
 
860
        # Client's medium rooted a transport root (not at the bzrdir)
 
861
        client = FakeClient(transport.base)
 
862
        transport = transport.clone('quack')
 
863
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
864
        reference_format = reference_bzrdir_format.get_branch_format()
 
865
        network_name = reference_format.network_name()
 
866
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
867
        reference_repo_name = reference_repo_fmt.network_name()
 
868
        client.add_expected_call(
 
869
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
870
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
871
            reference_repo_name))
 
872
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
873
            _client=client)
 
874
        branch = a_bzrdir.create_branch(repository=repo)
 
875
        # We should have got a remote branch
 
876
        self.assertIsInstance(branch, remote.RemoteBranch)
 
877
        # its format should have the settings from the response
 
878
        format = branch._format
 
879
        self.assertEqual(network_name, format.network_name())
 
880
 
727
881
 
728
882
class TestBzrDirCreateRepository(TestRemote):
729
883
 
750
904
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
905
                'False'),
752
906
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
907
        a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
908
            _client=client)
755
909
        repo = a_bzrdir.create_repository()
756
910
        # We should have got a remote repository
785
939
        client.add_success_response('stat', '0', '65535')
786
940
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
941
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
942
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
943
            _client=client)
790
944
        repo = bzrdir.open_repository()
791
945
        self.assertEqual(
818
972
        client.add_success_response('stat', '0', '65535')
819
973
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
974
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
975
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
976
            _client=client)
823
977
        repo = bzrdir.open_repository()
824
978
        self.assertEqual(
839
993
        transport = transport.clone('quack')
840
994
        client = FakeClient(transport.base)
841
995
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
996
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
997
            _client=client)
844
998
        repo = bzrdir.open_repository()
845
999
        self.assertEqual(
852
1006
 
853
1007
    def test_success(self):
854
1008
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1009
        fmt = RemoteBzrDirFormat()
856
1010
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1011
        transport = self.get_transport()
858
1012
        client = FakeClient(transport.base)
874
1028
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1029
        corresponding error from the client.
876
1030
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1031
        fmt = RemoteBzrDirFormat()
878
1032
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1033
        transport = self.get_transport()
880
1034
        client = FakeClient(transport.base)
898
1052
        """Integration test for error translation."""
899
1053
        transport = self.make_smart_server('foo')
900
1054
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1055
        fmt = RemoteBzrDirFormat()
902
1056
        err = self.assertRaises(errors.NoSuchFile,
903
1057
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1058
 
935
1089
 
936
1090
    def make_remote_bzrdir(self, transport, client):
937
1091
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1092
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1093
            _client=client)
940
1094
 
941
1095
 
967
1121
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1122
 
969
1123
 
 
1124
class TestBranchBreakLock(RemoteBranchTestCase):
 
1125
 
 
1126
    def test_break_lock(self):
 
1127
        transport_path = 'quack'
 
1128
        transport = MemoryTransport()
 
1129
        client = FakeClient(transport.base)
 
1130
        client.add_expected_call(
 
1131
            'Branch.get_stacked_on_url', ('quack/',),
 
1132
            'error', ('NotStacked',))
 
1133
        client.add_expected_call(
 
1134
            'Branch.break_lock', ('quack/',),
 
1135
            'success', ('ok',))
 
1136
        transport.mkdir('quack')
 
1137
        transport = transport.clone('quack')
 
1138
        branch = self.make_remote_branch(transport, client)
 
1139
        branch.break_lock()
 
1140
        self.assertFinished(client)
 
1141
 
 
1142
 
 
1143
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1144
 
 
1145
    def test_get_physical_lock_status_yes(self):
 
1146
        transport = MemoryTransport()
 
1147
        client = FakeClient(transport.base)
 
1148
        client.add_expected_call(
 
1149
            'Branch.get_stacked_on_url', ('quack/',),
 
1150
            'error', ('NotStacked',))
 
1151
        client.add_expected_call(
 
1152
            'Branch.get_physical_lock_status', ('quack/',),
 
1153
            'success', ('yes',))
 
1154
        transport.mkdir('quack')
 
1155
        transport = transport.clone('quack')
 
1156
        branch = self.make_remote_branch(transport, client)
 
1157
        result = branch.get_physical_lock_status()
 
1158
        self.assertFinished(client)
 
1159
        self.assertEqual(True, result)
 
1160
 
 
1161
    def test_get_physical_lock_status_no(self):
 
1162
        transport = MemoryTransport()
 
1163
        client = FakeClient(transport.base)
 
1164
        client.add_expected_call(
 
1165
            'Branch.get_stacked_on_url', ('quack/',),
 
1166
            'error', ('NotStacked',))
 
1167
        client.add_expected_call(
 
1168
            'Branch.get_physical_lock_status', ('quack/',),
 
1169
            'success', ('no',))
 
1170
        transport.mkdir('quack')
 
1171
        transport = transport.clone('quack')
 
1172
        branch = self.make_remote_branch(transport, client)
 
1173
        result = branch.get_physical_lock_status()
 
1174
        self.assertFinished(client)
 
1175
        self.assertEqual(False, result)
 
1176
 
 
1177
 
970
1178
class TestBranchGetParent(RemoteBranchTestCase):
971
1179
 
972
1180
    def test_no_parent(self):
1061
1269
        self.reset_smart_call_log()
1062
1270
        verb = 'Branch.set_parent_location'
1063
1271
        self.disable_verb(verb)
1064
 
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1272
        branch.lock_write()
 
1273
        try:
 
1274
            branch.set_parent('http://foo/')
 
1275
        finally:
 
1276
            branch.unlock()
 
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()
 
1438
        c.set_user_option('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()
 
1454
        c.set_user_option('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('.')
1664
2005
        self.assertLength(10, 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(10, 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.get_config_file', ('memory:///', ),
 
2055
            'success', ('ok', ), "# line 1\n")
 
2056
        client.add_expected_call(
 
2057
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2058
            'repo token'),
 
2059
            'success', ('ok',))
 
2060
        client.add_expected_call(
 
2061
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2062
            'success', ('ok',))
 
2063
        transport = MemoryTransport()
 
2064
        branch = self.make_remote_branch(transport, client)
 
2065
        branch.lock_write()
 
2066
        config = branch.get_config_stack()
 
2067
        config.set('email', 'The Dude <lebowski@example.com>')
 
2068
        branch.unlock()
 
2069
        self.assertFinished(client)
 
2070
        self.assertEqual(
 
2071
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2072
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2073
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2074
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2075
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2076
                 ('memory:///', 'branch token', 'repo token'),
 
2077
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2078
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2079
            client._calls)
 
2080
 
1667
2081
 
1668
2082
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2083
 
1683
2097
        self.assertFinished(client)
1684
2098
 
1685
2099
 
 
2100
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2101
 
 
2102
    def test_simple(self):
 
2103
        transport = MemoryTransport()
 
2104
        client = FakeClient(transport.base)
 
2105
        client.add_expected_call(
 
2106
            'Branch.get_stacked_on_url', ('quack/',),
 
2107
            'error', ('NotStacked',),)
 
2108
        client.add_expected_call(
 
2109
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2110
            'success', ('ok', '0',),)
 
2111
        client.add_expected_call(
 
2112
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2113
            'error', ('NoSuchRevision', 'unknown',),)
 
2114
        transport.mkdir('quack')
 
2115
        transport = transport.clone('quack')
 
2116
        branch = self.make_remote_branch(transport, client)
 
2117
        self.assertEquals(0, branch.revision_id_to_revno('null:'))
 
2118
        self.assertRaises(errors.NoSuchRevision,
 
2119
            branch.revision_id_to_revno, 'unknown')
 
2120
        self.assertFinished(client)
 
2121
 
 
2122
    def test_dotted(self):
 
2123
        transport = MemoryTransport()
 
2124
        client = FakeClient(transport.base)
 
2125
        client.add_expected_call(
 
2126
            'Branch.get_stacked_on_url', ('quack/',),
 
2127
            'error', ('NotStacked',),)
 
2128
        client.add_expected_call(
 
2129
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2130
            'success', ('ok', '0',),)
 
2131
        client.add_expected_call(
 
2132
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2133
            'error', ('NoSuchRevision', 'unknown',),)
 
2134
        transport.mkdir('quack')
 
2135
        transport = transport.clone('quack')
 
2136
        branch = self.make_remote_branch(transport, client)
 
2137
        self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2138
        self.assertRaises(errors.NoSuchRevision,
 
2139
            branch.revision_id_to_dotted_revno, 'unknown')
 
2140
        self.assertFinished(client)
 
2141
 
 
2142
    def test_dotted_no_smart_verb(self):
 
2143
        self.setup_smart_server_with_call_log()
 
2144
        branch = self.make_branch('.')
 
2145
        self.disable_verb('Branch.revision_id_to_revno')
 
2146
        self.reset_smart_call_log()
 
2147
        self.assertEquals((0, ),
 
2148
            branch.revision_id_to_dotted_revno('null:'))
 
2149
        self.assertLength(7, self.hpss_calls)
 
2150
 
 
2151
 
1686
2152
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2153
 
1688
2154
    def test__get_config(self):
1805
2271
        client = FakeClient(transport.base)
1806
2272
        transport = transport.clone(transport_path)
1807
2273
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2274
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2275
            _client=False)
1810
2276
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2277
        return repo, client
1819
2285
 
1820
2286
    def test_get_format_description(self):
1821
2287
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2288
        real_format = branch.format_registry.get_default()
1823
2289
        remote_format._network_name = real_format.network_name()
1824
2290
        self.assertEqual(remoted_description(real_format),
1825
2291
            remote_format.get_format_description())
1828
2294
class TestRepositoryFormat(TestRemoteRepository):
1829
2295
 
1830
2296
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2297
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2298
        true_format = RemoteRepositoryFormat()
1833
2299
        true_format._network_name = true_name
1834
2300
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2301
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2302
        false_format = RemoteRepositoryFormat()
1837
2303
        false_format._network_name = false_name
1838
2304
        self.assertEqual(False, false_format.fast_deltas)
1839
2305
 
1840
2306
    def test_get_format_description(self):
1841
2307
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2308
        real_format = repository.format_registry.get_default()
1843
2309
        remote_repo_format._network_name = real_format.network_name()
1844
2310
        self.assertEqual(remoted_description(real_format),
1845
2311
            remote_repo_format.get_format_description())
1846
2312
 
1847
2313
 
 
2314
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2315
 
 
2316
    def test_empty(self):
 
2317
        transport_path = 'quack'
 
2318
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2319
        client.add_success_response_with_body('', 'ok')
 
2320
        self.assertEquals([], repo.all_revision_ids())
 
2321
        self.assertEqual(
 
2322
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2323
             ('quack/',))],
 
2324
            client._calls)
 
2325
 
 
2326
    def test_with_some_content(self):
 
2327
        transport_path = 'quack'
 
2328
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2329
        client.add_success_response_with_body(
 
2330
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2331
        self.assertEquals(["rev1", "rev2", "anotherrev"],
 
2332
            repo.all_revision_ids())
 
2333
        self.assertEqual(
 
2334
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2335
             ('quack/',))],
 
2336
            client._calls)
 
2337
 
 
2338
 
1848
2339
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2340
 
1850
2341
    def test_revid_none(self):
1903
2394
                         result)
1904
2395
 
1905
2396
 
 
2397
class TestRepositoryBreakLock(TestRemoteRepository):
 
2398
 
 
2399
    def test_break_lock(self):
 
2400
        transport_path = 'quack'
 
2401
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2402
        client.add_success_response('ok')
 
2403
        repo.break_lock()
 
2404
        self.assertEqual(
 
2405
            [('call', 'Repository.break_lock', ('quack/',))],
 
2406
            client._calls)
 
2407
 
 
2408
 
 
2409
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2410
 
 
2411
    def test_get_serializer_format(self):
 
2412
        transport_path = 'hill'
 
2413
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2414
        client.add_success_response('ok', '7')
 
2415
        self.assertEquals('7', repo.get_serializer_format())
 
2416
        self.assertEqual(
 
2417
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2418
              ('hill/', ))],
 
2419
            client._calls)
 
2420
 
 
2421
 
 
2422
class TestRepositoryReconcile(TestRemoteRepository):
 
2423
 
 
2424
    def test_reconcile(self):
 
2425
        transport_path = 'hill'
 
2426
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2427
        body = ("garbage_inventories: 2\n"
 
2428
                "inconsistent_parents: 3\n")
 
2429
        client.add_expected_call(
 
2430
            'Repository.lock_write', ('hill/', ''),
 
2431
            'success', ('ok', 'a token'))
 
2432
        client.add_success_response_with_body(body, 'ok')
 
2433
        reconciler = repo.reconcile()
 
2434
        self.assertEqual(
 
2435
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2436
             ('call_expecting_body', 'Repository.reconcile',
 
2437
                ('hill/', 'a token'))],
 
2438
            client._calls)
 
2439
        self.assertEquals(2, reconciler.garbage_inventories)
 
2440
        self.assertEquals(3, reconciler.inconsistent_parents)
 
2441
 
 
2442
 
 
2443
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2444
 
 
2445
    def test_text(self):
 
2446
        # ('ok',), body with signature text
 
2447
        transport_path = 'quack'
 
2448
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2449
        client.add_success_response_with_body(
 
2450
            'THETEXT', 'ok')
 
2451
        self.assertEquals("THETEXT", repo.get_signature_text("revid"))
 
2452
        self.assertEqual(
 
2453
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2454
             ('quack/', 'revid'))],
 
2455
            client._calls)
 
2456
 
 
2457
    def test_no_signature(self):
 
2458
        transport_path = 'quick'
 
2459
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2460
        client.add_error_response('nosuchrevision', 'unknown')
 
2461
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2462
                "unknown")
 
2463
        self.assertEqual(
 
2464
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2465
              ('quick/', 'unknown'))],
 
2466
            client._calls)
 
2467
 
 
2468
 
1906
2469
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2470
 
1908
2471
    def test_get_graph(self):
1913
2476
        self.assertNotEqual(graph._parents_provider, repo)
1914
2477
 
1915
2478
 
 
2479
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2480
 
 
2481
    def test_add_signature_text(self):
 
2482
        transport_path = 'quack'
 
2483
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2484
        client.add_expected_call(
 
2485
            'Repository.lock_write', ('quack/', ''),
 
2486
            'success', ('ok', 'a token'))
 
2487
        client.add_expected_call(
 
2488
            'Repository.start_write_group', ('quack/', 'a token'),
 
2489
            'success', ('ok', ('token1', )))
 
2490
        client.add_expected_call(
 
2491
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2492
                'token1'),
 
2493
            'success', ('ok', ), None)
 
2494
        repo.lock_write()
 
2495
        repo.start_write_group()
 
2496
        self.assertIs(None,
 
2497
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2498
        self.assertEqual(
 
2499
            ('call_with_body_bytes_expecting_body',
 
2500
              'Repository.add_signature_text',
 
2501
                ('quack/', 'a token', 'rev1', 'token1'),
 
2502
              'every bloody emperor'),
 
2503
            client._calls[-1])
 
2504
 
 
2505
 
1916
2506
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2507
 
1918
2508
    def test_get_parent_map_caching(self):
1968
2558
        parents = repo.get_parent_map([rev_id])
1969
2559
        self.assertEqual(
1970
2560
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2561
              'Repository.get_parent_map',
 
2562
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2563
             ('disconnect medium',),
1974
2564
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2565
              ('quack/', ''))],
2095
2685
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2686
        self.assertLength(0, self.hpss_calls)
2097
2687
 
 
2688
    def test_exposes_get_cached_parent_map(self):
 
2689
        """RemoteRepository exposes get_cached_parent_map from
 
2690
        _unstacked_provider
 
2691
        """
 
2692
        r1 = u'\u0e33'.encode('utf8')
 
2693
        r2 = u'\u0dab'.encode('utf8')
 
2694
        lines = [' '.join([r2, r1]), r1]
 
2695
        encoded_body = bz2.compress('\n'.join(lines))
 
2696
 
 
2697
        transport_path = 'quack'
 
2698
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2699
        client.add_success_response_with_body(encoded_body, 'ok')
 
2700
        repo.lock_read()
 
2701
        # get_cached_parent_map should *not* trigger an RPC
 
2702
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2703
        self.assertEqual([], client._calls)
 
2704
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2705
        self.assertEqual({r1: (NULL_REVISION,)},
 
2706
            repo.get_cached_parent_map([r1]))
 
2707
        self.assertEqual(
 
2708
            [('call_with_body_bytes_expecting_body',
 
2709
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2710
              '\n\n0')],
 
2711
            client._calls)
 
2712
        repo.unlock()
 
2713
 
2098
2714
 
2099
2715
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2716
 
2115
2731
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2732
 
2117
2733
 
 
2734
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2735
 
 
2736
    def test_hpss_missing_revision(self):
 
2737
        transport_path = 'quack'
 
2738
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2739
        client.add_success_response_with_body(
 
2740
            '', 'ok', '10')
 
2741
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2742
            ['somerev1', 'anotherrev2'])
 
2743
        self.assertEqual(
 
2744
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2745
             ('quack/', ), "somerev1\nanotherrev2")],
 
2746
            client._calls)
 
2747
 
 
2748
    def test_hpss_get_single_revision(self):
 
2749
        transport_path = 'quack'
 
2750
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2751
        somerev1 = Revision("somerev1")
 
2752
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2753
        somerev1.timestamp = 1321828927
 
2754
        somerev1.timezone = -60
 
2755
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2756
        somerev1.message = "Message"
 
2757
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2758
            somerev1))
 
2759
        # Split up body into two bits to make sure the zlib compression object
 
2760
        # gets data fed twice.
 
2761
        client.add_success_response_with_body(
 
2762
                [body[:10], body[10:]], 'ok', '10')
 
2763
        revs = repo.get_revisions(['somerev1'])
 
2764
        self.assertEquals(revs, [somerev1])
 
2765
        self.assertEqual(
 
2766
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2767
             ('quack/', ), "somerev1")],
 
2768
            client._calls)
 
2769
 
 
2770
 
2118
2771
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2772
 
2120
2773
    def test_null_revision(self):
2257
2910
        self.setup_smart_server_with_call_log()
2258
2911
        tree = self.make_branch_and_memory_tree('.')
2259
2912
        tree.lock_write()
 
2913
        tree.add('')
2260
2914
        rev1 = tree.commit('First')
2261
2915
        rev2 = tree.commit('Second')
2262
2916
        tree.unlock()
2270
2924
                              call.call.method == verb])
2271
2925
 
2272
2926
 
 
2927
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2928
 
 
2929
    def test_has_signature_for_revision_id(self):
 
2930
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2931
        transport_path = 'quack'
 
2932
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2933
        client.add_success_response('yes')
 
2934
        result = repo.has_signature_for_revision_id('A')
 
2935
        self.assertEqual(
 
2936
            [('call', 'Repository.has_signature_for_revision_id',
 
2937
              ('quack/', 'A'))],
 
2938
            client._calls)
 
2939
        self.assertEqual(True, result)
 
2940
 
 
2941
    def test_is_not_shared(self):
 
2942
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2943
        transport_path = 'qwack'
 
2944
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2945
        client.add_success_response('no')
 
2946
        result = repo.has_signature_for_revision_id('A')
 
2947
        self.assertEqual(
 
2948
            [('call', 'Repository.has_signature_for_revision_id',
 
2949
              ('qwack/', 'A'))],
 
2950
            client._calls)
 
2951
        self.assertEqual(False, result)
 
2952
 
 
2953
 
 
2954
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2955
 
 
2956
    def test_get_physical_lock_status_yes(self):
 
2957
        transport_path = 'qwack'
 
2958
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2959
        client.add_success_response('yes')
 
2960
        result = repo.get_physical_lock_status()
 
2961
        self.assertEqual(
 
2962
            [('call', 'Repository.get_physical_lock_status',
 
2963
              ('qwack/', ))],
 
2964
            client._calls)
 
2965
        self.assertEqual(True, result)
 
2966
 
 
2967
    def test_get_physical_lock_status_no(self):
 
2968
        transport_path = 'qwack'
 
2969
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2970
        client.add_success_response('no')
 
2971
        result = repo.get_physical_lock_status()
 
2972
        self.assertEqual(
 
2973
            [('call', 'Repository.get_physical_lock_status',
 
2974
              ('qwack/', ))],
 
2975
            client._calls)
 
2976
        self.assertEqual(False, result)
 
2977
 
 
2978
 
2273
2979
class TestRepositoryIsShared(TestRemoteRepository):
2274
2980
 
2275
2981
    def test_is_shared(self):
2295
3001
        self.assertEqual(False, result)
2296
3002
 
2297
3003
 
 
3004
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3005
 
 
3006
    def test_make_working_trees(self):
 
3007
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3008
        transport_path = 'quack'
 
3009
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3010
        client.add_success_response('yes')
 
3011
        result = repo.make_working_trees()
 
3012
        self.assertEqual(
 
3013
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3014
            client._calls)
 
3015
        self.assertEqual(True, result)
 
3016
 
 
3017
    def test_no_working_trees(self):
 
3018
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3019
        transport_path = 'qwack'
 
3020
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3021
        client.add_success_response('no')
 
3022
        result = repo.make_working_trees()
 
3023
        self.assertEqual(
 
3024
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3025
            client._calls)
 
3026
        self.assertEqual(False, result)
 
3027
 
 
3028
 
2298
3029
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3030
 
2300
3031
    def test_lock_write(self):
2301
3032
        transport_path = 'quack'
2302
3033
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3034
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3035
        token = repo.lock_write().repository_token
2305
3036
        self.assertEqual(
2306
3037
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3038
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3039
        self.assertEqual('a token', token)
2309
3040
 
2310
3041
    def test_lock_write_already_locked(self):
2311
3042
        transport_path = 'quack'
2326
3057
            client._calls)
2327
3058
 
2328
3059
 
 
3060
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3061
 
 
3062
    def test_start_write_group(self):
 
3063
        transport_path = 'quack'
 
3064
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3065
        client.add_expected_call(
 
3066
            'Repository.lock_write', ('quack/', ''),
 
3067
            'success', ('ok', 'a token'))
 
3068
        client.add_expected_call(
 
3069
            'Repository.start_write_group', ('quack/', 'a token'),
 
3070
            'success', ('ok', ('token1', )))
 
3071
        repo.lock_write()
 
3072
        repo.start_write_group()
 
3073
 
 
3074
    def test_start_write_group_unsuspendable(self):
 
3075
        # Some repositories do not support suspending write
 
3076
        # groups. For those, fall back to the "real" repository.
 
3077
        transport_path = 'quack'
 
3078
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3079
        def stub_ensure_real():
 
3080
            client._calls.append(('_ensure_real',))
 
3081
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3082
        repo._ensure_real = stub_ensure_real
 
3083
        client.add_expected_call(
 
3084
            'Repository.lock_write', ('quack/', ''),
 
3085
            'success', ('ok', 'a token'))
 
3086
        client.add_expected_call(
 
3087
            'Repository.start_write_group', ('quack/', 'a token'),
 
3088
            'error', ('UnsuspendableWriteGroup',))
 
3089
        repo.lock_write()
 
3090
        repo.start_write_group()
 
3091
        self.assertEquals(client._calls[-2:], [ 
 
3092
            ('_ensure_real',),
 
3093
            ('start_write_group',)])
 
3094
 
 
3095
    def test_commit_write_group(self):
 
3096
        transport_path = 'quack'
 
3097
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3098
        client.add_expected_call(
 
3099
            'Repository.lock_write', ('quack/', ''),
 
3100
            'success', ('ok', 'a token'))
 
3101
        client.add_expected_call(
 
3102
            'Repository.start_write_group', ('quack/', 'a token'),
 
3103
            'success', ('ok', ['token1']))
 
3104
        client.add_expected_call(
 
3105
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3106
            'success', ('ok',))
 
3107
        repo.lock_write()
 
3108
        repo.start_write_group()
 
3109
        repo.commit_write_group()
 
3110
 
 
3111
    def test_abort_write_group(self):
 
3112
        transport_path = 'quack'
 
3113
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3114
        client.add_expected_call(
 
3115
            'Repository.lock_write', ('quack/', ''),
 
3116
            'success', ('ok', 'a token'))
 
3117
        client.add_expected_call(
 
3118
            'Repository.start_write_group', ('quack/', 'a token'),
 
3119
            'success', ('ok', ['token1']))
 
3120
        client.add_expected_call(
 
3121
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3122
            'success', ('ok',))
 
3123
        repo.lock_write()
 
3124
        repo.start_write_group()
 
3125
        repo.abort_write_group(False)
 
3126
 
 
3127
    def test_suspend_write_group(self):
 
3128
        transport_path = 'quack'
 
3129
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3130
        self.assertEquals([], repo.suspend_write_group())
 
3131
 
 
3132
    def test_resume_write_group(self):
 
3133
        transport_path = 'quack'
 
3134
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3135
        client.add_expected_call(
 
3136
            'Repository.lock_write', ('quack/', ''),
 
3137
            'success', ('ok', 'a token'))
 
3138
        client.add_expected_call(
 
3139
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3140
            'success', ('ok',))
 
3141
        repo.lock_write()
 
3142
        repo.resume_write_group(['token1'])
 
3143
 
 
3144
 
2329
3145
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3146
 
2331
3147
    def test_backwards_compat(self):
2390
3206
        self.assertEqual([], client._calls)
2391
3207
 
2392
3208
 
 
3209
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3210
    """Test Repository.iter_file_bytes."""
 
3211
 
 
3212
    def test_single(self):
 
3213
        transport_path = 'quack'
 
3214
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3215
        client.add_expected_call(
 
3216
            'Repository.iter_files_bytes', ('quack/', ),
 
3217
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3218
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3219
                "somerev", "myid")]):
 
3220
            self.assertEquals("myid", identifier)
 
3221
            self.assertEquals("".join(byte_stream), "mydata" * 10)
 
3222
 
 
3223
    def test_missing(self):
 
3224
        transport_path = 'quack'
 
3225
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3226
        client.add_expected_call(
 
3227
            'Repository.iter_files_bytes',
 
3228
                ('quack/', ),
 
3229
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3230
            iter(["absent\0somefile\0somerev\n"]))
 
3231
        self.assertRaises(errors.RevisionNotPresent, list,
 
3232
                repo.iter_files_bytes(
 
3233
                [("somefile", "somerev", "myid")]))
 
3234
 
 
3235
 
2393
3236
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3237
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3238
    tests.
2402
3245
        the client is finished.
2403
3246
        """
2404
3247
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3248
        fmt = repository.format_registry.get_default()
2406
3249
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3250
        self.assertEqual([], resume_tokens)
2408
3251
        self.assertEqual(set(), missing_keys)
2508
3351
                return True
2509
3352
        repo._real_repository = FakeRealRepository()
2510
3353
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3354
        fmt = repository.format_registry.get_default()
2512
3355
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3356
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3357
        # Every record from the first inventory delta should have been sent to
2670
3513
        self.calls = calls
2671
3514
        self._pack_collection = _StubPackCollection(calls)
2672
3515
 
 
3516
    def start_write_group(self):
 
3517
        self.calls.append(('start_write_group',))
 
3518
 
2673
3519
    def is_in_write_group(self):
2674
3520
        return False
2675
3521
 
2734
3580
             ('pack collection autopack',)],
2735
3581
            client._calls)
2736
3582
 
 
3583
    def test_oom_error_reporting(self):
 
3584
        """An out-of-memory condition on the server is reported clearly"""
 
3585
        transport_path = 'quack'
 
3586
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3587
        client.add_expected_call(
 
3588
            'PackRepository.autopack', ('quack/',),
 
3589
            'error', ('MemoryError',))
 
3590
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3591
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3592
 
2737
3593
 
2738
3594
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
3595
    """Base class for unit tests for bzrlib.remote._translate_error."""
2812
3668
            detail='extra detail')
2813
3669
        self.assertEqual(expected_error, translated_error)
2814
3670
 
 
3671
    def test_norepository(self):
 
3672
        bzrdir = self.make_bzrdir('')
 
3673
        translated_error = self.translateTuple(('norepository',),
 
3674
            bzrdir=bzrdir)
 
3675
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3676
        self.assertEqual(expected_error, translated_error)
 
3677
 
2815
3678
    def test_LockContention(self):
2816
3679
        translated_error = self.translateTuple(('LockContention',))
2817
3680
        expected_error = errors.LockContention('(remote lock)')
2845
3708
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3709
        self.assertEqual(expected_error, translated_error)
2847
3710
 
 
3711
    def test_NotStacked(self):
 
3712
        branch = self.make_branch('')
 
3713
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3714
        expected_error = errors.NotStacked(branch)
 
3715
        self.assertEqual(expected_error, translated_error)
 
3716
 
2848
3717
    def test_ReadError_no_args(self):
2849
3718
        path = 'a path'
2850
3719
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3735
 
2867
3736
    def test_PermissionDenied_no_args(self):
2868
3737
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3738
        translated_error = self.translateTuple(('PermissionDenied',),
 
3739
            path=path)
2870
3740
        expected_error = errors.PermissionDenied(path)
2871
3741
        self.assertEqual(expected_error, translated_error)
2872
3742
 
2895
3765
        expected_error = errors.PermissionDenied(path, extra)
2896
3766
        self.assertEqual(expected_error, translated_error)
2897
3767
 
 
3768
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3769
 
 
3770
    def test_NoSuchFile_context_path(self):
 
3771
        local_path = "local path"
 
3772
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3773
            path=local_path)
 
3774
        expected_error = errors.ReadError(local_path)
 
3775
        self.assertEqual(expected_error, translated_error)
 
3776
 
 
3777
    def test_NoSuchFile_without_context(self):
 
3778
        remote_path = "remote path"
 
3779
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3780
        expected_error = errors.ReadError(remote_path)
 
3781
        self.assertEqual(expected_error, translated_error)
 
3782
 
 
3783
    def test_ReadOnlyError(self):
 
3784
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3785
        expected_error = errors.TransportNotPossible("readonly transport")
 
3786
        self.assertEqual(expected_error, translated_error)
 
3787
 
 
3788
    def test_MemoryError(self):
 
3789
        translated_error = self.translateTuple(('MemoryError',))
 
3790
        self.assertStartsWith(str(translated_error),
 
3791
            "remote server out of memory")
 
3792
 
 
3793
    def test_generic_IndexError_no_classname(self):
 
3794
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3795
        translated_error = self.translateErrorFromSmartServer(err)
 
3796
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3797
        self.assertEqual(expected_error, translated_error)
 
3798
 
 
3799
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3800
 
 
3801
    def test_generic_KeyError(self):
 
3802
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3803
        translated_error = self.translateErrorFromSmartServer(err)
 
3804
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3805
        self.assertEqual(expected_error, translated_error)
 
3806
 
2898
3807
 
2899
3808
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3809
    """Unit tests for bzrlib.remote._translate_error's robustness.
3045
3954
        _, stacked = branch_factory()
3046
3955
        source = stacked.repository._get_source(target_repository_format)
3047
3956
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3957
        stacked.repository._ensure_real()
 
3958
        graph = stacked.repository.get_graph()
 
3959
        revs = [r for (r,ps) in graph.iter_ancestry([tip])
 
3960
                if r != NULL_REVISION]
 
3961
        revs.reverse()
 
3962
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3963
        self.reset_smart_call_log()
3051
3964
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3965
        # We trust that if a revision is in the stream the rest of the new
3055
3966
        # content for it is too, as per our main fetch tests; here we are
3056
3967
        # checking that the revisions are actually included at all, and their
3095
4006
        self.assertEqual(expected_revs, rev_ord)
3096
4007
        # Getting topological sort requires VFS calls still - one of which is
3097
4008
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4009
        self.assertLength(14, self.hpss_calls)
3099
4010
 
3100
4011
    def test_stacked_get_stream_groupcompress(self):
3101
4012
        # Repository._get_source.get_stream() from a stacked repository with
3142
4053
 
3143
4054
    def test_copy_content_into_avoids_revision_history(self):
3144
4055
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4056
        builder = self.make_branch_builder('remote')
 
4057
        builder.build_commit(message="Commit.")
3147
4058
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4059
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4060
        local.repository.fetch(remote_branch.repository)
3150
4061
        self.hpss_calls = []
3151
4062
        remote_branch.copy_content_into(local)
3152
4063
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4064
 
 
4065
    def test_fetch_everything_needs_just_one_call(self):
 
4066
        local = self.make_branch('local')
 
4067
        builder = self.make_branch_builder('remote')
 
4068
        builder.build_commit(message="Commit.")
 
4069
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4070
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4071
        self.hpss_calls = []
 
4072
        local.repository.fetch(
 
4073
            remote_branch.repository,
 
4074
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4075
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4076
 
 
4077
    def override_verb(self, verb_name, verb):
 
4078
        request_handlers = request.request_handlers
 
4079
        orig_verb = request_handlers.get(verb_name)
 
4080
        orig_info = request_handlers.get_info(verb_name)
 
4081
        request_handlers.register(verb_name, verb, override_existing=True)
 
4082
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4083
                override_existing=True, info=orig_info)
 
4084
 
 
4085
    def test_fetch_everything_backwards_compat(self):
 
4086
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4087
        
 
4088
        Pre-2.4 do not support 'everything' searches with the
 
4089
        Repository.get_stream_1.19 verb.
 
4090
        """
 
4091
        verb_log = []
 
4092
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4093
            """A version of the Repository.get_stream_1.19 verb patched to
 
4094
            reject 'everything' searches the way 2.3 and earlier do.
 
4095
            """
 
4096
            def recreate_search(self, repository, search_bytes,
 
4097
                                discard_excess=False):
 
4098
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4099
                if search_bytes == 'everything':
 
4100
                    return (None,
 
4101
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4102
                return super(OldGetStreamVerb,
 
4103
                        self).recreate_search(repository, search_bytes,
 
4104
                            discard_excess=discard_excess)
 
4105
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4106
        local = self.make_branch('local')
 
4107
        builder = self.make_branch_builder('remote')
 
4108
        builder.build_commit(message="Commit.")
 
4109
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4110
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4111
        self.hpss_calls = []
 
4112
        local.repository.fetch(
 
4113
            remote_branch.repository,
 
4114
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4115
        # make sure the overridden verb was used
 
4116
        self.assertLength(1, verb_log)
 
4117
        # more than one HPSS call is needed, but because it's a VFS callback
 
4118
        # its hard to predict exactly how many.
 
4119
        self.assertTrue(len(self.hpss_calls) > 1)
 
4120
 
 
4121
 
 
4122
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4123
    tests.TestCaseWithTransport):
 
4124
    """Ensure correct handling of bound_location modifications.
 
4125
 
 
4126
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4127
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4128
    happen in this context.
 
4129
    """
 
4130
 
 
4131
    def setUp(self):
 
4132
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4133
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4134
 
 
4135
    def make_master_and_checkout(self, master_name, checkout_name):
 
4136
        # Create the master branch and its associated checkout
 
4137
        self.master = self.make_branch_and_tree(master_name)
 
4138
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4139
        # Modify the master branch so there is something to update
 
4140
        self.master.commit('add stuff')
 
4141
        self.last_revid = self.master.commit('even more stuff')
 
4142
        self.bound_location = self.checkout.branch.get_bound_location()
 
4143
 
 
4144
    def assertUpdateSucceeds(self, new_location):
 
4145
        self.checkout.lock_write()
 
4146
        try:
 
4147
            self.checkout.branch.set_bound_location(new_location)
 
4148
            self.checkout.update()
 
4149
        finally:
 
4150
            self.checkout.unlock()
 
4151
        self.assertEquals(self.last_revid, self.checkout.last_revision())
 
4152
 
 
4153
    def test_without_final_slash(self):
 
4154
        self.make_master_and_checkout('master', 'checkout')
 
4155
        # For unclear reasons some users have a bound_location without a final
 
4156
        # '/', simulate that by forcing such a value
 
4157
        self.assertEndsWith(self.bound_location, '/')
 
4158
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4159
 
 
4160
    def test_plus_sign(self):
 
4161
        self.make_master_and_checkout('+master', 'checkout')
 
4162
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4163
 
 
4164
    def test_tilda(self):
 
4165
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4166
        # interpretation
 
4167
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4168
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4169
 
 
4170
 
 
4171
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4172
 
 
4173
    def test_no_context(self):
 
4174
        class OutOfCoffee(errors.BzrError):
 
4175
            """A dummy exception for testing."""
 
4176
 
 
4177
            def __init__(self, urgency):
 
4178
                self.urgency = urgency
 
4179
        remote.no_context_error_translators.register("OutOfCoffee",
 
4180
            lambda err: OutOfCoffee(err.error_args[0]))
 
4181
        transport = MemoryTransport()
 
4182
        client = FakeClient(transport.base)
 
4183
        client.add_expected_call(
 
4184
            'Branch.get_stacked_on_url', ('quack/',),
 
4185
            'error', ('NotStacked',))
 
4186
        client.add_expected_call(
 
4187
            'Branch.last_revision_info',
 
4188
            ('quack/',),
 
4189
            'error', ('OutOfCoffee', 'low'))
 
4190
        transport.mkdir('quack')
 
4191
        transport = transport.clone('quack')
 
4192
        branch = self.make_remote_branch(transport, client)
 
4193
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4194
        self.assertFinished(client)
 
4195
 
 
4196
    def test_with_context(self):
 
4197
        class OutOfTea(errors.BzrError):
 
4198
            def __init__(self, branch, urgency):
 
4199
                self.branch = branch
 
4200
                self.urgency = urgency
 
4201
        remote.error_translators.register("OutOfTea",
 
4202
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4203
                find("branch")))
 
4204
        transport = MemoryTransport()
 
4205
        client = FakeClient(transport.base)
 
4206
        client.add_expected_call(
 
4207
            'Branch.get_stacked_on_url', ('quack/',),
 
4208
            'error', ('NotStacked',))
 
4209
        client.add_expected_call(
 
4210
            'Branch.last_revision_info',
 
4211
            ('quack/',),
 
4212
            'error', ('OutOfTea', 'low'))
 
4213
        transport.mkdir('quack')
 
4214
        transport = transport.clone('quack')
 
4215
        branch = self.make_remote_branch(transport, client)
 
4216
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4217
        self.assertFinished(client)
 
4218
 
 
4219
 
 
4220
class TestRepositoryPack(TestRemoteRepository):
 
4221
 
 
4222
    def test_pack(self):
 
4223
        transport_path = 'quack'
 
4224
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4225
        client.add_expected_call(
 
4226
            'Repository.lock_write', ('quack/', ''),
 
4227
            'success', ('ok', 'token'))
 
4228
        client.add_expected_call(
 
4229
            'Repository.pack', ('quack/', 'token', 'False'),
 
4230
            'success', ('ok',), )
 
4231
        client.add_expected_call(
 
4232
            'Repository.unlock', ('quack/', 'token'),
 
4233
            'success', ('ok', ))
 
4234
        repo.pack()
 
4235
 
 
4236
    def test_pack_with_hint(self):
 
4237
        transport_path = 'quack'
 
4238
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4239
        client.add_expected_call(
 
4240
            'Repository.lock_write', ('quack/', ''),
 
4241
            'success', ('ok', 'token'))
 
4242
        client.add_expected_call(
 
4243
            'Repository.pack', ('quack/', 'token', 'False'),
 
4244
            'success', ('ok',), )
 
4245
        client.add_expected_call(
 
4246
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4247
            'success', ('ok', ))
 
4248
        repo.pack(['hinta', 'hintb'])
 
4249
 
 
4250
 
 
4251
class TestRepositoryIterInventories(TestRemoteRepository):
 
4252
    """Test Repository.iter_inventories."""
 
4253
 
 
4254
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4255
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4256
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4257
 
 
4258
    def test_single_empty(self):
 
4259
        transport_path = 'quack'
 
4260
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4261
        fmt = bzrdir.format_registry.get('2a')().repository_format
 
4262
        repo._format = fmt
 
4263
        stream = [('inventory-deltas', [
 
4264
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4265
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4266
        client.add_expected_call(
 
4267
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4268
            'success', ('ok', ),
 
4269
            _stream_to_byte_stream(stream, fmt))
 
4270
        ret = list(repo.iter_inventories(["somerevid"]))
 
4271
        self.assertLength(1, ret)
 
4272
        inv = ret[0]
 
4273
        self.assertEquals("somerevid", inv.revision_id)
 
4274
 
 
4275
    def test_empty(self):
 
4276
        transport_path = 'quack'
 
4277
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4278
        ret = list(repo.iter_inventories([]))
 
4279
        self.assertEquals(ret, [])
 
4280
 
 
4281
    def test_missing(self):
 
4282
        transport_path = 'quack'
 
4283
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4284
        client.add_expected_call(
 
4285
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4286
            'success', ('ok', ), iter([]))
 
4287
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4288
            ["somerevid"]))