/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: Martin
  • Date: 2017-08-26 13:09:08 UTC
  • mto: (6754.4.4 check)
  • mto: This revision was merged to the branch mainline in revision 6755.
  • Revision ID: gzlist@googlemail.com-20170826130908-acpf9jit3h51kus1
Use future divison in lru_cache to pass tests on Python 3

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