/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: 2017-06-10 21:59:15 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170610215915-zcpu0in3r1irx3ml
Move serializer to bzr.

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