/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 breezy/tests/test_remote.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-09 23:53:11 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180509235311-k1zk8mwcb09b8vm0
Update TODO.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2013, 2016 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
23
23
These tests correspond to tests.test_smart, which exercises the server side.
24
24
"""
25
25
 
 
26
import base64
26
27
import bz2
27
 
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
 
from bzrlib import (
 
30
from .. import (
 
31
    bencode,
30
32
    branch,
31
 
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    repository,
 
37
    tests,
 
38
    transport,
 
39
    treebuilder,
 
40
    )
 
41
from ..branch import Branch
 
42
from ..bzr import (
 
43
    bzrdir,
35
44
    inventory,
36
45
    inventory_delta,
37
 
    pack,
38
46
    remote,
39
 
    repository,
40
 
    tests,
41
 
    treebuilder,
42
 
    urlutils,
43
47
    versionedfile,
44
 
    )
45
 
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
47
 
from bzrlib.remote import (
 
48
    vf_search,
 
49
    )
 
50
from ..bzr.bzrdir import (
 
51
    BzrDir,
 
52
    BzrDirFormat,
 
53
    )
 
54
from ..bzr import (
 
55
    RemoteBzrProber,
 
56
    )
 
57
from ..bzr.chk_serializer import chk_bencode_serializer
 
58
from ..bzr.remote import (
48
59
    RemoteBranch,
49
60
    RemoteBranchFormat,
50
61
    RemoteBzrDir,
52
63
    RemoteRepository,
53
64
    RemoteRepositoryFormat,
54
65
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import medium
58
 
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
60
 
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
 
66
from ..bzr import groupcompress_repo, knitpack_repo
 
67
from ..revision import (
 
68
    NULL_REVISION,
 
69
    Revision,
 
70
    )
 
71
from ..sixish import (
 
72
    BytesIO,
 
73
    )
 
74
from ..bzr.smart import medium, request
 
75
from ..bzr.smart.client import _SmartClient
 
76
from ..bzr.smart.repository import (
 
77
    SmartServerRepositoryGetParentMap,
 
78
    SmartServerRepositoryGetStream_1_19,
 
79
    _stream_to_byte_stream,
 
80
    )
 
81
from . import (
64
82
    test_server,
65
83
    )
66
 
from bzrlib.transport import get_transport
67
 
from bzrlib.transport.memory import MemoryTransport
68
 
from bzrlib.transport.remote import (
 
84
from .scenarios import load_tests_apply_scenarios
 
85
from ..transport.memory import MemoryTransport
 
86
from ..transport.remote import (
69
87
    RemoteTransport,
70
88
    RemoteSSHTransport,
71
89
    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 = [
 
90
    )
 
91
 
 
92
 
 
93
load_tests = load_tests_apply_scenarios
 
94
 
 
95
 
 
96
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
97
 
 
98
    scenarios = [
78
99
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
100
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
101
        ('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):
 
102
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
103
 
86
104
 
87
105
    def setUp(self):
88
106
        super(BasicRemoteObjectTests, self).setUp()
89
107
        self.transport = self.get_transport()
90
108
        # make a branch that can be opened over the smart transport
91
109
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
110
        self.addCleanup(self.transport.disconnect)
96
111
 
97
112
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
113
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
114
        self.assertIsInstance(b, BzrDir)
100
115
 
101
116
    def test_open_remote_branch(self):
102
117
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
118
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
119
        branch = b.open_branch()
105
120
        self.assertIsInstance(branch, Branch)
106
121
 
112
127
        self.local_wt.commit(message='test commit', rev_id=revid)
113
128
        self.assertTrue(repo.has_revision(revid))
114
129
 
115
 
    def test_remote_branch_revision_history(self):
116
 
        b = BzrDir.open_from_transport(self.transport).open_branch()
117
 
        self.assertEqual([], b.revision_history())
118
 
        r1 = self.local_wt.commit('1st commit')
119
 
        r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
 
        self.assertEqual([r1, r2], b.revision_history())
121
 
 
122
130
    def test_find_correct_format(self):
123
131
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
132
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
133
        self.assertTrue(RemoteBzrProber
 
134
                        in controldir.ControlDirFormat._server_probers)
 
135
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
136
 
129
137
    def test_open_detected_smart_format(self):
130
138
        fmt = BzrDirFormat.find_format(self.transport)
150
158
 
151
159
    def test_remote_repo_format_supports_external_references(self):
152
160
        t = self.transport
153
 
        bd = self.make_bzrdir('unstackable', format='pack-0.92')
 
161
        bd = self.make_controldir('unstackable', format='pack-0.92')
154
162
        r = bd.create_repository()
155
163
        self.assertFalse(r._format.supports_external_lookups)
156
164
        r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
157
165
        self.assertFalse(r._format.supports_external_lookups)
158
 
        bd = self.make_bzrdir('stackable', format='1.9')
 
166
        bd = self.make_controldir('stackable', format='1.9')
159
167
        r = bd.create_repository()
160
168
        self.assertTrue(r._format.supports_external_lookups)
161
169
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
164
172
    def test_remote_branch_set_append_revisions_only(self):
165
173
        # Make a format 1.9 branch, which supports append_revisions_only
166
174
        branch = self.make_branch('branch', format='1.9')
167
 
        config = branch.get_config()
168
175
        branch.set_append_revisions_only(True)
 
176
        config = branch.get_config_stack()
169
177
        self.assertEqual(
170
 
            'True', config.get_user_option('append_revisions_only'))
 
178
            True, config.get('append_revisions_only'))
171
179
        branch.set_append_revisions_only(False)
 
180
        config = branch.get_config_stack()
172
181
        self.assertEqual(
173
 
            'False', config.get_user_option('append_revisions_only'))
 
182
            False, config.get('append_revisions_only'))
174
183
 
175
184
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
176
185
        branch = self.make_branch('branch', format='knit')
177
 
        config = branch.get_config()
178
186
        self.assertRaises(
179
187
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
180
188
 
189
197
 
190
198
    def read_body_bytes(self, count=-1):
191
199
        if self._body_buffer is None:
192
 
            self._body_buffer = StringIO(self.body)
 
200
            self._body_buffer = BytesIO(self.body)
193
201
        bytes = self._body_buffer.read(count)
194
202
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
195
203
            self._fake_client.expecting_body = False
246
254
    def _get_next_response(self):
247
255
        try:
248
256
            response_tuple = self.responses.pop(0)
249
 
        except IndexError, e:
 
257
        except IndexError as e:
250
258
            raise AssertionError("%r didn't expect any more calls"
251
259
                % (self,))
252
260
        if response_tuple[0] == 'unknown':
338
346
class TestRemote(tests.TestCaseWithMemoryTransport):
339
347
 
340
348
    def get_branch_format(self):
341
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
349
        reference_bzrdir_format = controldir.format_registry.get('default')()
342
350
        return reference_bzrdir_format.get_branch_format()
343
351
 
344
352
    def get_repo_format(self):
345
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
353
        reference_bzrdir_format = controldir.format_registry.get('default')()
346
354
        return reference_bzrdir_format.repository_format
347
355
 
348
356
    def assertFinished(self, fake_client):
359
367
        a given client_base and transport_base.
360
368
        """
361
369
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
370
        t = transport.get_transport(transport_base)
 
371
        result = client_medium.remote_path_from_transport(t)
364
372
        self.assertEqual(expected, result)
365
373
 
366
374
    def test_remote_path_from_transport(self):
377
385
        a given transport_base and relpath of that transport.  (Note that
378
386
        HttpTransportBase is a subclass of SmartClientMedium)
379
387
        """
380
 
        base_transport = get_transport(transport_base)
 
388
        base_transport = transport.get_transport(transport_base)
381
389
        client_medium = base_transport.get_smart_medium()
382
390
        cloned_transport = base_transport.clone(relpath)
383
391
        result = client_medium.remote_path_from_transport(cloned_transport)
430
438
 
431
439
    def test_backwards_compat(self):
432
440
        self.setup_smart_server_with_call_log()
433
 
        a_dir = self.make_bzrdir('.')
 
441
        a_dir = self.make_controldir('.')
434
442
        self.reset_smart_call_log()
435
443
        verb = 'BzrDir.cloning_metadir'
436
444
        self.disable_verb(verb)
442
450
    def test_branch_reference(self):
443
451
        transport = self.get_transport('quack')
444
452
        referenced = self.make_branch('referenced')
445
 
        expected = referenced.bzrdir.cloning_metadir()
 
453
        expected = referenced.controldir.cloning_metadir()
446
454
        client = FakeClient(transport.base)
447
455
        client.add_expected_call(
448
456
            'BzrDir.cloning_metadir', ('quack/', 'False'),
450
458
        client.add_expected_call(
451
459
            'BzrDir.open_branchV3', ('quack/',),
452
460
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
461
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
462
            _client=client)
455
 
        result = a_bzrdir.cloning_metadir()
 
463
        result = a_controldir.cloning_metadir()
456
464
        # We should have got a control dir matching the referenced branch.
457
465
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
458
466
        self.assertEqual(expected._repository_format, result._repository_format)
462
470
    def test_current_server(self):
463
471
        transport = self.get_transport('.')
464
472
        transport = transport.clone('quack')
465
 
        self.make_bzrdir('quack')
 
473
        self.make_controldir('quack')
466
474
        client = FakeClient(transport.base)
467
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
475
        reference_bzrdir_format = controldir.format_registry.get('default')()
468
476
        control_name = reference_bzrdir_format.network_name()
469
477
        client.add_expected_call(
470
478
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
479
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
480
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
481
            _client=client)
474
 
        result = a_bzrdir.cloning_metadir()
 
482
        result = a_controldir.cloning_metadir()
475
483
        # We should have got a reference control dir with default branch and
476
484
        # repository formats.
477
485
        # This pokes a little, just to be sure.
480
488
        self.assertEqual(None, result._branch_format)
481
489
        self.assertFinished(client)
482
490
 
 
491
    def test_unknown(self):
 
492
        transport = self.get_transport('quack')
 
493
        referenced = self.make_branch('referenced')
 
494
        expected = referenced.controldir.cloning_metadir()
 
495
        client = FakeClient(transport.base)
 
496
        client.add_expected_call(
 
497
            'BzrDir.cloning_metadir', ('quack/', 'False'),
 
498
            'success', ('unknown', 'unknown', ('branch', ''))),
 
499
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
500
            _client=client)
 
501
        self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
 
502
 
 
503
 
 
504
class TestBzrDirCheckoutMetaDir(TestRemote):
 
505
 
 
506
    def test__get_checkout_format(self):
 
507
        transport = MemoryTransport()
 
508
        client = FakeClient(transport.base)
 
509
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
510
        control_name = reference_bzrdir_format.network_name()
 
511
        client.add_expected_call(
 
512
            'BzrDir.checkout_metadir', ('quack/', ),
 
513
            'success', (control_name, '', ''))
 
514
        transport.mkdir('quack')
 
515
        transport = transport.clone('quack')
 
516
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
517
            _client=client)
 
518
        result = a_controldir.checkout_metadir()
 
519
        # We should have got a reference control dir with default branch and
 
520
        # repository formats.
 
521
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
522
        self.assertEqual(None, result._repository_format)
 
523
        self.assertEqual(None, result._branch_format)
 
524
        self.assertFinished(client)
 
525
 
 
526
    def test_unknown_format(self):
 
527
        transport = MemoryTransport()
 
528
        client = FakeClient(transport.base)
 
529
        client.add_expected_call(
 
530
            'BzrDir.checkout_metadir', ('quack/',),
 
531
            'success', ('dontknow', '', ''))
 
532
        transport.mkdir('quack')
 
533
        transport = transport.clone('quack')
 
534
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
535
            _client=client)
 
536
        self.assertRaises(errors.UnknownFormatError,
 
537
            a_controldir.checkout_metadir)
 
538
        self.assertFinished(client)
 
539
 
 
540
 
 
541
class TestBzrDirGetBranches(TestRemote):
 
542
 
 
543
    def test_get_branches(self):
 
544
        transport = MemoryTransport()
 
545
        client = FakeClient(transport.base)
 
546
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
547
        branch_name = reference_bzrdir_format.get_branch_format().network_name()
 
548
        client.add_success_response_with_body(
 
549
            bencode.bencode({
 
550
                "foo": ("branch", branch_name),
 
551
                "": ("branch", branch_name)}), "success")
 
552
        client.add_success_response(
 
553
            'ok', '', 'no', 'no', 'no',
 
554
                reference_bzrdir_format.repository_format.network_name())
 
555
        client.add_error_response('NotStacked')
 
556
        client.add_success_response(
 
557
            'ok', '', 'no', 'no', 'no',
 
558
                reference_bzrdir_format.repository_format.network_name())
 
559
        client.add_error_response('NotStacked')
 
560
        transport.mkdir('quack')
 
561
        transport = transport.clone('quack')
 
562
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
563
            _client=client)
 
564
        result = a_controldir.get_branches()
 
565
        self.assertEqual({"", "foo"}, set(result.keys()))
 
566
        self.assertEqual(
 
567
            [('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
 
568
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
569
             ('call', 'Branch.get_stacked_on_url', ('quack/', )),
 
570
             ('call', 'BzrDir.find_repositoryV3', ('quack/', )),
 
571
             ('call', 'Branch.get_stacked_on_url', ('quack/', ))],
 
572
            client._calls)
 
573
 
 
574
 
 
575
class TestBzrDirDestroyBranch(TestRemote):
 
576
 
 
577
    def test_destroy_default(self):
 
578
        transport = self.get_transport('quack')
 
579
        referenced = self.make_branch('referenced')
 
580
        client = FakeClient(transport.base)
 
581
        client.add_expected_call(
 
582
            'BzrDir.destroy_branch', ('quack/', ),
 
583
            'success', ('ok',)),
 
584
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
585
            _client=client)
 
586
        a_controldir.destroy_branch()
 
587
        self.assertFinished(client)
 
588
 
 
589
 
 
590
class TestBzrDirHasWorkingTree(TestRemote):
 
591
 
 
592
    def test_has_workingtree(self):
 
593
        transport = self.get_transport('quack')
 
594
        client = FakeClient(transport.base)
 
595
        client.add_expected_call(
 
596
            'BzrDir.has_workingtree', ('quack/',),
 
597
            'success', ('yes',)),
 
598
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
599
            _client=client)
 
600
        self.assertTrue(a_controldir.has_workingtree())
 
601
        self.assertFinished(client)
 
602
 
 
603
    def test_no_workingtree(self):
 
604
        transport = self.get_transport('quack')
 
605
        client = FakeClient(transport.base)
 
606
        client.add_expected_call(
 
607
            'BzrDir.has_workingtree', ('quack/',),
 
608
            'success', ('no',)),
 
609
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
610
            _client=client)
 
611
        self.assertFalse(a_controldir.has_workingtree())
 
612
        self.assertFinished(client)
 
613
 
 
614
 
 
615
class TestBzrDirDestroyRepository(TestRemote):
 
616
 
 
617
    def test_destroy_repository(self):
 
618
        transport = self.get_transport('quack')
 
619
        client = FakeClient(transport.base)
 
620
        client.add_expected_call(
 
621
            'BzrDir.destroy_repository', ('quack/',),
 
622
            'success', ('ok',)),
 
623
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
624
            _client=client)
 
625
        a_controldir.destroy_repository()
 
626
        self.assertFinished(client)
 
627
 
483
628
 
484
629
class TestBzrDirOpen(TestRemote):
485
630
 
495
640
        client.add_expected_call(
496
641
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
642
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
643
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
644
        self.assertFinished(client)
500
645
 
501
646
    def test_present_without_workingtree(self):
502
647
        client, transport = self.make_fake_client_and_transport()
503
648
        client.add_expected_call(
504
649
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
650
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
651
            _client=client, _force_probe=True)
507
652
        self.assertIsInstance(bd, RemoteBzrDir)
508
653
        self.assertFalse(bd.has_workingtree())
513
658
        client, transport = self.make_fake_client_and_transport()
514
659
        client.add_expected_call(
515
660
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
661
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
662
            _client=client, _force_probe=True)
518
663
        self.assertIsInstance(bd, RemoteBzrDir)
519
664
        self.assertTrue(bd.has_workingtree())
526
671
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
527
672
        client.add_expected_call(
528
673
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
674
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
675
            _client=client, _force_probe=True)
531
676
        self.assertIsInstance(bd, RemoteBzrDir)
532
677
        self.assertFinished(client)
548
693
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
549
694
        client.add_expected_call(
550
695
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
696
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
697
            _client=client, _force_probe=True)
553
698
        self.assertIsInstance(bd, RemoteBzrDir)
554
699
        self.assertFinished(client)
585
730
        client.add_expected_call(
586
731
            'Branch.get_stacked_on_url', ('quack/',),
587
732
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
733
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
734
            _client=client)
590
735
        result = bzrdir.open_branch()
591
736
        self.assertIsInstance(result, RemoteBranch)
592
 
        self.assertEqual(bzrdir, result.bzrdir)
 
737
        self.assertEqual(bzrdir, result.controldir)
593
738
        self.assertFinished(client)
594
739
 
595
740
    def test_branch_missing(self):
598
743
        transport = transport.clone('quack')
599
744
        client = FakeClient(transport.base)
600
745
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
746
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
747
            _client=client)
603
748
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
749
        self.assertEqual(
609
754
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
755
        # branch opening, not any other network requests.
611
756
        calls = []
612
 
        def open_branch():
 
757
        def open_branch(name=None, possible_transports=None):
613
758
            calls.append("Called")
614
759
            return "a-branch"
615
760
        transport = MemoryTransport()
616
761
        # no requests on the network - catches other api calls being made.
617
762
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
763
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
764
            _client=client)
620
765
        # patch the open_branch call to record that it was called.
621
766
        bzrdir.open_branch = open_branch
640
785
        client.add_expected_call(
641
786
            'Branch.get_stacked_on_url', ('~hello/',),
642
787
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
788
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
789
            _client=client)
645
790
        result = bzrdir.open_branch()
646
791
        self.assertFinished(client)
663
808
        client.add_success_response(
664
809
            'ok', '', rich_response, subtree_response, external_lookup,
665
810
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
811
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
812
            _client=client)
668
813
        result = bzrdir.open_repository()
669
814
        self.assertEqual(
670
815
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
671
816
            client._calls)
672
817
        self.assertIsInstance(result, RemoteRepository)
673
 
        self.assertEqual(bzrdir, result.bzrdir)
 
818
        self.assertEqual(bzrdir, result.controldir)
674
819
        self.assertEqual(rich_root, result._format.rich_root_data)
675
820
        self.assertEqual(subtrees, result._format.supports_tree_reference)
676
821
 
686
831
        old.
687
832
        """
688
833
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
834
            RemoteBzrProber.probe_transport, OldServerTransport())
690
835
 
691
836
 
692
837
class TestBzrDirCreateBranch(TestRemote):
696
841
        repo = self.make_repository('.')
697
842
        self.reset_smart_call_log()
698
843
        self.disable_verb('BzrDir.create_branch')
699
 
        branch = repo.bzrdir.create_branch()
 
844
        branch = repo.controldir.create_branch()
700
845
        create_branch_call_count = len([call for call in self.hpss_calls if
701
846
            call.call.method == 'BzrDir.create_branch'])
702
847
        self.assertEqual(1, create_branch_call_count)
706
851
        transport = transport.clone('quack')
707
852
        self.make_repository('quack')
708
853
        client = FakeClient(transport.base)
709
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
854
        reference_bzrdir_format = controldir.format_registry.get('default')()
710
855
        reference_format = reference_bzrdir_format.get_branch_format()
711
856
        network_name = reference_format.network_name()
712
857
        reference_repo_fmt = reference_bzrdir_format.repository_format
715
860
            'BzrDir.create_branch', ('quack/', network_name),
716
861
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
862
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
719
 
            _client=client)
720
 
        branch = a_bzrdir.create_branch()
 
863
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
864
            _client=client)
 
865
        branch = a_controldir.create_branch()
 
866
        # We should have got a remote branch
 
867
        self.assertIsInstance(branch, remote.RemoteBranch)
 
868
        # its format should have the settings from the response
 
869
        format = branch._format
 
870
        self.assertEqual(network_name, format.network_name())
 
871
 
 
872
    def test_already_open_repo_and_reused_medium(self):
 
873
        """Bug 726584: create_branch(..., repository=repo) should work
 
874
        regardless of what the smart medium's base URL is.
 
875
        """
 
876
        self.transport_server = test_server.SmartTCPServer_for_testing
 
877
        transport = self.get_transport('.')
 
878
        repo = self.make_repository('quack')
 
879
        # Client's medium rooted a transport root (not at the bzrdir)
 
880
        client = FakeClient(transport.base)
 
881
        transport = transport.clone('quack')
 
882
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
883
        reference_format = reference_bzrdir_format.get_branch_format()
 
884
        network_name = reference_format.network_name()
 
885
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
886
        reference_repo_name = reference_repo_fmt.network_name()
 
887
        client.add_expected_call(
 
888
            'BzrDir.create_branch', ('extra/quack/', network_name),
 
889
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
 
890
            reference_repo_name))
 
891
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
892
            _client=client)
 
893
        branch = a_controldir.create_branch(repository=repo)
721
894
        # We should have got a remote branch
722
895
        self.assertIsInstance(branch, remote.RemoteBranch)
723
896
        # its format should have the settings from the response
729
902
 
730
903
    def test_backwards_compat(self):
731
904
        self.setup_smart_server_with_call_log()
732
 
        bzrdir = self.make_bzrdir('.')
 
905
        bzrdir = self.make_controldir('.')
733
906
        self.reset_smart_call_log()
734
907
        self.disable_verb('BzrDir.create_repository')
735
908
        repo = bzrdir.create_repository()
740
913
    def test_current_server(self):
741
914
        transport = self.get_transport('.')
742
915
        transport = transport.clone('quack')
743
 
        self.make_bzrdir('quack')
 
916
        self.make_controldir('quack')
744
917
        client = FakeClient(transport.base)
745
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
918
        reference_bzrdir_format = controldir.format_registry.get('default')()
746
919
        reference_format = reference_bzrdir_format.repository_format
747
920
        network_name = reference_format.network_name()
748
921
        client.add_expected_call(
750
923
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
924
                'False'),
752
925
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
926
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
927
            _client=client)
755
 
        repo = a_bzrdir.create_repository()
 
928
        repo = a_controldir.create_repository()
756
929
        # We should have got a remote repository
757
930
        self.assertIsInstance(repo, remote.RemoteRepository)
758
931
        # its format should have the settings from the response
779
952
        # name.
780
953
        client.add_success_response_with_body(
781
954
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
955
        client.add_success_response('stat', '0', '65535')
782
956
        client.add_success_response_with_body(
783
957
            reference_format.get_format_string(), 'ok')
784
958
        # PackRepository wants to do a stat
785
959
        client.add_success_response('stat', '0', '65535')
786
960
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
961
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
962
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
963
            _client=client)
790
964
        repo = bzrdir.open_repository()
791
965
        self.assertEqual(
793
967
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
968
             ('call', 'BzrDir.find_repository', ('quack/',)),
795
969
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
970
             ('call', 'stat', ('/quack/.bzr',)),
796
971
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
972
             ('call', 'stat', ('/quack/.bzr/repository',)),
798
973
             ],
812
987
        # name.
813
988
        client.add_success_response_with_body(
814
989
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
990
        client.add_success_response('stat', '0', '65535')
815
991
        client.add_success_response_with_body(
816
992
            reference_format.get_format_string(), 'ok')
817
993
        # PackRepository wants to do a stat
818
994
        client.add_success_response('stat', '0', '65535')
819
995
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
996
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
997
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
998
            _client=client)
823
999
        repo = bzrdir.open_repository()
824
1000
        self.assertEqual(
825
1001
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
1002
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
1003
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
 
1004
             ('call', 'stat', ('/quack/.bzr',)),
828
1005
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
1006
             ('call', 'stat', ('/quack/.bzr/repository',)),
830
1007
             ],
839
1016
        transport = transport.clone('quack')
840
1017
        client = FakeClient(transport.base)
841
1018
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1019
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
1020
            _client=client)
844
1021
        repo = bzrdir.open_repository()
845
1022
        self.assertEqual(
852
1029
 
853
1030
    def test_success(self):
854
1031
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1032
        fmt = RemoteBzrDirFormat()
856
1033
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1034
        transport = self.get_transport()
858
1035
        client = FakeClient(transport.base)
874
1051
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1052
        corresponding error from the client.
876
1053
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1054
        fmt = RemoteBzrDirFormat()
878
1055
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1056
        transport = self.get_transport()
880
1057
        client = FakeClient(transport.base)
898
1075
        """Integration test for error translation."""
899
1076
        transport = self.make_smart_server('foo')
900
1077
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1078
        fmt = RemoteBzrDirFormat()
902
1079
        err = self.assertRaises(errors.NoSuchFile,
903
1080
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1081
 
909
1086
    """
910
1087
 
911
1088
    def get_request(self):
912
 
        input_file = StringIO('ok\x011\n')
913
 
        output_file = StringIO()
 
1089
        input_file = BytesIO(b'ok\x011\n')
 
1090
        output_file = BytesIO()
914
1091
        client_medium = medium.SmartSimplePipesClientMedium(
915
1092
            input_file, output_file)
916
1093
        return medium.SmartClientStreamMediumRequest(client_medium)
935
1112
 
936
1113
    def make_remote_bzrdir(self, transport, client):
937
1114
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1115
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1116
            _client=client)
940
1117
 
941
1118
 
967
1144
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1145
 
969
1146
 
 
1147
class TestBranchBreakLock(RemoteBranchTestCase):
 
1148
 
 
1149
    def test_break_lock(self):
 
1150
        transport_path = 'quack'
 
1151
        transport = MemoryTransport()
 
1152
        client = FakeClient(transport.base)
 
1153
        client.add_expected_call(
 
1154
            'Branch.get_stacked_on_url', ('quack/',),
 
1155
            'error', ('NotStacked',))
 
1156
        client.add_expected_call(
 
1157
            'Branch.break_lock', ('quack/',),
 
1158
            'success', ('ok',))
 
1159
        transport.mkdir('quack')
 
1160
        transport = transport.clone('quack')
 
1161
        branch = self.make_remote_branch(transport, client)
 
1162
        branch.break_lock()
 
1163
        self.assertFinished(client)
 
1164
 
 
1165
 
 
1166
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1167
 
 
1168
    def test_get_physical_lock_status_yes(self):
 
1169
        transport = MemoryTransport()
 
1170
        client = FakeClient(transport.base)
 
1171
        client.add_expected_call(
 
1172
            'Branch.get_stacked_on_url', ('quack/',),
 
1173
            'error', ('NotStacked',))
 
1174
        client.add_expected_call(
 
1175
            'Branch.get_physical_lock_status', ('quack/',),
 
1176
            'success', ('yes',))
 
1177
        transport.mkdir('quack')
 
1178
        transport = transport.clone('quack')
 
1179
        branch = self.make_remote_branch(transport, client)
 
1180
        result = branch.get_physical_lock_status()
 
1181
        self.assertFinished(client)
 
1182
        self.assertEqual(True, result)
 
1183
 
 
1184
    def test_get_physical_lock_status_no(self):
 
1185
        transport = MemoryTransport()
 
1186
        client = FakeClient(transport.base)
 
1187
        client.add_expected_call(
 
1188
            'Branch.get_stacked_on_url', ('quack/',),
 
1189
            'error', ('NotStacked',))
 
1190
        client.add_expected_call(
 
1191
            'Branch.get_physical_lock_status', ('quack/',),
 
1192
            'success', ('no',))
 
1193
        transport.mkdir('quack')
 
1194
        transport = transport.clone('quack')
 
1195
        branch = self.make_remote_branch(transport, client)
 
1196
        result = branch.get_physical_lock_status()
 
1197
        self.assertFinished(client)
 
1198
        self.assertEqual(False, result)
 
1199
 
 
1200
 
970
1201
class TestBranchGetParent(RemoteBranchTestCase):
971
1202
 
972
1203
    def test_no_parent(self):
1062
1293
        verb = 'Branch.set_parent_location'
1063
1294
        self.disable_verb(verb)
1064
1295
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1296
        self.assertLength(14, self.hpss_calls)
1066
1297
 
1067
1298
 
1068
1299
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1143
1374
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1144
1375
 
1145
1376
 
 
1377
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1378
 
 
1379
    def test_uses_last_revision_info_and_tags_by_default(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',), '')
 
1391
        transport.mkdir('quack')
 
1392
        transport = transport.clone('quack')
 
1393
        branch = self.make_remote_branch(transport, client)
 
1394
        result = branch.heads_to_fetch()
 
1395
        self.assertFinished(client)
 
1396
        self.assertEqual(({'rev-tip'}, set()), result)
 
1397
 
 
1398
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1399
        transport = MemoryTransport()
 
1400
        client = FakeClient(transport.base)
 
1401
        client.add_expected_call(
 
1402
            'Branch.get_stacked_on_url', ('quack/',),
 
1403
            'error', ('NotStacked',))
 
1404
        client.add_expected_call(
 
1405
            'Branch.last_revision_info', ('quack/',),
 
1406
            'success', ('ok', '1', 'rev-tip'))
 
1407
        client.add_expected_call(
 
1408
            'Branch.get_config_file', ('quack/',),
 
1409
            'success', ('ok',), 'branch.fetch_tags = True')
 
1410
        # XXX: this will break if the default format's serialization of tags
 
1411
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1412
        client.add_expected_call(
 
1413
            'Branch.get_tags_bytes', ('quack/',),
 
1414
            'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1415
        transport.mkdir('quack')
 
1416
        transport = transport.clone('quack')
 
1417
        branch = self.make_remote_branch(transport, client)
 
1418
        result = branch.heads_to_fetch()
 
1419
        self.assertFinished(client)
 
1420
        self.assertEqual(
 
1421
            ({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
 
1422
 
 
1423
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1424
        transport = MemoryTransport()
 
1425
        client = FakeClient(transport.base)
 
1426
        client.add_expected_call(
 
1427
            'Branch.get_stacked_on_url', ('quack/',),
 
1428
            'error', ('NotStacked',))
 
1429
        client.add_expected_call(
 
1430
            'Branch.heads_to_fetch', ('quack/',),
 
1431
            'success', (['tip'], ['tagged-1', 'tagged-2']))
 
1432
        transport.mkdir('quack')
 
1433
        transport = transport.clone('quack')
 
1434
        branch = self.make_remote_branch(transport, client)
 
1435
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1436
        result = branch.heads_to_fetch()
 
1437
        self.assertFinished(client)
 
1438
        self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
 
1439
 
 
1440
    def make_branch_with_tags(self):
 
1441
        self.setup_smart_server_with_call_log()
 
1442
        # Make a branch with a single revision.
 
1443
        builder = self.make_branch_builder('foo')
 
1444
        builder.start_series()
 
1445
        builder.build_snapshot(None, [
 
1446
            ('add', ('', 'root-id', 'directory', ''))],
 
1447
            revision_id='tip')
 
1448
        builder.finish_series()
 
1449
        branch = builder.get_branch()
 
1450
        # Add two tags to that branch
 
1451
        branch.tags.set_tag('tag-1', 'rev-1')
 
1452
        branch.tags.set_tag('tag-2', 'rev-2')
 
1453
        return branch
 
1454
 
 
1455
    def test_backwards_compatible(self):
 
1456
        br = self.make_branch_with_tags()
 
1457
        br.get_config_stack().set('branch.fetch_tags', True)
 
1458
        self.addCleanup(br.lock_read().unlock)
 
1459
        # Disable the heads_to_fetch verb
 
1460
        verb = 'Branch.heads_to_fetch'
 
1461
        self.disable_verb(verb)
 
1462
        self.reset_smart_call_log()
 
1463
        result = br.heads_to_fetch()
 
1464
        self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
 
1465
        self.assertEqual(
 
1466
            ['Branch.last_revision_info', 'Branch.get_tags_bytes'],
 
1467
            [call.call.method for call in self.hpss_calls])
 
1468
 
 
1469
    def test_backwards_compatible_no_tags(self):
 
1470
        br = self.make_branch_with_tags()
 
1471
        br.get_config_stack().set('branch.fetch_tags', False)
 
1472
        self.addCleanup(br.lock_read().unlock)
 
1473
        # Disable the heads_to_fetch verb
 
1474
        verb = 'Branch.heads_to_fetch'
 
1475
        self.disable_verb(verb)
 
1476
        self.reset_smart_call_log()
 
1477
        result = br.heads_to_fetch()
 
1478
        self.assertEqual(({'tip'}, set()), result)
 
1479
        self.assertEqual(
 
1480
            ['Branch.last_revision_info'],
 
1481
            [call.call.method for call in self.hpss_calls])
 
1482
 
 
1483
 
1146
1484
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1147
1485
 
1148
1486
    def test_empty_branch(self):
1193
1531
        memory_branch = self.make_branch('base', format='1.9')
1194
1532
        vfs_url = self.get_vfs_only_url('base')
1195
1533
        stacked_branch.set_stacked_on_url(vfs_url)
1196
 
        transport = stacked_branch.bzrdir.root_transport
 
1534
        transport = stacked_branch.controldir.root_transport
1197
1535
        client = FakeClient(transport.base)
1198
1536
        client.add_expected_call(
1199
1537
            'Branch.get_stacked_on_url', ('stacked/',),
1203
1541
        client.add_expected_call(
1204
1542
            'Branch.get_stacked_on_url', ('stacked/',),
1205
1543
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1544
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1545
            _client=client)
1208
1546
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1547
        repo_fmt._custom_format = stacked_branch.repository._format
1236
1574
        # this will also do vfs access, but that goes direct to the transport
1237
1575
        # and isn't seen by the FakeClient.
1238
1576
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1577
            RemoteBzrDirFormat(), _client=client)
1240
1578
        branch = bzrdir.open_branch()
1241
1579
        result = branch.get_stacked_on_url()
1242
1580
        self.assertEqual('../base', result)
1269
1607
            'Branch.get_stacked_on_url', ('stacked/',),
1270
1608
            'success', ('ok', '../base'))
1271
1609
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1610
            RemoteBzrDirFormat(), _client=client)
1273
1611
        branch = bzrdir.open_branch()
1274
1612
        result = branch.get_stacked_on_url()
1275
1613
        self.assertEqual('../base', result)
1283
1621
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1622
 
1285
1623
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1624
        # _set_last_revision_info('null:') is translated to calling
1287
1625
        # Branch.set_last_revision(path, '') on the wire.
1288
1626
        transport = MemoryTransport()
1289
1627
        transport.mkdir('branch')
1307
1645
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
1646
            'success', ('ok',))
1309
1647
        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
1648
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1649
        result = branch._set_last_revision(NULL_REVISION)
1315
1650
        branch.unlock()
1316
1651
        self.assertEqual(None, result)
1317
1652
        self.assertFinished(client)
1318
1653
 
1319
1654
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1655
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1656
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1657
        transport = MemoryTransport()
1323
1658
        transport.mkdir('branch')
1344
1679
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
1680
            'success', ('ok',))
1346
1681
        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
1682
        # Lock the branch, reset the record of remote calls.
1351
1683
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1684
        result = branch._set_last_revision('rev-id2')
1353
1685
        branch.unlock()
1354
1686
        self.assertEqual(None, result)
1355
1687
        self.assertFinished(client)
1385
1717
        branch = self.make_remote_branch(transport, client)
1386
1718
        branch.lock_write()
1387
1719
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1720
            errors.NoSuchRevision, branch._set_last_revision, 'rev-id')
1389
1721
        branch.unlock()
1390
1722
        self.assertFinished(client)
1391
1723
 
1419
1751
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
1752
            'success', ('ok',))
1421
1753
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1754
        branch.lock_write()
1424
1755
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1756
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1757
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1758
            errors.TipChangeRejected,
 
1759
            branch._set_last_revision, 'rev-id')
1428
1760
        # The UTF-8 message from the response has been decoded into a unicode
1429
1761
        # object.
1430
1762
        self.assertIsInstance(err.msg, unicode)
1618
1950
    def test_get_multi_line_branch_conf(self):
1619
1951
        # Make sure that multiple-line branch.conf files are supported
1620
1952
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1953
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1954
        client = FakeClient()
1623
1955
        client.add_expected_call(
1624
1956
            'Branch.get_stacked_on_url', ('memory:///',),
1652
1984
        branch.unlock()
1653
1985
        self.assertFinished(client)
1654
1986
 
 
1987
    def test_set_option_with_dict(self):
 
1988
        client = FakeClient()
 
1989
        client.add_expected_call(
 
1990
            'Branch.get_stacked_on_url', ('memory:///',),
 
1991
            'error', ('NotStacked',),)
 
1992
        client.add_expected_call(
 
1993
            'Branch.lock_write', ('memory:///', '', ''),
 
1994
            'success', ('ok', 'branch token', 'repo token'))
 
1995
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1996
        client.add_expected_call(
 
1997
            'Branch.set_config_option_dict', ('memory:///', 'branch token',
 
1998
            'repo token', encoded_dict_value, 'foo', ''),
 
1999
            'success', ())
 
2000
        client.add_expected_call(
 
2001
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2002
            'success', ('ok',))
 
2003
        transport = MemoryTransport()
 
2004
        branch = self.make_remote_branch(transport, client)
 
2005
        branch.lock_write()
 
2006
        config = branch._get_config()
 
2007
        config.set_option(
 
2008
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2009
            'foo')
 
2010
        branch.unlock()
 
2011
        self.assertFinished(client)
 
2012
 
1655
2013
    def test_backwards_compat_set_option(self):
1656
2014
        self.setup_smart_server_with_call_log()
1657
2015
        branch = self.make_branch('.')
1661
2019
        self.addCleanup(branch.unlock)
1662
2020
        self.reset_smart_call_log()
1663
2021
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2022
        self.assertLength(11, self.hpss_calls)
1665
2023
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2024
 
 
2025
    def test_backwards_compat_set_option_with_dict(self):
 
2026
        self.setup_smart_server_with_call_log()
 
2027
        branch = self.make_branch('.')
 
2028
        verb = 'Branch.set_config_option_dict'
 
2029
        self.disable_verb(verb)
 
2030
        branch.lock_write()
 
2031
        self.addCleanup(branch.unlock)
 
2032
        self.reset_smart_call_log()
 
2033
        config = branch._get_config()
 
2034
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2035
        config.set_option(value_dict, 'name')
 
2036
        self.assertLength(11, self.hpss_calls)
 
2037
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2038
 
 
2039
 
 
2040
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2041
 
 
2042
    def test_get_branch_conf(self):
 
2043
        # in an empty branch we decode the response properly
 
2044
        client = FakeClient()
 
2045
        client.add_expected_call(
 
2046
            'Branch.get_stacked_on_url', ('memory:///',),
 
2047
            'error', ('NotStacked',),)
 
2048
        client.add_success_response_with_body('# config file body', 'ok')
 
2049
        transport = MemoryTransport()
 
2050
        branch = self.make_remote_branch(transport, client)
 
2051
        config = branch.get_config_stack()
 
2052
        config.get("email")
 
2053
        config.get("log_format")
 
2054
        self.assertEqual(
 
2055
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2056
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
2057
            client._calls)
 
2058
 
 
2059
    def test_set_branch_conf(self):
 
2060
        client = FakeClient()
 
2061
        client.add_expected_call(
 
2062
            'Branch.get_stacked_on_url', ('memory:///',),
 
2063
            'error', ('NotStacked',),)
 
2064
        client.add_expected_call(
 
2065
            'Branch.lock_write', ('memory:///', '', ''),
 
2066
            'success', ('ok', 'branch token', 'repo token'))
 
2067
        client.add_expected_call(
 
2068
            'Branch.get_config_file', ('memory:///', ),
 
2069
            'success', ('ok', ), "# line 1\n")
 
2070
        client.add_expected_call(
 
2071
            'Branch.get_config_file', ('memory:///', ),
 
2072
            'success', ('ok', ), "# line 1\n")
 
2073
        client.add_expected_call(
 
2074
            'Branch.put_config_file', ('memory:///', 'branch token',
 
2075
            'repo token'),
 
2076
            'success', ('ok',))
 
2077
        client.add_expected_call(
 
2078
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
 
2079
            'success', ('ok',))
 
2080
        transport = MemoryTransport()
 
2081
        branch = self.make_remote_branch(transport, client)
 
2082
        branch.lock_write()
 
2083
        config = branch.get_config_stack()
 
2084
        config.set('email', 'The Dude <lebowski@example.com>')
 
2085
        branch.unlock()
 
2086
        self.assertFinished(client)
 
2087
        self.assertEqual(
 
2088
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
 
2089
             ('call', 'Branch.lock_write', ('memory:///', '', '')),
 
2090
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2091
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
 
2092
             ('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
 
2093
                 ('memory:///', 'branch token', 'repo token'),
 
2094
                 '# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2095
             ('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
 
2096
            client._calls)
 
2097
 
1667
2098
 
1668
2099
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2100
 
1683
2114
        self.assertFinished(client)
1684
2115
 
1685
2116
 
 
2117
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2118
 
 
2119
    def test_simple(self):
 
2120
        transport = MemoryTransport()
 
2121
        client = FakeClient(transport.base)
 
2122
        client.add_expected_call(
 
2123
            'Branch.get_stacked_on_url', ('quack/',),
 
2124
            'error', ('NotStacked',),)
 
2125
        client.add_expected_call(
 
2126
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2127
            'success', ('ok', '0',),)
 
2128
        client.add_expected_call(
 
2129
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2130
            'error', ('NoSuchRevision', 'unknown',),)
 
2131
        transport.mkdir('quack')
 
2132
        transport = transport.clone('quack')
 
2133
        branch = self.make_remote_branch(transport, client)
 
2134
        self.assertEqual(0, branch.revision_id_to_revno('null:'))
 
2135
        self.assertRaises(errors.NoSuchRevision,
 
2136
            branch.revision_id_to_revno, 'unknown')
 
2137
        self.assertFinished(client)
 
2138
 
 
2139
    def test_dotted(self):
 
2140
        transport = MemoryTransport()
 
2141
        client = FakeClient(transport.base)
 
2142
        client.add_expected_call(
 
2143
            'Branch.get_stacked_on_url', ('quack/',),
 
2144
            'error', ('NotStacked',),)
 
2145
        client.add_expected_call(
 
2146
            'Branch.revision_id_to_revno', ('quack/', 'null:'),
 
2147
            'success', ('ok', '0',),)
 
2148
        client.add_expected_call(
 
2149
            'Branch.revision_id_to_revno', ('quack/', 'unknown'),
 
2150
            'error', ('NoSuchRevision', 'unknown',),)
 
2151
        transport.mkdir('quack')
 
2152
        transport = transport.clone('quack')
 
2153
        branch = self.make_remote_branch(transport, client)
 
2154
        self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
 
2155
        self.assertRaises(errors.NoSuchRevision,
 
2156
            branch.revision_id_to_dotted_revno, 'unknown')
 
2157
        self.assertFinished(client)
 
2158
 
 
2159
    def test_dotted_no_smart_verb(self):
 
2160
        self.setup_smart_server_with_call_log()
 
2161
        branch = self.make_branch('.')
 
2162
        self.disable_verb('Branch.revision_id_to_revno')
 
2163
        self.reset_smart_call_log()
 
2164
        self.assertEqual((0, ),
 
2165
            branch.revision_id_to_dotted_revno('null:'))
 
2166
        self.assertLength(8, self.hpss_calls)
 
2167
 
 
2168
 
1686
2169
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2170
 
1688
2171
    def test__get_config(self):
1698
2181
 
1699
2182
    def test_set_option_uses_vfs(self):
1700
2183
        self.setup_smart_server_with_call_log()
1701
 
        bzrdir = self.make_bzrdir('.')
 
2184
        bzrdir = self.make_controldir('.')
1702
2185
        self.reset_smart_call_log()
1703
2186
        config = bzrdir.get_config()
1704
2187
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2188
        self.assertLength(4, self.hpss_calls)
1706
2189
 
1707
2190
    def test_backwards_compat_get_option(self):
1708
2191
        self.setup_smart_server_with_call_log()
1709
 
        bzrdir = self.make_bzrdir('.')
 
2192
        bzrdir = self.make_controldir('.')
1710
2193
        verb = 'BzrDir.get_config_file'
1711
2194
        self.disable_verb(verb)
1712
2195
        self.reset_smart_call_log()
1713
2196
        self.assertEqual(None,
1714
2197
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2198
        self.assertLength(4, self.hpss_calls)
1716
2199
 
1717
2200
 
1718
2201
class TestTransportIsReadonly(tests.TestCase):
1805
2288
        client = FakeClient(transport.base)
1806
2289
        transport = transport.clone(transport_path)
1807
2290
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2291
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2292
            _client=False)
1810
2293
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2294
        return repo, client
1819
2302
 
1820
2303
    def test_get_format_description(self):
1821
2304
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2305
        real_format = branch.format_registry.get_default()
1823
2306
        remote_format._network_name = real_format.network_name()
1824
2307
        self.assertEqual(remoted_description(real_format),
1825
2308
            remote_format.get_format_description())
1828
2311
class TestRepositoryFormat(TestRemoteRepository):
1829
2312
 
1830
2313
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2314
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2315
        true_format = RemoteRepositoryFormat()
1833
2316
        true_format._network_name = true_name
1834
2317
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2318
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2319
        false_format = RemoteRepositoryFormat()
1837
2320
        false_format._network_name = false_name
1838
2321
        self.assertEqual(False, false_format.fast_deltas)
1839
2322
 
1840
2323
    def test_get_format_description(self):
1841
2324
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2325
        real_format = repository.format_registry.get_default()
1843
2326
        remote_repo_format._network_name = real_format.network_name()
1844
2327
        self.assertEqual(remoted_description(real_format),
1845
2328
            remote_repo_format.get_format_description())
1846
2329
 
1847
2330
 
 
2331
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2332
 
 
2333
    def test_empty(self):
 
2334
        transport_path = 'quack'
 
2335
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2336
        client.add_success_response_with_body('', 'ok')
 
2337
        self.assertEqual([], repo.all_revision_ids())
 
2338
        self.assertEqual(
 
2339
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2340
             ('quack/',))],
 
2341
            client._calls)
 
2342
 
 
2343
    def test_with_some_content(self):
 
2344
        transport_path = 'quack'
 
2345
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2346
        client.add_success_response_with_body(
 
2347
            'rev1\nrev2\nanotherrev\n', 'ok')
 
2348
        self.assertEqual(["rev1", "rev2", "anotherrev"],
 
2349
            repo.all_revision_ids())
 
2350
        self.assertEqual(
 
2351
            [('call_expecting_body', 'Repository.all_revision_ids',
 
2352
             ('quack/',))],
 
2353
            client._calls)
 
2354
 
 
2355
 
1848
2356
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2357
 
1850
2358
    def test_revid_none(self):
1856
2364
        result = repo.gather_stats(None)
1857
2365
        self.assertEqual(
1858
2366
            [('call_expecting_body', 'Repository.gather_stats',
1859
 
             ('quack/','','no'))],
 
2367
             ('quack/', '', 'no'))],
1860
2368
            client._calls)
1861
2369
        self.assertEqual({'revisions': 2, 'size': 18}, result)
1862
2370
 
1903
2411
                         result)
1904
2412
 
1905
2413
 
 
2414
class TestRepositoryBreakLock(TestRemoteRepository):
 
2415
 
 
2416
    def test_break_lock(self):
 
2417
        transport_path = 'quack'
 
2418
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2419
        client.add_success_response('ok')
 
2420
        repo.break_lock()
 
2421
        self.assertEqual(
 
2422
            [('call', 'Repository.break_lock', ('quack/',))],
 
2423
            client._calls)
 
2424
 
 
2425
 
 
2426
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2427
 
 
2428
    def test_get_serializer_format(self):
 
2429
        transport_path = 'hill'
 
2430
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2431
        client.add_success_response('ok', '7')
 
2432
        self.assertEqual('7', repo.get_serializer_format())
 
2433
        self.assertEqual(
 
2434
            [('call', 'VersionedFileRepository.get_serializer_format',
 
2435
              ('hill/', ))],
 
2436
            client._calls)
 
2437
 
 
2438
 
 
2439
class TestRepositoryReconcile(TestRemoteRepository):
 
2440
 
 
2441
    def test_reconcile(self):
 
2442
        transport_path = 'hill'
 
2443
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2444
        body = ("garbage_inventories: 2\n"
 
2445
                "inconsistent_parents: 3\n")
 
2446
        client.add_expected_call(
 
2447
            'Repository.lock_write', ('hill/', ''),
 
2448
            'success', ('ok', 'a token'))
 
2449
        client.add_success_response_with_body(body, 'ok')
 
2450
        reconciler = repo.reconcile()
 
2451
        self.assertEqual(
 
2452
            [('call', 'Repository.lock_write', ('hill/', '')),
 
2453
             ('call_expecting_body', 'Repository.reconcile',
 
2454
                ('hill/', 'a token'))],
 
2455
            client._calls)
 
2456
        self.assertEqual(2, reconciler.garbage_inventories)
 
2457
        self.assertEqual(3, reconciler.inconsistent_parents)
 
2458
 
 
2459
 
 
2460
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2461
 
 
2462
    def test_text(self):
 
2463
        # ('ok',), body with signature text
 
2464
        transport_path = 'quack'
 
2465
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2466
        client.add_success_response_with_body(
 
2467
            'THETEXT', 'ok')
 
2468
        self.assertEqual("THETEXT", repo.get_signature_text("revid"))
 
2469
        self.assertEqual(
 
2470
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2471
             ('quack/', 'revid'))],
 
2472
            client._calls)
 
2473
 
 
2474
    def test_no_signature(self):
 
2475
        transport_path = 'quick'
 
2476
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2477
        client.add_error_response('nosuchrevision', 'unknown')
 
2478
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2479
                "unknown")
 
2480
        self.assertEqual(
 
2481
            [('call_expecting_body', 'Repository.get_revision_signature_text',
 
2482
              ('quick/', 'unknown'))],
 
2483
            client._calls)
 
2484
 
 
2485
 
1906
2486
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2487
 
1908
2488
    def test_get_graph(self):
1913
2493
        self.assertNotEqual(graph._parents_provider, repo)
1914
2494
 
1915
2495
 
 
2496
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2497
 
 
2498
    def test_add_signature_text(self):
 
2499
        transport_path = 'quack'
 
2500
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2501
        client.add_expected_call(
 
2502
            'Repository.lock_write', ('quack/', ''),
 
2503
            'success', ('ok', 'a token'))
 
2504
        client.add_expected_call(
 
2505
            'Repository.start_write_group', ('quack/', 'a token'),
 
2506
            'success', ('ok', ('token1', )))
 
2507
        client.add_expected_call(
 
2508
            'Repository.add_signature_text', ('quack/', 'a token', 'rev1',
 
2509
                'token1'),
 
2510
            'success', ('ok', ), None)
 
2511
        repo.lock_write()
 
2512
        repo.start_write_group()
 
2513
        self.assertIs(None,
 
2514
            repo.add_signature_text("rev1", "every bloody emperor"))
 
2515
        self.assertEqual(
 
2516
            ('call_with_body_bytes_expecting_body',
 
2517
              'Repository.add_signature_text',
 
2518
                ('quack/', 'a token', 'rev1', 'token1'),
 
2519
              'every bloody emperor'),
 
2520
            client._calls[-1])
 
2521
 
 
2522
 
1916
2523
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2524
 
1918
2525
    def test_get_parent_map_caching(self):
1968
2575
        parents = repo.get_parent_map([rev_id])
1969
2576
        self.assertEqual(
1970
2577
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2578
              'Repository.get_parent_map',
 
2579
              ('quack/', 'include-missing:', rev_id), '\n\n0'),
1973
2580
             ('disconnect medium',),
1974
2581
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
2582
              ('quack/', ''))],
2042
2649
        # Make a branch with a single revision.
2043
2650
        builder = self.make_branch_builder('foo')
2044
2651
        builder.start_series()
2045
 
        builder.build_snapshot('first', None, [
2046
 
            ('add', ('', 'root-id', 'directory', ''))])
 
2652
        builder.build_snapshot(None, [
 
2653
            ('add', ('', 'root-id', 'directory', ''))],
 
2654
            revision_id='first')
2047
2655
        builder.finish_series()
2048
2656
        branch = builder.get_branch()
2049
2657
        repo = branch.repository
2095
2703
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2704
        self.assertLength(0, self.hpss_calls)
2097
2705
 
 
2706
    def test_exposes_get_cached_parent_map(self):
 
2707
        """RemoteRepository exposes get_cached_parent_map from
 
2708
        _unstacked_provider
 
2709
        """
 
2710
        r1 = u'\u0e33'.encode('utf8')
 
2711
        r2 = u'\u0dab'.encode('utf8')
 
2712
        lines = [' '.join([r2, r1]), r1]
 
2713
        encoded_body = bz2.compress('\n'.join(lines))
 
2714
 
 
2715
        transport_path = 'quack'
 
2716
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2717
        client.add_success_response_with_body(encoded_body, 'ok')
 
2718
        repo.lock_read()
 
2719
        # get_cached_parent_map should *not* trigger an RPC
 
2720
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2721
        self.assertEqual([], client._calls)
 
2722
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2723
        self.assertEqual({r1: (NULL_REVISION,)},
 
2724
            repo.get_cached_parent_map([r1]))
 
2725
        self.assertEqual(
 
2726
            [('call_with_body_bytes_expecting_body',
 
2727
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2728
              '\n\n0')],
 
2729
            client._calls)
 
2730
        repo.unlock()
 
2731
 
2098
2732
 
2099
2733
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2734
 
2110
2744
        graph = tree.branch.repository.get_graph()
2111
2745
        # This provides an opportunity for the missing rev-id to be cached.
2112
2746
        self.assertEqual({}, graph.get_parent_map(['rev1']))
2113
 
        tree.commit('message', rev_id='rev1')
 
2747
        tree.commit('message', rev_id=b'rev1')
2114
2748
        graph = tree.branch.repository.get_graph()
2115
2749
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2116
2750
 
2117
2751
 
 
2752
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2753
 
 
2754
    def test_hpss_missing_revision(self):
 
2755
        transport_path = 'quack'
 
2756
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2757
        client.add_success_response_with_body(
 
2758
            '', 'ok', '10')
 
2759
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2760
            ['somerev1', 'anotherrev2'])
 
2761
        self.assertEqual(
 
2762
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2763
             ('quack/', ), "somerev1\nanotherrev2")],
 
2764
            client._calls)
 
2765
 
 
2766
    def test_hpss_get_single_revision(self):
 
2767
        transport_path = 'quack'
 
2768
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2769
        somerev1 = Revision("somerev1")
 
2770
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2771
        somerev1.timestamp = 1321828927
 
2772
        somerev1.timezone = -60
 
2773
        somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2774
        somerev1.message = "Message"
 
2775
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2776
            somerev1))
 
2777
        # Split up body into two bits to make sure the zlib compression object
 
2778
        # gets data fed twice.
 
2779
        client.add_success_response_with_body(
 
2780
                [body[:10], body[10:]], 'ok', '10')
 
2781
        revs = repo.get_revisions(['somerev1'])
 
2782
        self.assertEqual(revs, [somerev1])
 
2783
        self.assertEqual(
 
2784
            [('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
 
2785
             ('quack/', ), "somerev1")],
 
2786
            client._calls)
 
2787
 
 
2788
 
2118
2789
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2119
2790
 
2120
2791
    def test_null_revision(self):
2231
2902
        # Then it should ask the fallback, using revno/revid from the
2232
2903
        # history-incomplete response as the known revno/revid.
2233
2904
        client.add_expected_call(
2234
 
            'Repository.get_rev_id_for_revno',('fallback/', 1, (2, 'rev-two')),
 
2905
            'Repository.get_rev_id_for_revno', ('fallback/', 1, (2, 'rev-two')),
2235
2906
            'success', ('ok', 'rev-one'))
2236
2907
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2237
2908
        self.assertEqual((True, 'rev-one'), result)
2257
2928
        self.setup_smart_server_with_call_log()
2258
2929
        tree = self.make_branch_and_memory_tree('.')
2259
2930
        tree.lock_write()
 
2931
        tree.add('')
2260
2932
        rev1 = tree.commit('First')
2261
2933
        rev2 = tree.commit('Second')
2262
2934
        tree.unlock()
2270
2942
                              call.call.method == verb])
2271
2943
 
2272
2944
 
 
2945
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2946
 
 
2947
    def test_has_signature_for_revision_id(self):
 
2948
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2949
        transport_path = 'quack'
 
2950
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2951
        client.add_success_response('yes')
 
2952
        result = repo.has_signature_for_revision_id('A')
 
2953
        self.assertEqual(
 
2954
            [('call', 'Repository.has_signature_for_revision_id',
 
2955
              ('quack/', 'A'))],
 
2956
            client._calls)
 
2957
        self.assertEqual(True, result)
 
2958
 
 
2959
    def test_is_not_shared(self):
 
2960
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2961
        transport_path = 'qwack'
 
2962
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2963
        client.add_success_response('no')
 
2964
        result = repo.has_signature_for_revision_id('A')
 
2965
        self.assertEqual(
 
2966
            [('call', 'Repository.has_signature_for_revision_id',
 
2967
              ('qwack/', 'A'))],
 
2968
            client._calls)
 
2969
        self.assertEqual(False, result)
 
2970
 
 
2971
 
 
2972
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2973
 
 
2974
    def test_get_physical_lock_status_yes(self):
 
2975
        transport_path = 'qwack'
 
2976
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2977
        client.add_success_response('yes')
 
2978
        result = repo.get_physical_lock_status()
 
2979
        self.assertEqual(
 
2980
            [('call', 'Repository.get_physical_lock_status',
 
2981
              ('qwack/', ))],
 
2982
            client._calls)
 
2983
        self.assertEqual(True, result)
 
2984
 
 
2985
    def test_get_physical_lock_status_no(self):
 
2986
        transport_path = 'qwack'
 
2987
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2988
        client.add_success_response('no')
 
2989
        result = repo.get_physical_lock_status()
 
2990
        self.assertEqual(
 
2991
            [('call', 'Repository.get_physical_lock_status',
 
2992
              ('qwack/', ))],
 
2993
            client._calls)
 
2994
        self.assertEqual(False, result)
 
2995
 
 
2996
 
2273
2997
class TestRepositoryIsShared(TestRemoteRepository):
2274
2998
 
2275
2999
    def test_is_shared(self):
2295
3019
        self.assertEqual(False, result)
2296
3020
 
2297
3021
 
 
3022
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3023
 
 
3024
    def test_make_working_trees(self):
 
3025
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3026
        transport_path = 'quack'
 
3027
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3028
        client.add_success_response('yes')
 
3029
        result = repo.make_working_trees()
 
3030
        self.assertEqual(
 
3031
            [('call', 'Repository.make_working_trees', ('quack/',))],
 
3032
            client._calls)
 
3033
        self.assertEqual(True, result)
 
3034
 
 
3035
    def test_no_working_trees(self):
 
3036
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3037
        transport_path = 'qwack'
 
3038
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3039
        client.add_success_response('no')
 
3040
        result = repo.make_working_trees()
 
3041
        self.assertEqual(
 
3042
            [('call', 'Repository.make_working_trees', ('qwack/',))],
 
3043
            client._calls)
 
3044
        self.assertEqual(False, result)
 
3045
 
 
3046
 
2298
3047
class TestRepositoryLockWrite(TestRemoteRepository):
2299
3048
 
2300
3049
    def test_lock_write(self):
2301
3050
        transport_path = 'quack'
2302
3051
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3052
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3053
        token = repo.lock_write().repository_token
2305
3054
        self.assertEqual(
2306
3055
            [('call', 'Repository.lock_write', ('quack/', ''))],
2307
3056
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3057
        self.assertEqual('a token', token)
2309
3058
 
2310
3059
    def test_lock_write_already_locked(self):
2311
3060
        transport_path = 'quack'
2326
3075
            client._calls)
2327
3076
 
2328
3077
 
 
3078
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3079
 
 
3080
    def test_start_write_group(self):
 
3081
        transport_path = 'quack'
 
3082
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3083
        client.add_expected_call(
 
3084
            'Repository.lock_write', ('quack/', ''),
 
3085
            'success', ('ok', 'a token'))
 
3086
        client.add_expected_call(
 
3087
            'Repository.start_write_group', ('quack/', 'a token'),
 
3088
            'success', ('ok', ('token1', )))
 
3089
        repo.lock_write()
 
3090
        repo.start_write_group()
 
3091
 
 
3092
    def test_start_write_group_unsuspendable(self):
 
3093
        # Some repositories do not support suspending write
 
3094
        # groups. For those, fall back to the "real" repository.
 
3095
        transport_path = 'quack'
 
3096
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3097
        def stub_ensure_real():
 
3098
            client._calls.append(('_ensure_real',))
 
3099
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3100
        repo._ensure_real = stub_ensure_real
 
3101
        client.add_expected_call(
 
3102
            'Repository.lock_write', ('quack/', ''),
 
3103
            'success', ('ok', 'a token'))
 
3104
        client.add_expected_call(
 
3105
            'Repository.start_write_group', ('quack/', 'a token'),
 
3106
            'error', ('UnsuspendableWriteGroup',))
 
3107
        repo.lock_write()
 
3108
        repo.start_write_group()
 
3109
        self.assertEqual(client._calls[-2:], [ 
 
3110
            ('_ensure_real',),
 
3111
            ('start_write_group',)])
 
3112
 
 
3113
    def test_commit_write_group(self):
 
3114
        transport_path = 'quack'
 
3115
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3116
        client.add_expected_call(
 
3117
            'Repository.lock_write', ('quack/', ''),
 
3118
            'success', ('ok', 'a token'))
 
3119
        client.add_expected_call(
 
3120
            'Repository.start_write_group', ('quack/', 'a token'),
 
3121
            'success', ('ok', ['token1']))
 
3122
        client.add_expected_call(
 
3123
            'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
 
3124
            'success', ('ok',))
 
3125
        repo.lock_write()
 
3126
        repo.start_write_group()
 
3127
        repo.commit_write_group()
 
3128
 
 
3129
    def test_abort_write_group(self):
 
3130
        transport_path = 'quack'
 
3131
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3132
        client.add_expected_call(
 
3133
            'Repository.lock_write', ('quack/', ''),
 
3134
            'success', ('ok', 'a token'))
 
3135
        client.add_expected_call(
 
3136
            'Repository.start_write_group', ('quack/', 'a token'),
 
3137
            'success', ('ok', ['token1']))
 
3138
        client.add_expected_call(
 
3139
            'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
 
3140
            'success', ('ok',))
 
3141
        repo.lock_write()
 
3142
        repo.start_write_group()
 
3143
        repo.abort_write_group(False)
 
3144
 
 
3145
    def test_suspend_write_group(self):
 
3146
        transport_path = 'quack'
 
3147
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3148
        self.assertEqual([], repo.suspend_write_group())
 
3149
 
 
3150
    def test_resume_write_group(self):
 
3151
        transport_path = 'quack'
 
3152
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3153
        client.add_expected_call(
 
3154
            'Repository.lock_write', ('quack/', ''),
 
3155
            'success', ('ok', 'a token'))
 
3156
        client.add_expected_call(
 
3157
            'Repository.check_write_group', ('quack/', 'a token', ['token1']),
 
3158
            'success', ('ok',))
 
3159
        repo.lock_write()
 
3160
        repo.resume_write_group(['token1'])
 
3161
 
 
3162
 
2329
3163
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3164
 
2331
3165
    def test_backwards_compat(self):
2390
3224
        self.assertEqual([], client._calls)
2391
3225
 
2392
3226
 
 
3227
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3228
    """Test Repository.iter_file_bytes."""
 
3229
 
 
3230
    def test_single(self):
 
3231
        transport_path = 'quack'
 
3232
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3233
        client.add_expected_call(
 
3234
            'Repository.iter_files_bytes', ('quack/', ),
 
3235
            'success', ('ok',), iter(["ok\x000", "\n", zlib.compress("mydata" * 10)]))
 
3236
        for (identifier, byte_stream) in repo.iter_files_bytes([("somefile",
 
3237
                "somerev", "myid")]):
 
3238
            self.assertEqual("myid", identifier)
 
3239
            self.assertEqual("".join(byte_stream), "mydata" * 10)
 
3240
 
 
3241
    def test_missing(self):
 
3242
        transport_path = 'quack'
 
3243
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3244
        client.add_expected_call(
 
3245
            'Repository.iter_files_bytes',
 
3246
                ('quack/', ),
 
3247
            'error', ('RevisionNotPresent', 'somefile', 'somerev'),
 
3248
            iter(["absent\0somefile\0somerev\n"]))
 
3249
        self.assertRaises(errors.RevisionNotPresent, list,
 
3250
                repo.iter_files_bytes(
 
3251
                [("somefile", "somerev", "myid")]))
 
3252
 
 
3253
 
2393
3254
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3255
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3256
    tests.
2402
3263
        the client is finished.
2403
3264
        """
2404
3265
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3266
        fmt = repository.format_registry.get_default()
2406
3267
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3268
        self.assertEqual([], resume_tokens)
2408
3269
        self.assertEqual(set(), missing_keys)
2417
3278
    """
2418
3279
 
2419
3280
    def setUp(self):
2420
 
        TestRemoteRepository.setUp(self)
 
3281
        super(TestRepositoryInsertStream, self).setUp()
2421
3282
        self.disable_verb('Repository.insert_stream_1.19')
2422
3283
 
2423
3284
    def test_unlocked_repo(self):
2508
3369
                return True
2509
3370
        repo._real_repository = FakeRealRepository()
2510
3371
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3372
        fmt = repository.format_registry.get_default()
2512
3373
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3374
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3375
        # Every record from the first inventory delta should have been sent to
2613
3474
class TestRepositoryTarball(TestRemoteRepository):
2614
3475
 
2615
3476
    # This is a canned tarball reponse we can validate against
2616
 
    tarball_content = (
 
3477
    tarball_content = base64.b64decode(
2617
3478
        'QlpoOTFBWSZTWdGkj3wAAWF/k8aQACBIB//A9+8cIX/v33AACEAYABAECEACNz'
2618
3479
        'JqsgJJFPTSnk1A3qh6mTQAAAANPUHkagkSTEkaA09QaNAAAGgAAAcwCYCZGAEY'
2619
3480
        'mJhMJghpiaYBUkKammSHqNMZQ0NABkNAeo0AGneAevnlwQoGzEzNVzaYxp/1Uk'
2626
3487
        'QplPKp2nqBWAfwBGaOwVrz3y1T+UZZNismXHsb2Jq18T+VaD9k4P8DqE3g70qV'
2627
3488
        'JLurpnDI6VS5oqDDPVbtVjMxMxMg4rzQVipn2Bv1fVNK0iq3Gl0hhnnHKm/egy'
2628
3489
        'nWQ7QH/F3JFOFCQ0aSPfA='
2629
 
        ).decode('base64')
 
3490
        )
2630
3491
 
2631
3492
    def test_repository_tarball(self):
2632
3493
        # Test that Repository.tarball generates the right operations
2670
3531
        self.calls = calls
2671
3532
        self._pack_collection = _StubPackCollection(calls)
2672
3533
 
 
3534
    def start_write_group(self):
 
3535
        self.calls.append(('start_write_group',))
 
3536
 
2673
3537
    def is_in_write_group(self):
2674
3538
        return False
2675
3539
 
2734
3598
             ('pack collection autopack',)],
2735
3599
            client._calls)
2736
3600
 
 
3601
    def test_oom_error_reporting(self):
 
3602
        """An out-of-memory condition on the server is reported clearly"""
 
3603
        transport_path = 'quack'
 
3604
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3605
        client.add_expected_call(
 
3606
            'PackRepository.autopack', ('quack/',),
 
3607
            'error', ('MemoryError',))
 
3608
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3609
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3610
 
2737
3611
 
2738
3612
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
 
    """Base class for unit tests for bzrlib.remote._translate_error."""
 
3613
    """Base class for unit tests for breezy.bzr.remote._translate_error."""
2740
3614
 
2741
3615
    def translateTuple(self, error_tuple, **context):
2742
3616
        """Call _translate_error with an ErrorFromSmartServer built from the
2762
3636
        """
2763
3637
        try:
2764
3638
            raise error_object
2765
 
        except errors.ErrorFromSmartServer, server_error:
 
3639
        except errors.ErrorFromSmartServer as server_error:
2766
3640
            translated_error = self.assertRaises(
2767
3641
                errors.BzrError, remote._translate_error, server_error,
2768
3642
                **context)
2770
3644
 
2771
3645
 
2772
3646
class TestErrorTranslationSuccess(TestErrorTranslationBase):
2773
 
    """Unit tests for bzrlib.remote._translate_error.
 
3647
    """Unit tests for breezy.bzr.remote._translate_error.
2774
3648
 
2775
3649
    Given an ErrorFromSmartServer (which has an error tuple from a smart
2776
3650
    server) and some context, _translate_error raises more specific errors from
2777
 
    bzrlib.errors.
 
3651
    breezy.errors.
2778
3652
 
2779
3653
    This test case covers the cases where _translate_error succeeds in
2780
3654
    translating an ErrorFromSmartServer to something better.  See
2798
3672
        self.assertEqual(expected_error, translated_error)
2799
3673
 
2800
3674
    def test_nobranch(self):
2801
 
        bzrdir = self.make_bzrdir('')
 
3675
        bzrdir = self.make_controldir('')
2802
3676
        translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
2803
3677
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3678
        self.assertEqual(expected_error, translated_error)
2805
3679
 
2806
3680
    def test_nobranch_one_arg(self):
2807
 
        bzrdir = self.make_bzrdir('')
 
3681
        bzrdir = self.make_controldir('')
2808
3682
        translated_error = self.translateTuple(
2809
3683
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
2810
3684
        expected_error = errors.NotBranchError(
2812
3686
            detail='extra detail')
2813
3687
        self.assertEqual(expected_error, translated_error)
2814
3688
 
 
3689
    def test_norepository(self):
 
3690
        bzrdir = self.make_controldir('')
 
3691
        translated_error = self.translateTuple(('norepository',),
 
3692
            bzrdir=bzrdir)
 
3693
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3694
        self.assertEqual(expected_error, translated_error)
 
3695
 
2815
3696
    def test_LockContention(self):
2816
3697
        translated_error = self.translateTuple(('LockContention',))
2817
3698
        expected_error = errors.LockContention('(remote lock)')
2818
3699
        self.assertEqual(expected_error, translated_error)
2819
3700
 
2820
3701
    def test_UnlockableTransport(self):
2821
 
        bzrdir = self.make_bzrdir('')
 
3702
        bzrdir = self.make_controldir('')
2822
3703
        translated_error = self.translateTuple(
2823
3704
            ('UnlockableTransport',), bzrdir=bzrdir)
2824
3705
        expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2845
3726
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3727
        self.assertEqual(expected_error, translated_error)
2847
3728
 
 
3729
    def test_NotStacked(self):
 
3730
        branch = self.make_branch('')
 
3731
        translated_error = self.translateTuple(('NotStacked',), branch=branch)
 
3732
        expected_error = errors.NotStacked(branch)
 
3733
        self.assertEqual(expected_error, translated_error)
 
3734
 
2848
3735
    def test_ReadError_no_args(self):
2849
3736
        path = 'a path'
2850
3737
        translated_error = self.translateTuple(('ReadError',), path=path)
2866
3753
 
2867
3754
    def test_PermissionDenied_no_args(self):
2868
3755
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3756
        translated_error = self.translateTuple(('PermissionDenied',),
 
3757
            path=path)
2870
3758
        expected_error = errors.PermissionDenied(path)
2871
3759
        self.assertEqual(expected_error, translated_error)
2872
3760
 
2895
3783
        expected_error = errors.PermissionDenied(path, extra)
2896
3784
        self.assertEqual(expected_error, translated_error)
2897
3785
 
 
3786
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3787
 
 
3788
    def test_NoSuchFile_context_path(self):
 
3789
        local_path = "local path"
 
3790
        translated_error = self.translateTuple(('ReadError', "remote path"),
 
3791
            path=local_path)
 
3792
        expected_error = errors.ReadError(local_path)
 
3793
        self.assertEqual(expected_error, translated_error)
 
3794
 
 
3795
    def test_NoSuchFile_without_context(self):
 
3796
        remote_path = "remote path"
 
3797
        translated_error = self.translateTuple(('ReadError', remote_path))
 
3798
        expected_error = errors.ReadError(remote_path)
 
3799
        self.assertEqual(expected_error, translated_error)
 
3800
 
 
3801
    def test_ReadOnlyError(self):
 
3802
        translated_error = self.translateTuple(('ReadOnlyError',))
 
3803
        expected_error = errors.TransportNotPossible("readonly transport")
 
3804
        self.assertEqual(expected_error, translated_error)
 
3805
 
 
3806
    def test_MemoryError(self):
 
3807
        translated_error = self.translateTuple(('MemoryError',))
 
3808
        self.assertStartsWith(str(translated_error),
 
3809
            "remote server out of memory")
 
3810
 
 
3811
    def test_generic_IndexError_no_classname(self):
 
3812
        err = errors.ErrorFromSmartServer(('error', "list index out of range"))
 
3813
        translated_error = self.translateErrorFromSmartServer(err)
 
3814
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3815
        self.assertEqual(expected_error, translated_error)
 
3816
 
 
3817
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3818
 
 
3819
    def test_generic_KeyError(self):
 
3820
        err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
 
3821
        translated_error = self.translateErrorFromSmartServer(err)
 
3822
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3823
        self.assertEqual(expected_error, translated_error)
 
3824
 
2898
3825
 
2899
3826
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
 
    """Unit tests for bzrlib.remote._translate_error's robustness.
 
3827
    """Unit tests for breezy.bzr.remote._translate_error's robustness.
2901
3828
 
2902
3829
    TestErrorTranslationSuccess is for cases where _translate_error can
2903
3830
    translate successfully.  This class about how _translate_err behaves when
2961
3888
        base_transport = self.get_transport()
2962
3889
        base_builder = self.make_branch_builder('base', format='1.9')
2963
3890
        base_builder.start_series()
2964
 
        base_revid = base_builder.build_snapshot('rev-id', None,
 
3891
        base_revid = base_builder.build_snapshot(None,
2965
3892
            [('add', ('', None, 'directory', None))],
2966
 
            'message')
 
3893
            'message', revision_id='rev-id')
2967
3894
        base_builder.finish_series()
2968
3895
        stacked_branch = self.make_branch('stacked', format='1.9')
2969
3896
        stacked_branch.set_stacked_on_url('../base')
2994
3921
        """Get stacked_upon and stacked branches with content in each."""
2995
3922
        self.setup_smart_server_with_call_log()
2996
3923
        tree1 = self.make_branch_and_tree('tree1', format='1.9')
2997
 
        tree1.commit('rev1', rev_id='rev1')
2998
 
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
 
3924
        tree1.commit('rev1', rev_id=b'rev1')
 
3925
        tree2 = tree1.branch.controldir.sprout('tree2', stacked=True
2999
3926
            ).open_workingtree()
3000
3927
        local_tree = tree2.branch.create_checkout('local')
3001
3928
        local_tree.commit('local changes make me feel good.')
3008
3935
        # the public implementation of get_parent_map obeys stacking
3009
3936
        _, branch = self.prepare_stacked_remote_branch()
3010
3937
        repo = branch.repository
3011
 
        self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
 
3938
        self.assertEqual({'rev1'}, set(repo.get_parent_map(['rev1'])))
3012
3939
 
3013
3940
    def test_unstacked_get_parent_map(self):
3014
3941
        # _unstacked_provider.get_parent_map ignores stacking
3015
3942
        _, branch = self.prepare_stacked_remote_branch()
3016
3943
        provider = branch.repository._unstacked_provider
3017
 
        self.assertEqual([], provider.get_parent_map(['rev1']).keys())
 
3944
        self.assertEqual(set(), set(provider.get_parent_map(['rev1'])))
3018
3945
 
3019
3946
    def fetch_stream_to_rev_order(self, stream):
3020
3947
        result = []
3036
3963
        :result: The revision ids in the stream, in the order seen,
3037
3964
            the topological order of revisions in the source.
3038
3965
        """
3039
 
        unordered_format = bzrdir.format_registry.get(format)()
 
3966
        unordered_format = controldir.format_registry.get(format)()
3040
3967
        target_repository_format = unordered_format.repository_format
3041
3968
        # Cross check
3042
3969
        self.assertEqual(order, target_repository_format._fetch_order)
3045
3972
        _, stacked = branch_factory()
3046
3973
        source = stacked.repository._get_source(target_repository_format)
3047
3974
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3975
        stacked.repository._ensure_real()
 
3976
        graph = stacked.repository.get_graph()
 
3977
        revs = [r for (r, ps) in graph.iter_ancestry([tip])
 
3978
                if r != NULL_REVISION]
 
3979
        revs.reverse()
 
3980
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3981
        self.reset_smart_call_log()
3051
3982
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3983
        # We trust that if a revision is in the stream the rest of the new
3055
3984
        # content for it is too, as per our main fetch tests; here we are
3056
3985
        # checking that the revisions are actually included at all, and their
3072
4001
        # is itself stacked yields the full data from all three sources.
3073
4002
        def make_stacked_stacked():
3074
4003
            _, stacked = self.prepare_stacked_remote_branch()
3075
 
            tree = stacked.bzrdir.sprout('tree3', stacked=True
 
4004
            tree = stacked.controldir.sprout('tree3', stacked=True
3076
4005
                ).open_workingtree()
3077
4006
            local_tree = tree.branch.create_checkout('local-tree3')
3078
4007
            local_tree.commit('more local changes are better')
3095
4024
        self.assertEqual(expected_revs, rev_ord)
3096
4025
        # Getting topological sort requires VFS calls still - one of which is
3097
4026
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4027
        self.assertLength(14, self.hpss_calls)
3099
4028
 
3100
4029
    def test_stacked_get_stream_groupcompress(self):
3101
4030
        # Repository._get_source.get_stream() from a stacked repository with
3142
4071
 
3143
4072
    def test_copy_content_into_avoids_revision_history(self):
3144
4073
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4074
        builder = self.make_branch_builder('remote')
 
4075
        builder.build_commit(message="Commit.")
3147
4076
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4077
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4078
        local.repository.fetch(remote_branch.repository)
3150
4079
        self.hpss_calls = []
3151
4080
        remote_branch.copy_content_into(local)
3152
4081
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4082
 
 
4083
    def test_fetch_everything_needs_just_one_call(self):
 
4084
        local = self.make_branch('local')
 
4085
        builder = self.make_branch_builder('remote')
 
4086
        builder.build_commit(message="Commit.")
 
4087
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4088
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4089
        self.hpss_calls = []
 
4090
        local.repository.fetch(
 
4091
            remote_branch.repository,
 
4092
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4093
        self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
 
4094
 
 
4095
    def override_verb(self, verb_name, verb):
 
4096
        request_handlers = request.request_handlers
 
4097
        orig_verb = request_handlers.get(verb_name)
 
4098
        orig_info = request_handlers.get_info(verb_name)
 
4099
        request_handlers.register(verb_name, verb, override_existing=True)
 
4100
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4101
                override_existing=True, info=orig_info)
 
4102
 
 
4103
    def test_fetch_everything_backwards_compat(self):
 
4104
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4105
        
 
4106
        Pre-2.4 do not support 'everything' searches with the
 
4107
        Repository.get_stream_1.19 verb.
 
4108
        """
 
4109
        verb_log = []
 
4110
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4111
            """A version of the Repository.get_stream_1.19 verb patched to
 
4112
            reject 'everything' searches the way 2.3 and earlier do.
 
4113
            """
 
4114
            def recreate_search(self, repository, search_bytes,
 
4115
                                discard_excess=False):
 
4116
                verb_log.append(search_bytes.split('\n', 1)[0])
 
4117
                if search_bytes == 'everything':
 
4118
                    return (None,
 
4119
                            request.FailedSmartServerResponse(('BadSearch',)))
 
4120
                return super(OldGetStreamVerb,
 
4121
                        self).recreate_search(repository, search_bytes,
 
4122
                            discard_excess=discard_excess)
 
4123
        self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
 
4124
        local = self.make_branch('local')
 
4125
        builder = self.make_branch_builder('remote')
 
4126
        builder.build_commit(message="Commit.")
 
4127
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4128
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4129
        self.hpss_calls = []
 
4130
        local.repository.fetch(
 
4131
            remote_branch.repository,
 
4132
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4133
        # make sure the overridden verb was used
 
4134
        self.assertLength(1, verb_log)
 
4135
        # more than one HPSS call is needed, but because it's a VFS callback
 
4136
        # its hard to predict exactly how many.
 
4137
        self.assertTrue(len(self.hpss_calls) > 1)
 
4138
 
 
4139
 
 
4140
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4141
    tests.TestCaseWithTransport):
 
4142
    """Ensure correct handling of bound_location modifications.
 
4143
 
 
4144
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4145
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4146
    happen in this context.
 
4147
    """
 
4148
 
 
4149
    def setUp(self):
 
4150
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4151
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4152
 
 
4153
    def make_master_and_checkout(self, master_name, checkout_name):
 
4154
        # Create the master branch and its associated checkout
 
4155
        self.master = self.make_branch_and_tree(master_name)
 
4156
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4157
        # Modify the master branch so there is something to update
 
4158
        self.master.commit('add stuff')
 
4159
        self.last_revid = self.master.commit('even more stuff')
 
4160
        self.bound_location = self.checkout.branch.get_bound_location()
 
4161
 
 
4162
    def assertUpdateSucceeds(self, new_location):
 
4163
        self.checkout.branch.set_bound_location(new_location)
 
4164
        self.checkout.update()
 
4165
        self.assertEqual(self.last_revid, self.checkout.last_revision())
 
4166
 
 
4167
    def test_without_final_slash(self):
 
4168
        self.make_master_and_checkout('master', 'checkout')
 
4169
        # For unclear reasons some users have a bound_location without a final
 
4170
        # '/', simulate that by forcing such a value
 
4171
        self.assertEndsWith(self.bound_location, '/')
 
4172
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4173
 
 
4174
    def test_plus_sign(self):
 
4175
        self.make_master_and_checkout('+master', 'checkout')
 
4176
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4177
 
 
4178
    def test_tilda(self):
 
4179
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4180
        # interpretation
 
4181
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4182
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4183
 
 
4184
 
 
4185
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4186
 
 
4187
    def test_no_context(self):
 
4188
        class OutOfCoffee(errors.BzrError):
 
4189
            """A dummy exception for testing."""
 
4190
 
 
4191
            def __init__(self, urgency):
 
4192
                self.urgency = urgency
 
4193
        remote.no_context_error_translators.register("OutOfCoffee",
 
4194
            lambda err: OutOfCoffee(err.error_args[0]))
 
4195
        transport = MemoryTransport()
 
4196
        client = FakeClient(transport.base)
 
4197
        client.add_expected_call(
 
4198
            'Branch.get_stacked_on_url', ('quack/',),
 
4199
            'error', ('NotStacked',))
 
4200
        client.add_expected_call(
 
4201
            'Branch.last_revision_info',
 
4202
            ('quack/',),
 
4203
            'error', ('OutOfCoffee', 'low'))
 
4204
        transport.mkdir('quack')
 
4205
        transport = transport.clone('quack')
 
4206
        branch = self.make_remote_branch(transport, client)
 
4207
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4208
        self.assertFinished(client)
 
4209
 
 
4210
    def test_with_context(self):
 
4211
        class OutOfTea(errors.BzrError):
 
4212
            def __init__(self, branch, urgency):
 
4213
                self.branch = branch
 
4214
                self.urgency = urgency
 
4215
        remote.error_translators.register("OutOfTea",
 
4216
            lambda err, find, path: OutOfTea(err.error_args[0],
 
4217
                find("branch")))
 
4218
        transport = MemoryTransport()
 
4219
        client = FakeClient(transport.base)
 
4220
        client.add_expected_call(
 
4221
            'Branch.get_stacked_on_url', ('quack/',),
 
4222
            'error', ('NotStacked',))
 
4223
        client.add_expected_call(
 
4224
            'Branch.last_revision_info',
 
4225
            ('quack/',),
 
4226
            'error', ('OutOfTea', 'low'))
 
4227
        transport.mkdir('quack')
 
4228
        transport = transport.clone('quack')
 
4229
        branch = self.make_remote_branch(transport, client)
 
4230
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4231
        self.assertFinished(client)
 
4232
 
 
4233
 
 
4234
class TestRepositoryPack(TestRemoteRepository):
 
4235
 
 
4236
    def test_pack(self):
 
4237
        transport_path = 'quack'
 
4238
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4239
        client.add_expected_call(
 
4240
            'Repository.lock_write', ('quack/', ''),
 
4241
            'success', ('ok', 'token'))
 
4242
        client.add_expected_call(
 
4243
            'Repository.pack', ('quack/', 'token', 'False'),
 
4244
            'success', ('ok',), )
 
4245
        client.add_expected_call(
 
4246
            'Repository.unlock', ('quack/', 'token'),
 
4247
            'success', ('ok', ))
 
4248
        repo.pack()
 
4249
 
 
4250
    def test_pack_with_hint(self):
 
4251
        transport_path = 'quack'
 
4252
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4253
        client.add_expected_call(
 
4254
            'Repository.lock_write', ('quack/', ''),
 
4255
            'success', ('ok', 'token'))
 
4256
        client.add_expected_call(
 
4257
            'Repository.pack', ('quack/', 'token', 'False'),
 
4258
            'success', ('ok',), )
 
4259
        client.add_expected_call(
 
4260
            'Repository.unlock', ('quack/', 'token', 'False'),
 
4261
            'success', ('ok', ))
 
4262
        repo.pack(['hinta', 'hintb'])
 
4263
 
 
4264
 
 
4265
class TestRepositoryIterInventories(TestRemoteRepository):
 
4266
    """Test Repository.iter_inventories."""
 
4267
 
 
4268
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4269
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4270
        return "".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4271
 
 
4272
    def test_single_empty(self):
 
4273
        transport_path = 'quack'
 
4274
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4275
        fmt = controldir.format_registry.get('2a')().repository_format
 
4276
        repo._format = fmt
 
4277
        stream = [('inventory-deltas', [
 
4278
            versionedfile.FulltextContentFactory('somerevid', None, None,
 
4279
                self._serialize_inv_delta('null:', 'somerevid', []))])]
 
4280
        client.add_expected_call(
 
4281
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4282
            'success', ('ok', ),
 
4283
            _stream_to_byte_stream(stream, fmt))
 
4284
        ret = list(repo.iter_inventories(["somerevid"]))
 
4285
        self.assertLength(1, ret)
 
4286
        inv = ret[0]
 
4287
        self.assertEqual("somerevid", inv.revision_id)
 
4288
 
 
4289
    def test_empty(self):
 
4290
        transport_path = 'quack'
 
4291
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4292
        ret = list(repo.iter_inventories([]))
 
4293
        self.assertEqual(ret, [])
 
4294
 
 
4295
    def test_missing(self):
 
4296
        transport_path = 'quack'
 
4297
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4298
        client.add_expected_call(
 
4299
            'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
 
4300
            'success', ('ok', ), iter([]))
 
4301
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4302
            ["somerevid"]))