/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_remote.py

  • Committer: Jelmer Vernooij
  • Date: 2018-06-11 20:48:24 UTC
  • mfrom: (6974.2.1 python3-graph)
  • Revision ID: jelmer@jelmer.uk-20180611204824-zll0a3pzyciekd1f
merge lp:~jelmer/brz/python3-graph

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2013, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
23
23
These tests correspond to tests.test_smart, which exercises the server side.
24
24
"""
25
25
 
 
26
import base64
26
27
import bz2
27
 
from cStringIO import StringIO
 
28
import zlib
28
29
 
29
 
from bzrlib import (
 
30
from .. import (
 
31
    bencode,
30
32
    branch,
31
 
    bzrdir,
32
33
    config,
 
34
    controldir,
33
35
    errors,
34
 
    graph,
 
36
    repository,
 
37
    tests,
 
38
    transport,
 
39
    treebuilder,
 
40
    )
 
41
from ..branch import Branch
 
42
from ..bzr import (
 
43
    bzrdir,
35
44
    inventory,
36
45
    inventory_delta,
37
 
    pack,
38
46
    remote,
39
 
    repository,
40
 
    tests,
41
 
    treebuilder,
42
 
    urlutils,
43
47
    versionedfile,
44
 
    )
45
 
from bzrlib.branch import Branch
46
 
from bzrlib.bzrdir import BzrDir, BzrDirFormat
47
 
from bzrlib.remote import (
 
48
    vf_search,
 
49
    )
 
50
from ..bzr.bzrdir import (
 
51
    BzrDir,
 
52
    BzrDirFormat,
 
53
    )
 
54
from ..bzr import (
 
55
    RemoteBzrProber,
 
56
    )
 
57
from ..bzr.chk_serializer import chk_bencode_serializer
 
58
from ..bzr.remote import (
48
59
    RemoteBranch,
49
60
    RemoteBranchFormat,
50
61
    RemoteBzrDir,
52
63
    RemoteRepository,
53
64
    RemoteRepositoryFormat,
54
65
    )
55
 
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
 
from bzrlib.revision import NULL_REVISION
57
 
from bzrlib.smart import medium
58
 
from bzrlib.smart.client import _SmartClient
59
 
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
60
 
from bzrlib.tests import (
61
 
    condition_isinstance,
62
 
    split_suite_by_condition,
63
 
    multiply_tests,
 
66
from ..bzr import groupcompress_repo, knitpack_repo
 
67
from ..revision import (
 
68
    NULL_REVISION,
 
69
    Revision,
 
70
    )
 
71
from ..sixish import (
 
72
    BytesIO,
 
73
    text_type,
 
74
    )
 
75
from ..bzr.smart import medium, request
 
76
from ..bzr.smart.client import _SmartClient
 
77
from ..bzr.smart.repository import (
 
78
    SmartServerRepositoryGetParentMap,
 
79
    SmartServerRepositoryGetStream_1_19,
 
80
    _stream_to_byte_stream,
 
81
    )
 
82
from . import (
64
83
    test_server,
65
84
    )
66
 
from bzrlib.transport import get_transport
67
 
from bzrlib.transport.memory import MemoryTransport
68
 
from bzrlib.transport.remote import (
 
85
from .scenarios import load_tests_apply_scenarios
 
86
from ..transport.memory import MemoryTransport
 
87
from ..transport.remote import (
69
88
    RemoteTransport,
70
89
    RemoteSSHTransport,
71
90
    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 = [
 
91
    )
 
92
 
 
93
 
 
94
load_tests = load_tests_apply_scenarios
 
95
 
 
96
 
 
97
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
 
98
 
 
99
    scenarios = [
78
100
        ('HPSS-v2',
79
 
         {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
 
101
            {'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
80
102
        ('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):
 
103
            {'transport_server': test_server.SmartTCPServer_for_testing})]
 
104
 
86
105
 
87
106
    def setUp(self):
88
107
        super(BasicRemoteObjectTests, self).setUp()
89
108
        self.transport = self.get_transport()
90
109
        # make a branch that can be opened over the smart transport
91
110
        self.local_wt = BzrDir.create_standalone_workingtree('.')
92
 
 
93
 
    def tearDown(self):
94
 
        self.transport.disconnect()
95
 
        tests.TestCaseWithTransport.tearDown(self)
 
111
        self.addCleanup(self.transport.disconnect)
96
112
 
97
113
    def test_create_remote_bzrdir(self):
98
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
114
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
115
        self.assertIsInstance(b, BzrDir)
100
116
 
101
117
    def test_open_remote_branch(self):
102
118
        # open a standalone branch in the working directory
103
 
        b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
 
119
        b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
120
        branch = b.open_branch()
105
121
        self.assertIsInstance(branch, Branch)
106
122
 
112
128
        self.local_wt.commit(message='test commit', rev_id=revid)
113
129
        self.assertTrue(repo.has_revision(revid))
114
130
 
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
131
    def test_find_correct_format(self):
123
132
        """Should open a RemoteBzrDir over a RemoteTransport"""
124
133
        fmt = BzrDirFormat.find_format(self.transport)
125
 
        self.assertTrue(RemoteBzrDirFormat
126
 
                        in BzrDirFormat._control_server_formats)
127
 
        self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
 
134
        self.assertTrue(RemoteBzrProber
 
135
                        in controldir.ControlDirFormat._server_probers)
 
136
        self.assertIsInstance(fmt, RemoteBzrDirFormat)
128
137
 
129
138
    def test_open_detected_smart_format(self):
130
139
        fmt = BzrDirFormat.find_format(self.transport)
150
159
 
151
160
    def test_remote_repo_format_supports_external_references(self):
152
161
        t = self.transport
153
 
        bd = self.make_bzrdir('unstackable', format='pack-0.92')
 
162
        bd = self.make_controldir('unstackable', format='pack-0.92')
154
163
        r = bd.create_repository()
155
164
        self.assertFalse(r._format.supports_external_lookups)
156
165
        r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
157
166
        self.assertFalse(r._format.supports_external_lookups)
158
 
        bd = self.make_bzrdir('stackable', format='1.9')
 
167
        bd = self.make_controldir('stackable', format='1.9')
159
168
        r = bd.create_repository()
160
169
        self.assertTrue(r._format.supports_external_lookups)
161
170
        r = BzrDir.open_from_transport(t.clone('stackable')).open_repository()
164
173
    def test_remote_branch_set_append_revisions_only(self):
165
174
        # Make a format 1.9 branch, which supports append_revisions_only
166
175
        branch = self.make_branch('branch', format='1.9')
167
 
        config = branch.get_config()
168
176
        branch.set_append_revisions_only(True)
 
177
        config = branch.get_config_stack()
169
178
        self.assertEqual(
170
 
            'True', config.get_user_option('append_revisions_only'))
 
179
            True, config.get('append_revisions_only'))
171
180
        branch.set_append_revisions_only(False)
 
181
        config = branch.get_config_stack()
172
182
        self.assertEqual(
173
 
            'False', config.get_user_option('append_revisions_only'))
 
183
            False, config.get('append_revisions_only'))
174
184
 
175
185
    def test_remote_branch_set_append_revisions_only_upgrade_reqd(self):
176
186
        branch = self.make_branch('branch', format='knit')
177
 
        config = branch.get_config()
178
187
        self.assertRaises(
179
188
            errors.UpgradeRequired, branch.set_append_revisions_only, True)
180
189
 
189
198
 
190
199
    def read_body_bytes(self, count=-1):
191
200
        if self._body_buffer is None:
192
 
            self._body_buffer = StringIO(self.body)
 
201
            self._body_buffer = BytesIO(self.body)
193
202
        bytes = self._body_buffer.read(count)
194
203
        if self._body_buffer.tell() == len(self._body_buffer.getvalue()):
195
204
            self._fake_client.expecting_body = False
225
234
        self.responses.append((response_type, response_args, response_body))
226
235
 
227
236
    def add_success_response(self, *args):
228
 
        self.responses.append(('success', args, None))
 
237
        self.responses.append((b'success', args, None))
229
238
 
230
239
    def add_success_response_with_body(self, body, *args):
231
 
        self.responses.append(('success', args, body))
 
240
        self.responses.append((b'success', args, body))
232
241
        if self._expected_calls is not None:
233
242
            self._expected_calls.append(None)
234
243
 
235
244
    def add_error_response(self, *args):
236
 
        self.responses.append(('error', args))
 
245
        self.responses.append((b'error', args))
237
246
 
238
247
    def add_unknown_method_response(self, verb):
239
 
        self.responses.append(('unknown', verb))
 
248
        self.responses.append((b'unknown', verb))
240
249
 
241
250
    def finished_test(self):
242
251
        if self._expected_calls:
246
255
    def _get_next_response(self):
247
256
        try:
248
257
            response_tuple = self.responses.pop(0)
249
 
        except IndexError, e:
 
258
        except IndexError as e:
250
259
            raise AssertionError("%r didn't expect any more calls"
251
260
                % (self,))
252
 
        if response_tuple[0] == 'unknown':
 
261
        if response_tuple[0] == b'unknown':
253
262
            raise errors.UnknownSmartMethod(response_tuple[1])
254
 
        elif response_tuple[0] == 'error':
 
263
        elif response_tuple[0] == b'error':
255
264
            raise errors.ErrorFromSmartServer(response_tuple[1])
256
265
        return response_tuple
257
266
 
325
334
 
326
335
    def test_unicode_path(self):
327
336
        client = FakeClient('/')
328
 
        client.add_success_response('yes',)
 
337
        client.add_success_response(b'yes',)
329
338
        transport = RemoteTransport('bzr://localhost/', _client=client)
330
 
        filename = u'/hell\u00d8'.encode('utf8')
 
339
        filename = u'/hell\u00d8'.encode('utf-8')
331
340
        result = transport.has(filename)
332
341
        self.assertEqual(
333
 
            [('call', 'has', (filename,))],
 
342
            [('call', b'has', (filename,))],
334
343
            client._calls)
335
344
        self.assertTrue(result)
336
345
 
338
347
class TestRemote(tests.TestCaseWithMemoryTransport):
339
348
 
340
349
    def get_branch_format(self):
341
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
350
        reference_bzrdir_format = controldir.format_registry.get('default')()
342
351
        return reference_bzrdir_format.get_branch_format()
343
352
 
344
353
    def get_repo_format(self):
345
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
354
        reference_bzrdir_format = controldir.format_registry.get('default')()
346
355
        return reference_bzrdir_format.repository_format
347
356
 
348
357
    def assertFinished(self, fake_client):
359
368
        a given client_base and transport_base.
360
369
        """
361
370
        client_medium = medium.SmartClientMedium(client_base)
362
 
        transport = get_transport(transport_base)
363
 
        result = client_medium.remote_path_from_transport(transport)
 
371
        t = transport.get_transport(transport_base)
 
372
        result = client_medium.remote_path_from_transport(t)
364
373
        self.assertEqual(expected, result)
365
374
 
366
375
    def test_remote_path_from_transport(self):
377
386
        a given transport_base and relpath of that transport.  (Note that
378
387
        HttpTransportBase is a subclass of SmartClientMedium)
379
388
        """
380
 
        base_transport = get_transport(transport_base)
 
389
        base_transport = transport.get_transport(transport_base)
381
390
        client_medium = base_transport.get_smart_medium()
382
391
        cloned_transport = base_transport.clone(relpath)
383
392
        result = client_medium.remote_path_from_transport(cloned_transport)
430
439
 
431
440
    def test_backwards_compat(self):
432
441
        self.setup_smart_server_with_call_log()
433
 
        a_dir = self.make_bzrdir('.')
 
442
        a_dir = self.make_controldir('.')
434
443
        self.reset_smart_call_log()
435
 
        verb = 'BzrDir.cloning_metadir'
 
444
        verb = b'BzrDir.cloning_metadir'
436
445
        self.disable_verb(verb)
437
446
        format = a_dir.cloning_metadir()
438
447
        call_count = len([call for call in self.hpss_calls if
442
451
    def test_branch_reference(self):
443
452
        transport = self.get_transport('quack')
444
453
        referenced = self.make_branch('referenced')
445
 
        expected = referenced.bzrdir.cloning_metadir()
 
454
        expected = referenced.controldir.cloning_metadir()
446
455
        client = FakeClient(transport.base)
447
456
        client.add_expected_call(
448
 
            'BzrDir.cloning_metadir', ('quack/', 'False'),
449
 
            'error', ('BranchReference',)),
 
457
            b'BzrDir.cloning_metadir', (b'quack/', b'False'),
 
458
            b'error', (b'BranchReference',)),
450
459
        client.add_expected_call(
451
 
            'BzrDir.open_branchV3', ('quack/',),
452
 
            'success', ('ref', self.get_url('referenced'))),
453
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
460
            b'BzrDir.open_branchV3', (b'quack/',),
 
461
            b'success', (b'ref', self.get_url('referenced'))),
 
462
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
454
463
            _client=client)
455
 
        result = a_bzrdir.cloning_metadir()
 
464
        result = a_controldir.cloning_metadir()
456
465
        # We should have got a control dir matching the referenced branch.
457
466
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
458
467
        self.assertEqual(expected._repository_format, result._repository_format)
462
471
    def test_current_server(self):
463
472
        transport = self.get_transport('.')
464
473
        transport = transport.clone('quack')
465
 
        self.make_bzrdir('quack')
 
474
        self.make_controldir('quack')
466
475
        client = FakeClient(transport.base)
467
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
476
        reference_bzrdir_format = controldir.format_registry.get('default')()
468
477
        control_name = reference_bzrdir_format.network_name()
469
478
        client.add_expected_call(
470
 
            'BzrDir.cloning_metadir', ('quack/', 'False'),
471
 
            'success', (control_name, '', ('branch', ''))),
472
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
479
            b'BzrDir.cloning_metadir', (b'quack/', b'False'),
 
480
            b'success', (control_name, b'', (b'branch', b''))),
 
481
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
473
482
            _client=client)
474
 
        result = a_bzrdir.cloning_metadir()
 
483
        result = a_controldir.cloning_metadir()
475
484
        # We should have got a reference control dir with default branch and
476
485
        # repository formats.
477
486
        # This pokes a little, just to be sure.
480
489
        self.assertEqual(None, result._branch_format)
481
490
        self.assertFinished(client)
482
491
 
 
492
    def test_unknown(self):
 
493
        transport = self.get_transport('quack')
 
494
        referenced = self.make_branch('referenced')
 
495
        expected = referenced.controldir.cloning_metadir()
 
496
        client = FakeClient(transport.base)
 
497
        client.add_expected_call(
 
498
            b'BzrDir.cloning_metadir', (b'quack/', b'False'),
 
499
            b'success', (b'unknown', b'unknown', (b'branch', b''))),
 
500
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
501
            _client=client)
 
502
        self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
 
503
 
 
504
 
 
505
class TestBzrDirCheckoutMetaDir(TestRemote):
 
506
 
 
507
    def test__get_checkout_format(self):
 
508
        transport = MemoryTransport()
 
509
        client = FakeClient(transport.base)
 
510
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
511
        control_name = reference_bzrdir_format.network_name()
 
512
        client.add_expected_call(
 
513
            b'BzrDir.checkout_metadir', (b'quack/', ),
 
514
            b'success', (control_name, b'', b''))
 
515
        transport.mkdir('quack')
 
516
        transport = transport.clone('quack')
 
517
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
518
            _client=client)
 
519
        result = a_controldir.checkout_metadir()
 
520
        # We should have got a reference control dir with default branch and
 
521
        # repository formats.
 
522
        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
 
523
        self.assertEqual(None, result._repository_format)
 
524
        self.assertEqual(None, result._branch_format)
 
525
        self.assertFinished(client)
 
526
 
 
527
    def test_unknown_format(self):
 
528
        transport = MemoryTransport()
 
529
        client = FakeClient(transport.base)
 
530
        client.add_expected_call(
 
531
            b'BzrDir.checkout_metadir', (b'quack/',),
 
532
            b'success', (b'dontknow', b'', b''))
 
533
        transport.mkdir('quack')
 
534
        transport = transport.clone('quack')
 
535
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
536
            _client=client)
 
537
        self.assertRaises(errors.UnknownFormatError,
 
538
            a_controldir.checkout_metadir)
 
539
        self.assertFinished(client)
 
540
 
 
541
 
 
542
class TestBzrDirGetBranches(TestRemote):
 
543
 
 
544
    def test_get_branches(self):
 
545
        transport = MemoryTransport()
 
546
        client = FakeClient(transport.base)
 
547
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
548
        branch_name = reference_bzrdir_format.get_branch_format().network_name()
 
549
        client.add_success_response_with_body(
 
550
            bencode.bencode({
 
551
                b"foo": (b"branch", branch_name),
 
552
                b"": (b"branch", branch_name)}), b"success")
 
553
        client.add_success_response(
 
554
            b'ok', b'', b'no', b'no', b'no',
 
555
                reference_bzrdir_format.repository_format.network_name())
 
556
        client.add_error_response(b'NotStacked')
 
557
        client.add_success_response(
 
558
            b'ok', b'', b'no', b'no', b'no',
 
559
                reference_bzrdir_format.repository_format.network_name())
 
560
        client.add_error_response(b'NotStacked')
 
561
        transport.mkdir('quack')
 
562
        transport = transport.clone('quack')
 
563
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
564
            _client=client)
 
565
        result = a_controldir.get_branches()
 
566
        self.assertEqual({b"", b"foo"}, set(result.keys()))
 
567
        self.assertEqual(
 
568
            [('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
 
569
             ('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
 
570
             ('call', b'Branch.get_stacked_on_url', (b'quack/', )),
 
571
             ('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
 
572
             ('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
 
573
            client._calls)
 
574
 
 
575
 
 
576
class TestBzrDirDestroyBranch(TestRemote):
 
577
 
 
578
    def test_destroy_default(self):
 
579
        transport = self.get_transport('quack')
 
580
        referenced = self.make_branch('referenced')
 
581
        client = FakeClient(transport.base)
 
582
        client.add_expected_call(
 
583
            b'BzrDir.destroy_branch', (b'quack/', ),
 
584
            b'success', (b'ok',)),
 
585
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
586
            _client=client)
 
587
        a_controldir.destroy_branch()
 
588
        self.assertFinished(client)
 
589
 
 
590
 
 
591
class TestBzrDirHasWorkingTree(TestRemote):
 
592
 
 
593
    def test_has_workingtree(self):
 
594
        transport = self.get_transport('quack')
 
595
        client = FakeClient(transport.base)
 
596
        client.add_expected_call(
 
597
            b'BzrDir.has_workingtree', (b'quack/',),
 
598
            b'success', (b'yes',)),
 
599
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
600
            _client=client)
 
601
        self.assertTrue(a_controldir.has_workingtree())
 
602
        self.assertFinished(client)
 
603
 
 
604
    def test_no_workingtree(self):
 
605
        transport = self.get_transport('quack')
 
606
        client = FakeClient(transport.base)
 
607
        client.add_expected_call(
 
608
            b'BzrDir.has_workingtree', (b'quack/',),
 
609
            b'success', (b'no',)),
 
610
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
611
            _client=client)
 
612
        self.assertFalse(a_controldir.has_workingtree())
 
613
        self.assertFinished(client)
 
614
 
 
615
 
 
616
class TestBzrDirDestroyRepository(TestRemote):
 
617
 
 
618
    def test_destroy_repository(self):
 
619
        transport = self.get_transport('quack')
 
620
        client = FakeClient(transport.base)
 
621
        client.add_expected_call(
 
622
            b'BzrDir.destroy_repository', (b'quack/',),
 
623
            b'success', (b'ok',)),
 
624
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
625
            _client=client)
 
626
        a_controldir.destroy_repository()
 
627
        self.assertFinished(client)
 
628
 
483
629
 
484
630
class TestBzrDirOpen(TestRemote):
485
631
 
493
639
    def test_absent(self):
494
640
        client, transport = self.make_fake_client_and_transport()
495
641
        client.add_expected_call(
496
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
 
642
            b'BzrDir.open_2.1', (b'quack/',), b'success', (b'no',))
497
643
        self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
 
                remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
 
644
                RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
645
        self.assertFinished(client)
500
646
 
501
647
    def test_present_without_workingtree(self):
502
648
        client, transport = self.make_fake_client_and_transport()
503
649
        client.add_expected_call(
504
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
650
            b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'no'))
 
651
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
652
            _client=client, _force_probe=True)
507
653
        self.assertIsInstance(bd, RemoteBzrDir)
508
654
        self.assertFalse(bd.has_workingtree())
512
658
    def test_present_with_workingtree(self):
513
659
        client, transport = self.make_fake_client_and_transport()
514
660
        client.add_expected_call(
515
 
            'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'yes'))
516
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
661
            b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'yes'))
 
662
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
663
            _client=client, _force_probe=True)
518
664
        self.assertIsInstance(bd, RemoteBzrDir)
519
665
        self.assertTrue(bd.has_workingtree())
523
669
    def test_backwards_compat(self):
524
670
        client, transport = self.make_fake_client_and_transport()
525
671
        client.add_expected_call(
526
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
672
            b'BzrDir.open_2.1', (b'quack/',), b'unknown', (b'BzrDir.open_2.1',))
527
673
        client.add_expected_call(
528
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
529
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
674
            b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
 
675
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
676
            _client=client, _force_probe=True)
531
677
        self.assertIsInstance(bd, RemoteBzrDir)
532
678
        self.assertFinished(client)
545
691
            client._check_call(method, args)
546
692
        client._check_call = check_call
547
693
        client.add_expected_call(
548
 
            'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
 
694
            b'BzrDir.open_2.1', (b'quack/',), b'unknown', (b'BzrDir.open_2.1',))
549
695
        client.add_expected_call(
550
 
            'BzrDir.open', ('quack/',), 'success', ('yes',))
551
 
        bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
696
            b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
 
697
        bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
552
698
            _client=client, _force_probe=True)
553
699
        self.assertIsInstance(bd, RemoteBzrDir)
554
700
        self.assertFinished(client)
561
707
        self.make_branch('.')
562
708
        a_dir = BzrDir.open(self.get_url('.'))
563
709
        self.reset_smart_call_log()
564
 
        verb = 'BzrDir.open_branchV3'
 
710
        verb = b'BzrDir.open_branchV3'
565
711
        self.disable_verb(verb)
566
712
        format = a_dir.open_branch()
567
713
        call_count = len([call for call in self.hpss_calls if
577
723
        transport = transport.clone('quack')
578
724
        client = FakeClient(transport.base)
579
725
        client.add_expected_call(
580
 
            'BzrDir.open_branchV3', ('quack/',),
581
 
            'success', ('branch', branch_network_name))
582
 
        client.add_expected_call(
583
 
            'BzrDir.find_repositoryV3', ('quack/',),
584
 
            'success', ('ok', '', 'no', 'no', 'no', network_name))
585
 
        client.add_expected_call(
586
 
            'Branch.get_stacked_on_url', ('quack/',),
587
 
            'error', ('NotStacked',))
588
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
726
            b'BzrDir.open_branchV3', (b'quack/',),
 
727
            b'success', (b'branch', branch_network_name))
 
728
        client.add_expected_call(
 
729
            b'BzrDir.find_repositoryV3', (b'quack/',),
 
730
            b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
 
731
        client.add_expected_call(
 
732
            b'Branch.get_stacked_on_url', (b'quack/',),
 
733
            b'error', (b'NotStacked',))
 
734
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
735
            _client=client)
590
736
        result = bzrdir.open_branch()
591
737
        self.assertIsInstance(result, RemoteBranch)
592
 
        self.assertEqual(bzrdir, result.bzrdir)
 
738
        self.assertEqual(bzrdir, result.controldir)
593
739
        self.assertFinished(client)
594
740
 
595
741
    def test_branch_missing(self):
597
743
        transport.mkdir('quack')
598
744
        transport = transport.clone('quack')
599
745
        client = FakeClient(transport.base)
600
 
        client.add_error_response('nobranch')
601
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
746
        client.add_error_response(b'nobranch')
 
747
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
748
            _client=client)
603
749
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
604
750
        self.assertEqual(
605
 
            [('call', 'BzrDir.open_branchV3', ('quack/',))],
 
751
            [('call', b'BzrDir.open_branchV3', (b'quack/',))],
606
752
            client._calls)
607
753
 
608
754
    def test__get_tree_branch(self):
609
755
        # _get_tree_branch is a form of open_branch, but it should only ask for
610
756
        # branch opening, not any other network requests.
611
757
        calls = []
612
 
        def open_branch():
 
758
        def open_branch(name=None, possible_transports=None):
613
759
            calls.append("Called")
614
760
            return "a-branch"
615
761
        transport = MemoryTransport()
616
762
        # no requests on the network - catches other api calls being made.
617
763
        client = FakeClient(transport.base)
618
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
764
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
765
            _client=client)
620
766
        # patch the open_branch call to record that it was called.
621
767
        bzrdir.open_branch = open_branch
632
778
        network_name = reference_format.network_name()
633
779
        branch_network_name = self.get_branch_format().network_name()
634
780
        client.add_expected_call(
635
 
            'BzrDir.open_branchV3', ('~hello/',),
636
 
            'success', ('branch', branch_network_name))
637
 
        client.add_expected_call(
638
 
            'BzrDir.find_repositoryV3', ('~hello/',),
639
 
            'success', ('ok', '', 'no', 'no', 'no', network_name))
640
 
        client.add_expected_call(
641
 
            'Branch.get_stacked_on_url', ('~hello/',),
642
 
            'error', ('NotStacked',))
643
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
781
            b'BzrDir.open_branchV3', (b'~hello/',),
 
782
            b'success', (b'branch', branch_network_name))
 
783
        client.add_expected_call(
 
784
            b'BzrDir.find_repositoryV3', (b'~hello/',),
 
785
            b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
 
786
        client.add_expected_call(
 
787
            b'Branch.get_stacked_on_url', (b'~hello/',),
 
788
            b'error', (b'NotStacked',))
 
789
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
644
790
            _client=client)
645
791
        result = bzrdir.open_branch()
646
792
        self.assertFinished(client)
647
793
 
648
 
    def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
 
794
    def check_open_repository(self, rich_root, subtrees, external_lookup=b'no'):
649
795
        reference_format = self.get_repo_format()
650
796
        network_name = reference_format.network_name()
651
797
        transport = MemoryTransport()
652
798
        transport.mkdir('quack')
653
799
        transport = transport.clone('quack')
654
800
        if rich_root:
655
 
            rich_response = 'yes'
 
801
            rich_response = b'yes'
656
802
        else:
657
 
            rich_response = 'no'
 
803
            rich_response = b'no'
658
804
        if subtrees:
659
 
            subtree_response = 'yes'
 
805
            subtree_response = b'yes'
660
806
        else:
661
 
            subtree_response = 'no'
 
807
            subtree_response = b'no'
662
808
        client = FakeClient(transport.base)
663
809
        client.add_success_response(
664
 
            'ok', '', rich_response, subtree_response, external_lookup,
 
810
            b'ok', b'', rich_response, subtree_response, external_lookup,
665
811
            network_name)
666
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
812
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
667
813
            _client=client)
668
814
        result = bzrdir.open_repository()
669
815
        self.assertEqual(
670
 
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
 
816
            [('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
671
817
            client._calls)
672
818
        self.assertIsInstance(result, RemoteRepository)
673
 
        self.assertEqual(bzrdir, result.bzrdir)
 
819
        self.assertEqual(bzrdir, result.controldir)
674
820
        self.assertEqual(rich_root, result._format.rich_root_data)
675
821
        self.assertEqual(subtrees, result._format.supports_tree_reference)
676
822
 
679
825
        self.check_open_repository(False, True)
680
826
        self.check_open_repository(True, False)
681
827
        self.check_open_repository(False, False)
682
 
        self.check_open_repository(False, False, 'yes')
 
828
        self.check_open_repository(False, False, b'yes')
683
829
 
684
830
    def test_old_server(self):
685
831
        """RemoteBzrDirFormat should fail to probe if the server version is too
686
832
        old.
687
833
        """
688
834
        self.assertRaises(errors.NotBranchError,
689
 
            RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
835
            RemoteBzrProber.probe_transport, OldServerTransport())
690
836
 
691
837
 
692
838
class TestBzrDirCreateBranch(TestRemote):
695
841
        self.setup_smart_server_with_call_log()
696
842
        repo = self.make_repository('.')
697
843
        self.reset_smart_call_log()
698
 
        self.disable_verb('BzrDir.create_branch')
699
 
        branch = repo.bzrdir.create_branch()
 
844
        self.disable_verb(b'BzrDir.create_branch')
 
845
        branch = repo.controldir.create_branch()
700
846
        create_branch_call_count = len([call for call in self.hpss_calls if
701
 
            call.call.method == 'BzrDir.create_branch'])
 
847
            call.call.method == b'BzrDir.create_branch'])
702
848
        self.assertEqual(1, create_branch_call_count)
703
849
 
704
850
    def test_current_server(self):
706
852
        transport = transport.clone('quack')
707
853
        self.make_repository('quack')
708
854
        client = FakeClient(transport.base)
709
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
710
 
        reference_format = reference_bzrdir_format.get_branch_format()
711
 
        network_name = reference_format.network_name()
712
 
        reference_repo_fmt = reference_bzrdir_format.repository_format
713
 
        reference_repo_name = reference_repo_fmt.network_name()
714
 
        client.add_expected_call(
715
 
            'BzrDir.create_branch', ('quack/', network_name),
716
 
            'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
 
            reference_repo_name))
718
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
719
 
            _client=client)
720
 
        branch = a_bzrdir.create_branch()
 
855
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
856
        reference_format = reference_bzrdir_format.get_branch_format()
 
857
        network_name = reference_format.network_name()
 
858
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
859
        reference_repo_name = reference_repo_fmt.network_name()
 
860
        client.add_expected_call(
 
861
            b'BzrDir.create_branch', (b'quack/', network_name),
 
862
            b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
 
863
            reference_repo_name))
 
864
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
865
            _client=client)
 
866
        branch = a_controldir.create_branch()
 
867
        # We should have got a remote branch
 
868
        self.assertIsInstance(branch, remote.RemoteBranch)
 
869
        # its format should have the settings from the response
 
870
        format = branch._format
 
871
        self.assertEqual(network_name, format.network_name())
 
872
 
 
873
    def test_already_open_repo_and_reused_medium(self):
 
874
        """Bug 726584: create_branch(..., repository=repo) should work
 
875
        regardless of what the smart medium's base URL is.
 
876
        """
 
877
        self.transport_server = test_server.SmartTCPServer_for_testing
 
878
        transport = self.get_transport('.')
 
879
        repo = self.make_repository('quack')
 
880
        # Client's medium rooted a transport root (not at the bzrdir)
 
881
        client = FakeClient(transport.base)
 
882
        transport = transport.clone('quack')
 
883
        reference_bzrdir_format = controldir.format_registry.get('default')()
 
884
        reference_format = reference_bzrdir_format.get_branch_format()
 
885
        network_name = reference_format.network_name()
 
886
        reference_repo_fmt = reference_bzrdir_format.repository_format
 
887
        reference_repo_name = reference_repo_fmt.network_name()
 
888
        client.add_expected_call(
 
889
            b'BzrDir.create_branch', (b'extra/quack/', network_name),
 
890
            b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
 
891
            reference_repo_name))
 
892
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
 
893
            _client=client)
 
894
        branch = a_controldir.create_branch(repository=repo)
721
895
        # We should have got a remote branch
722
896
        self.assertIsInstance(branch, remote.RemoteBranch)
723
897
        # its format should have the settings from the response
729
903
 
730
904
    def test_backwards_compat(self):
731
905
        self.setup_smart_server_with_call_log()
732
 
        bzrdir = self.make_bzrdir('.')
 
906
        bzrdir = self.make_controldir('.')
733
907
        self.reset_smart_call_log()
734
 
        self.disable_verb('BzrDir.create_repository')
 
908
        self.disable_verb(b'BzrDir.create_repository')
735
909
        repo = bzrdir.create_repository()
736
910
        create_repo_call_count = len([call for call in self.hpss_calls if
737
 
            call.call.method == 'BzrDir.create_repository'])
 
911
            call.call.method == b'BzrDir.create_repository'])
738
912
        self.assertEqual(1, create_repo_call_count)
739
913
 
740
914
    def test_current_server(self):
741
915
        transport = self.get_transport('.')
742
916
        transport = transport.clone('quack')
743
 
        self.make_bzrdir('quack')
 
917
        self.make_controldir('quack')
744
918
        client = FakeClient(transport.base)
745
 
        reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
919
        reference_bzrdir_format = controldir.format_registry.get('default')()
746
920
        reference_format = reference_bzrdir_format.repository_format
747
921
        network_name = reference_format.network_name()
748
922
        client.add_expected_call(
749
 
            'BzrDir.create_repository', ('quack/',
750
 
                'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
751
 
                'False'),
752
 
            'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
 
        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
923
            b'BzrDir.create_repository', (b'quack/',
 
924
                b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
 
925
                b'False'),
 
926
            b'success', (b'ok', b'yes', b'yes', b'yes', network_name))
 
927
        a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
928
            _client=client)
755
 
        repo = a_bzrdir.create_repository()
 
929
        repo = a_controldir.create_repository()
756
930
        # We should have got a remote repository
757
931
        self.assertIsInstance(repo, remote.RemoteRepository)
758
932
        # its format should have the settings from the response
772
946
        server_url = 'bzr://example.com/'
773
947
        self.permit_url(server_url)
774
948
        client = FakeClient(server_url)
775
 
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
776
 
        client.add_unknown_method_response('BzrDir.find_repositoryV2')
777
 
        client.add_success_response('ok', '', 'no', 'no')
 
949
        client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
 
950
        client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
 
951
        client.add_success_response(b'ok', b'', b'no', b'no')
778
952
        # A real repository instance will be created to determine the network
779
953
        # name.
780
954
        client.add_success_response_with_body(
781
 
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
955
            b"Bazaar-NG meta directory, format 1\n", b'ok')
 
956
        client.add_success_response(b'stat', b'0', b'65535')
782
957
        client.add_success_response_with_body(
783
 
            reference_format.get_format_string(), 'ok')
 
958
            reference_format.get_format_string(), b'ok')
784
959
        # PackRepository wants to do a stat
785
 
        client.add_success_response('stat', '0', '65535')
 
960
        client.add_success_response(b'stat', b'0', b'65535')
786
961
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
787
962
            _client=client)
788
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
963
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
789
964
            _client=client)
790
965
        repo = bzrdir.open_repository()
791
966
        self.assertEqual(
792
 
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
793
 
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
 
             ('call', 'BzrDir.find_repository', ('quack/',)),
795
 
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
796
 
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
 
             ('call', 'stat', ('/quack/.bzr/repository',)),
 
967
            [('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
 
968
             ('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
 
969
             ('call', b'BzrDir.find_repository', (b'quack/',)),
 
970
             ('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
 
971
             ('call', b'stat', (b'/quack/.bzr',)),
 
972
             ('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
 
973
             ('call', b'stat', (b'/quack/.bzr/repository',)),
798
974
             ],
799
975
            client._calls)
800
976
        self.assertEqual(network_name, repo._format.network_name())
806
982
        server_url = 'bzr://example.com/'
807
983
        self.permit_url(server_url)
808
984
        client = FakeClient(server_url)
809
 
        client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
 
        client.add_success_response('ok', '', 'no', 'no', 'no')
 
985
        client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
 
986
        client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
987
        # A real repository instance will be created to determine the network
812
988
        # name.
813
989
        client.add_success_response_with_body(
814
 
            "Bazaar-NG meta directory, format 1\n", 'ok')
 
990
            b"Bazaar-NG meta directory, format 1\n", b'ok')
 
991
        client.add_success_response(b'stat', b'0', b'65535')
815
992
        client.add_success_response_with_body(
816
 
            reference_format.get_format_string(), 'ok')
 
993
            reference_format.get_format_string(), b'ok')
817
994
        # PackRepository wants to do a stat
818
 
        client.add_success_response('stat', '0', '65535')
 
995
        client.add_success_response(b'stat', b'0', b'65535')
819
996
        remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
820
997
            _client=client)
821
 
        bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
 
998
        bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
822
999
            _client=client)
823
1000
        repo = bzrdir.open_repository()
824
1001
        self.assertEqual(
825
 
            [('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
 
             ('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
 
             ('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
828
 
             ('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
 
             ('call', 'stat', ('/quack/.bzr/repository',)),
 
1002
            [('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
 
1003
             ('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
 
1004
             ('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
 
1005
             ('call', b'stat', (b'/quack/.bzr',)),
 
1006
             ('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
 
1007
             ('call', b'stat', (b'/quack/.bzr/repository',)),
830
1008
             ],
831
1009
            client._calls)
832
1010
        self.assertEqual(network_name, repo._format.network_name())
838
1016
        transport.mkdir('quack')
839
1017
        transport = transport.clone('quack')
840
1018
        client = FakeClient(transport.base)
841
 
        client.add_success_response('ok', '', 'no', 'no', 'no', network_name)
842
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1019
        client.add_success_response(b'ok', b'', b'no', b'no', b'no', network_name)
 
1020
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
843
1021
            _client=client)
844
1022
        repo = bzrdir.open_repository()
845
1023
        self.assertEqual(
846
 
            [('call', 'BzrDir.find_repositoryV3', ('quack/',))],
 
1024
            [('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
847
1025
            client._calls)
848
1026
        self.assertEqual(network_name, repo._format.network_name())
849
1027
 
852
1030
 
853
1031
    def test_success(self):
854
1032
        """Simple test for typical successful call."""
855
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1033
        fmt = RemoteBzrDirFormat()
856
1034
        default_format_name = BzrDirFormat.get_default_format().network_name()
857
1035
        transport = self.get_transport()
858
1036
        client = FakeClient(transport.base)
859
1037
        client.add_expected_call(
860
 
            'BzrDirFormat.initialize_ex_1.16',
861
 
                (default_format_name, 'path', 'False', 'False', 'False', '',
862
 
                 '', '', '', 'False'),
863
 
            'success',
864
 
                ('.', 'no', 'no', 'yes', 'repo fmt', 'repo bzrdir fmt',
865
 
                 'bzrdir fmt', 'False', '', '', 'repo lock token'))
 
1038
            b'BzrDirFormat.initialize_ex_1.16',
 
1039
                (default_format_name, b'path', b'False', b'False', b'False', b'',
 
1040
                 b'', b'', b'', b'False'),
 
1041
            b'success',
 
1042
                (b'.', b'no', b'no', b'yes', b'repo fmt', b'repo bzrdir fmt',
 
1043
                 b'bzrdir fmt', b'False', b'', b'', b'repo lock token'))
866
1044
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
867
1045
        # it's currently hard to test that without supplying a real remote
868
1046
        # transport connected to a real server.
874
1052
        """Error responses are translated, e.g. 'PermissionDenied' raises the
875
1053
        corresponding error from the client.
876
1054
        """
877
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1055
        fmt = RemoteBzrDirFormat()
878
1056
        default_format_name = BzrDirFormat.get_default_format().network_name()
879
1057
        transport = self.get_transport()
880
1058
        client = FakeClient(transport.base)
881
1059
        client.add_expected_call(
882
 
            'BzrDirFormat.initialize_ex_1.16',
883
 
                (default_format_name, 'path', 'False', 'False', 'False', '',
884
 
                 '', '', '', 'False'),
885
 
            'error',
886
 
                ('PermissionDenied', 'path', 'extra info'))
 
1060
            b'BzrDirFormat.initialize_ex_1.16',
 
1061
                (default_format_name, b'path', b'False', b'False', b'False', b'',
 
1062
                 b'', b'', b'', b'False'),
 
1063
            b'error',
 
1064
                (b'PermissionDenied', b'path', b'extra info'))
887
1065
        # XXX: It would be better to call fmt.initialize_on_transport_ex, but
888
1066
        # it's currently hard to test that without supplying a real remote
889
1067
        # transport connected to a real server.
898
1076
        """Integration test for error translation."""
899
1077
        transport = self.make_smart_server('foo')
900
1078
        transport = transport.clone('no-such-path')
901
 
        fmt = bzrdir.RemoteBzrDirFormat()
 
1079
        fmt = RemoteBzrDirFormat()
902
1080
        err = self.assertRaises(errors.NoSuchFile,
903
1081
            fmt.initialize_on_transport_ex, transport, create_prefix=False)
904
1082
 
909
1087
    """
910
1088
 
911
1089
    def get_request(self):
912
 
        input_file = StringIO('ok\x011\n')
913
 
        output_file = StringIO()
 
1090
        input_file = BytesIO(b'ok\x011\n')
 
1091
        output_file = BytesIO()
914
1092
        client_medium = medium.SmartSimplePipesClientMedium(
915
1093
            input_file, output_file)
916
1094
        return medium.SmartClientStreamMediumRequest(client_medium)
935
1113
 
936
1114
    def make_remote_bzrdir(self, transport, client):
937
1115
        """Make a RemotebzrDir using 'client' as the _client."""
938
 
        return RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1116
        return RemoteBzrDir(transport, RemoteBzrDirFormat(),
939
1117
            _client=client)
940
1118
 
941
1119
 
945
1123
        """Trick a RemoteBranch into thinking it is locked."""
946
1124
        branch._lock_mode = 'w'
947
1125
        branch._lock_count = 2
948
 
        branch._lock_token = 'branch token'
949
 
        branch._repo_lock_token = 'repo token'
 
1126
        branch._lock_token = b'branch token'
 
1127
        branch._repo_lock_token = b'repo token'
950
1128
        branch.repository._lock_mode = 'w'
951
1129
        branch.repository._lock_count = 2
952
 
        branch.repository._lock_token = 'repo token'
 
1130
        branch.repository._lock_token = b'repo token'
953
1131
 
954
1132
    def make_remote_branch(self, transport, client):
955
1133
        """Make a RemoteBranch using 'client' as its _SmartClient.
967
1145
        return RemoteBranch(bzrdir, repo, _client=client, format=format)
968
1146
 
969
1147
 
 
1148
class TestBranchBreakLock(RemoteBranchTestCase):
 
1149
 
 
1150
    def test_break_lock(self):
 
1151
        transport_path = 'quack'
 
1152
        transport = MemoryTransport()
 
1153
        client = FakeClient(transport.base)
 
1154
        client.add_expected_call(
 
1155
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1156
            b'error', (b'NotStacked',))
 
1157
        client.add_expected_call(
 
1158
            b'Branch.break_lock', (b'quack/',),
 
1159
            b'success', (b'ok',))
 
1160
        transport.mkdir('quack')
 
1161
        transport = transport.clone('quack')
 
1162
        branch = self.make_remote_branch(transport, client)
 
1163
        branch.break_lock()
 
1164
        self.assertFinished(client)
 
1165
 
 
1166
 
 
1167
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
 
1168
 
 
1169
    def test_get_physical_lock_status_yes(self):
 
1170
        transport = MemoryTransport()
 
1171
        client = FakeClient(transport.base)
 
1172
        client.add_expected_call(
 
1173
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1174
            b'error', (b'NotStacked',))
 
1175
        client.add_expected_call(
 
1176
            b'Branch.get_physical_lock_status', (b'quack/',),
 
1177
            b'success', (b'yes',))
 
1178
        transport.mkdir('quack')
 
1179
        transport = transport.clone('quack')
 
1180
        branch = self.make_remote_branch(transport, client)
 
1181
        result = branch.get_physical_lock_status()
 
1182
        self.assertFinished(client)
 
1183
        self.assertEqual(True, result)
 
1184
 
 
1185
    def test_get_physical_lock_status_no(self):
 
1186
        transport = MemoryTransport()
 
1187
        client = FakeClient(transport.base)
 
1188
        client.add_expected_call(
 
1189
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1190
            b'error', (b'NotStacked',))
 
1191
        client.add_expected_call(
 
1192
            b'Branch.get_physical_lock_status', (b'quack/',),
 
1193
            b'success', (b'no',))
 
1194
        transport.mkdir('quack')
 
1195
        transport = transport.clone('quack')
 
1196
        branch = self.make_remote_branch(transport, client)
 
1197
        result = branch.get_physical_lock_status()
 
1198
        self.assertFinished(client)
 
1199
        self.assertEqual(False, result)
 
1200
 
 
1201
 
970
1202
class TestBranchGetParent(RemoteBranchTestCase):
971
1203
 
972
1204
    def test_no_parent(self):
974
1206
        transport = MemoryTransport()
975
1207
        client = FakeClient(transport.base)
976
1208
        client.add_expected_call(
977
 
            'Branch.get_stacked_on_url', ('quack/',),
978
 
            'error', ('NotStacked',))
 
1209
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1210
            b'error', (b'NotStacked',))
979
1211
        client.add_expected_call(
980
 
            'Branch.get_parent', ('quack/',),
981
 
            'success', ('',))
 
1212
            b'Branch.get_parent', (b'quack/',),
 
1213
            b'success', (b'',))
982
1214
        transport.mkdir('quack')
983
1215
        transport = transport.clone('quack')
984
1216
        branch = self.make_remote_branch(transport, client)
990
1222
        transport = MemoryTransport()
991
1223
        client = FakeClient(transport.base)
992
1224
        client.add_expected_call(
993
 
            'Branch.get_stacked_on_url', ('kwaak/',),
994
 
            'error', ('NotStacked',))
 
1225
            b'Branch.get_stacked_on_url', (b'kwaak/',),
 
1226
            b'error', (b'NotStacked',))
995
1227
        client.add_expected_call(
996
 
            'Branch.get_parent', ('kwaak/',),
997
 
            'success', ('../foo/',))
 
1228
            b'Branch.get_parent', (b'kwaak/',),
 
1229
            b'success', (b'../foo/',))
998
1230
        transport.mkdir('kwaak')
999
1231
        transport = transport.clone('kwaak')
1000
1232
        branch = self.make_remote_branch(transport, client)
1005
1237
        transport = MemoryTransport()
1006
1238
        client = FakeClient(transport.base)
1007
1239
        client.add_expected_call(
1008
 
            'Branch.get_stacked_on_url', ('kwaak/',),
1009
 
            'error', ('NotStacked',))
 
1240
            b'Branch.get_stacked_on_url', (b'kwaak/',),
 
1241
            b'error', (b'NotStacked',))
1010
1242
        client.add_expected_call(
1011
 
            'Branch.get_parent', ('kwaak/',),
1012
 
            'success', ('http://foo/',))
 
1243
            b'Branch.get_parent', (b'kwaak/',),
 
1244
            b'success', (b'http://foo/',))
1013
1245
        transport.mkdir('kwaak')
1014
1246
        transport = transport.clone('kwaak')
1015
1247
        branch = self.make_remote_branch(transport, client)
1025
1257
        transport = MemoryTransport()
1026
1258
        client = FakeClient(transport.base)
1027
1259
        client.add_expected_call(
1028
 
            'Branch.get_stacked_on_url', ('quack/',),
1029
 
            'error', ('NotStacked',))
 
1260
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1261
            b'error', (b'NotStacked',))
1030
1262
        client.add_expected_call(
1031
 
            'Branch.set_parent_location', ('quack/', 'b', 'r', ''),
1032
 
            'success', ())
 
1263
            b'Branch.set_parent_location', (b'quack/', b'b', b'r', b''),
 
1264
            b'success', ())
1033
1265
        transport.mkdir('quack')
1034
1266
        transport = transport.clone('quack')
1035
1267
        branch = self.make_remote_branch(transport, client)
1036
 
        branch._lock_token = 'b'
1037
 
        branch._repo_lock_token = 'r'
 
1268
        branch._lock_token = b'b'
 
1269
        branch._repo_lock_token = b'r'
1038
1270
        branch._set_parent_location(None)
1039
1271
        self.assertFinished(client)
1040
1272
 
1042
1274
        transport = MemoryTransport()
1043
1275
        client = FakeClient(transport.base)
1044
1276
        client.add_expected_call(
1045
 
            'Branch.get_stacked_on_url', ('kwaak/',),
1046
 
            'error', ('NotStacked',))
 
1277
            b'Branch.get_stacked_on_url', (b'kwaak/',),
 
1278
            b'error', (b'NotStacked',))
1047
1279
        client.add_expected_call(
1048
 
            'Branch.set_parent_location', ('kwaak/', 'b', 'r', 'foo'),
1049
 
            'success', ())
 
1280
            b'Branch.set_parent_location', (b'kwaak/', b'b', b'r', b'foo'),
 
1281
            b'success', ())
1050
1282
        transport.mkdir('kwaak')
1051
1283
        transport = transport.clone('kwaak')
1052
1284
        branch = self.make_remote_branch(transport, client)
1053
 
        branch._lock_token = 'b'
1054
 
        branch._repo_lock_token = 'r'
 
1285
        branch._lock_token = b'b'
 
1286
        branch._repo_lock_token = b'r'
1055
1287
        branch._set_parent_location('foo')
1056
1288
        self.assertFinished(client)
1057
1289
 
1059
1291
        self.setup_smart_server_with_call_log()
1060
1292
        branch = self.make_branch('.')
1061
1293
        self.reset_smart_call_log()
1062
 
        verb = 'Branch.set_parent_location'
 
1294
        verb = b'Branch.set_parent_location'
1063
1295
        self.disable_verb(verb)
1064
1296
        branch.set_parent('http://foo/')
1065
 
        self.assertLength(12, self.hpss_calls)
 
1297
        self.assertLength(14, self.hpss_calls)
1066
1298
 
1067
1299
 
1068
1300
class TestBranchGetTagsBytes(RemoteBranchTestCase):
1071
1303
        self.setup_smart_server_with_call_log()
1072
1304
        branch = self.make_branch('.')
1073
1305
        self.reset_smart_call_log()
1074
 
        verb = 'Branch.get_tags_bytes'
 
1306
        verb = b'Branch.get_tags_bytes'
1075
1307
        self.disable_verb(verb)
1076
1308
        branch.tags.get_tag_dict()
1077
1309
        call_count = len([call for call in self.hpss_calls if
1082
1314
        transport = MemoryTransport()
1083
1315
        client = FakeClient(transport.base)
1084
1316
        client.add_expected_call(
1085
 
            'Branch.get_stacked_on_url', ('quack/',),
1086
 
            'error', ('NotStacked',))
 
1317
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1318
            b'error', (b'NotStacked',))
1087
1319
        client.add_expected_call(
1088
 
            'Branch.get_tags_bytes', ('quack/',),
1089
 
            'success', ('',))
 
1320
            b'Branch.get_tags_bytes', (b'quack/',),
 
1321
            b'success', (b'',))
1090
1322
        transport.mkdir('quack')
1091
1323
        transport = transport.clone('quack')
1092
1324
        branch = self.make_remote_branch(transport, client)
1101
1333
        transport = MemoryTransport()
1102
1334
        client = FakeClient(transport.base)
1103
1335
        client.add_expected_call(
1104
 
            'Branch.get_stacked_on_url', ('quack/',),
1105
 
            'error', ('NotStacked',))
 
1336
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1337
            b'error', (b'NotStacked',))
1106
1338
        client.add_expected_call(
1107
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1108
 
            'success', ('',))
 
1339
            b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
 
1340
            b'success', ('',))
1109
1341
        transport.mkdir('quack')
1110
1342
        transport = transport.clone('quack')
1111
1343
        branch = self.make_remote_branch(transport, client)
1112
1344
        self.lock_remote_branch(branch)
1113
 
        branch._set_tags_bytes('tags bytes')
 
1345
        branch._set_tags_bytes(b'tags bytes')
1114
1346
        self.assertFinished(client)
1115
 
        self.assertEqual('tags bytes', client._calls[-1][-1])
 
1347
        self.assertEqual(b'tags bytes', client._calls[-1][-1])
1116
1348
 
1117
1349
    def test_backwards_compatible(self):
1118
1350
        transport = MemoryTransport()
1119
1351
        client = FakeClient(transport.base)
1120
1352
        client.add_expected_call(
1121
 
            'Branch.get_stacked_on_url', ('quack/',),
1122
 
            'error', ('NotStacked',))
 
1353
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1354
            b'error', (b'NotStacked',))
1123
1355
        client.add_expected_call(
1124
 
            'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1125
 
            'unknown', ('Branch.set_tags_bytes',))
 
1356
            b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
 
1357
            b'unknown', (b'Branch.set_tags_bytes',))
1126
1358
        transport.mkdir('quack')
1127
1359
        transport = transport.clone('quack')
1128
1360
        branch = self.make_remote_branch(transport, client)
1134
1366
                self.calls.append(('set_tags_bytes', bytes))
1135
1367
        real_branch = StubRealBranch()
1136
1368
        branch._real_branch = real_branch
1137
 
        branch._set_tags_bytes('tags bytes')
 
1369
        branch._set_tags_bytes(b'tags bytes')
1138
1370
        # Call a second time, to exercise the 'remote version already inferred'
1139
1371
        # code path.
1140
 
        branch._set_tags_bytes('tags bytes')
1141
 
        self.assertFinished(client)
1142
 
        self.assertEqual(
1143
 
            [('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
 
1372
        branch._set_tags_bytes(b'tags bytes')
 
1373
        self.assertFinished(client)
 
1374
        self.assertEqual(
 
1375
            [('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
 
1376
 
 
1377
 
 
1378
class TestBranchHeadsToFetch(RemoteBranchTestCase):
 
1379
 
 
1380
    def test_uses_last_revision_info_and_tags_by_default(self):
 
1381
        transport = MemoryTransport()
 
1382
        client = FakeClient(transport.base)
 
1383
        client.add_expected_call(
 
1384
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1385
            b'error', (b'NotStacked',))
 
1386
        client.add_expected_call(
 
1387
            b'Branch.last_revision_info', (b'quack/',),
 
1388
            b'success', (b'ok', b'1', b'rev-tip'))
 
1389
        client.add_expected_call(
 
1390
            b'Branch.get_config_file', (b'quack/',),
 
1391
            b'success', (b'ok',), '')
 
1392
        transport.mkdir('quack')
 
1393
        transport = transport.clone('quack')
 
1394
        branch = self.make_remote_branch(transport, client)
 
1395
        result = branch.heads_to_fetch()
 
1396
        self.assertFinished(client)
 
1397
        self.assertEqual(({b'rev-tip'}, set()), result)
 
1398
 
 
1399
    def test_uses_last_revision_info_and_tags_when_set(self):
 
1400
        transport = MemoryTransport()
 
1401
        client = FakeClient(transport.base)
 
1402
        client.add_expected_call(
 
1403
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1404
            b'error', (b'NotStacked',))
 
1405
        client.add_expected_call(
 
1406
            b'Branch.last_revision_info', (b'quack/',),
 
1407
            b'success', (b'ok', b'1', b'rev-tip'))
 
1408
        client.add_expected_call(
 
1409
            b'Branch.get_config_file', (b'quack/',),
 
1410
            b'success', (b'ok',), b'branch.fetch_tags = True')
 
1411
        # XXX: this will break if the default format's serialization of tags
 
1412
        # changes, or if the RPC for fetching tags changes from get_tags_bytes.
 
1413
        client.add_expected_call(
 
1414
            b'Branch.get_tags_bytes', (b'quack/',),
 
1415
            b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
 
1416
        transport.mkdir('quack')
 
1417
        transport = transport.clone('quack')
 
1418
        branch = self.make_remote_branch(transport, client)
 
1419
        result = branch.heads_to_fetch()
 
1420
        self.assertFinished(client)
 
1421
        self.assertEqual(
 
1422
            ({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
 
1423
 
 
1424
    def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
 
1425
        transport = MemoryTransport()
 
1426
        client = FakeClient(transport.base)
 
1427
        client.add_expected_call(
 
1428
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1429
            b'error', (b'NotStacked',))
 
1430
        client.add_expected_call(
 
1431
            b'Branch.heads_to_fetch', (b'quack/',),
 
1432
            b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
 
1433
        transport.mkdir('quack')
 
1434
        transport = transport.clone('quack')
 
1435
        branch = self.make_remote_branch(transport, client)
 
1436
        branch._format._use_default_local_heads_to_fetch = lambda: False
 
1437
        result = branch.heads_to_fetch()
 
1438
        self.assertFinished(client)
 
1439
        self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
 
1440
 
 
1441
    def make_branch_with_tags(self):
 
1442
        self.setup_smart_server_with_call_log()
 
1443
        # Make a branch with a single revision.
 
1444
        builder = self.make_branch_builder('foo')
 
1445
        builder.start_series()
 
1446
        builder.build_snapshot(None, [
 
1447
            ('add', ('', b'root-id', 'directory', ''))],
 
1448
            revision_id=b'tip')
 
1449
        builder.finish_series()
 
1450
        branch = builder.get_branch()
 
1451
        # Add two tags to that branch
 
1452
        branch.tags.set_tag('tag-1', b'rev-1')
 
1453
        branch.tags.set_tag('tag-2', b'rev-2')
 
1454
        return branch
 
1455
 
 
1456
    def test_backwards_compatible(self):
 
1457
        br = self.make_branch_with_tags()
 
1458
        br.get_config_stack().set('branch.fetch_tags', True)
 
1459
        self.addCleanup(br.lock_read().unlock)
 
1460
        # Disable the heads_to_fetch verb
 
1461
        verb = b'Branch.heads_to_fetch'
 
1462
        self.disable_verb(verb)
 
1463
        self.reset_smart_call_log()
 
1464
        result = br.heads_to_fetch()
 
1465
        self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
 
1466
        self.assertEqual(
 
1467
            [b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
 
1468
            [call.call.method for call in self.hpss_calls])
 
1469
 
 
1470
    def test_backwards_compatible_no_tags(self):
 
1471
        br = self.make_branch_with_tags()
 
1472
        br.get_config_stack().set('branch.fetch_tags', False)
 
1473
        self.addCleanup(br.lock_read().unlock)
 
1474
        # Disable the heads_to_fetch verb
 
1475
        verb = b'Branch.heads_to_fetch'
 
1476
        self.disable_verb(verb)
 
1477
        self.reset_smart_call_log()
 
1478
        result = br.heads_to_fetch()
 
1479
        self.assertEqual(({b'tip'}, set()), result)
 
1480
        self.assertEqual(
 
1481
            [b'Branch.last_revision_info'],
 
1482
            [call.call.method for call in self.hpss_calls])
1144
1483
 
1145
1484
 
1146
1485
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1150
1489
        transport = MemoryTransport()
1151
1490
        client = FakeClient(transport.base)
1152
1491
        client.add_expected_call(
1153
 
            'Branch.get_stacked_on_url', ('quack/',),
1154
 
            'error', ('NotStacked',))
 
1492
            b'Branch.get_stacked_on_url', (b'quack/',),
 
1493
            b'error', (b'NotStacked',))
1155
1494
        client.add_expected_call(
1156
 
            'Branch.last_revision_info', ('quack/',),
1157
 
            'success', ('ok', '0', 'null:'))
 
1495
            b'Branch.last_revision_info', (b'quack/',),
 
1496
            b'success', (b'ok', b'0', b'null:'))
1158
1497
        transport.mkdir('quack')
1159
1498
        transport = transport.clone('quack')
1160
1499
        branch = self.make_remote_branch(transport, client)
1168
1507
        transport = MemoryTransport()
1169
1508
        client = FakeClient(transport.base)
1170
1509
        client.add_expected_call(
1171
 
            'Branch.get_stacked_on_url', ('kwaak/',),
1172
 
            'error', ('NotStacked',))
 
1510
            b'Branch.get_stacked_on_url', (b'kwaak/',),
 
1511
            b'error', (b'NotStacked',))
1173
1512
        client.add_expected_call(
1174
 
            'Branch.last_revision_info', ('kwaak/',),
1175
 
            'success', ('ok', '2', revid))
 
1513
            b'Branch.last_revision_info', (b'kwaak/',),
 
1514
            b'success', (b'ok', b'2', revid))
1176
1515
        transport.mkdir('kwaak')
1177
1516
        transport = transport.clone('kwaak')
1178
1517
        branch = self.make_remote_branch(transport, client)
1193
1532
        memory_branch = self.make_branch('base', format='1.9')
1194
1533
        vfs_url = self.get_vfs_only_url('base')
1195
1534
        stacked_branch.set_stacked_on_url(vfs_url)
1196
 
        transport = stacked_branch.bzrdir.root_transport
 
1535
        transport = stacked_branch.controldir.root_transport
1197
1536
        client = FakeClient(transport.base)
1198
1537
        client.add_expected_call(
1199
 
            'Branch.get_stacked_on_url', ('stacked/',),
1200
 
            'success', ('ok', vfs_url))
 
1538
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1539
            b'success', (b'ok', vfs_url))
1201
1540
        # XXX: Multiple calls are bad, this second call documents what is
1202
1541
        # today.
1203
1542
        client.add_expected_call(
1204
 
            'Branch.get_stacked_on_url', ('stacked/',),
1205
 
            'success', ('ok', vfs_url))
1206
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
1543
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1544
            b'success', (b'ok', vfs_url))
 
1545
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1207
1546
            _client=client)
1208
1547
        repo_fmt = remote.RemoteRepositoryFormat()
1209
1548
        repo_fmt._custom_format = stacked_branch.repository._format
1220
1559
        client = FakeClient(self.get_url())
1221
1560
        branch_network_name = self.get_branch_format().network_name()
1222
1561
        client.add_expected_call(
1223
 
            'BzrDir.open_branchV3', ('stacked/',),
1224
 
            'success', ('branch', branch_network_name))
 
1562
            b'BzrDir.open_branchV3', (b'stacked/',),
 
1563
            b'success', (b'branch', branch_network_name))
1225
1564
        client.add_expected_call(
1226
 
            'BzrDir.find_repositoryV3', ('stacked/',),
1227
 
            'success', ('ok', '', 'no', 'no', 'yes',
 
1565
            b'BzrDir.find_repositoryV3', (b'stacked/',),
 
1566
            b'success', (b'ok', b'', b'no', b'no', b'yes',
1228
1567
                stacked_branch.repository._format.network_name()))
1229
1568
        # called twice, once from constructor and then again by us
1230
1569
        client.add_expected_call(
1231
 
            'Branch.get_stacked_on_url', ('stacked/',),
1232
 
            'unknown', ('Branch.get_stacked_on_url',))
 
1570
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1571
            b'unknown', (b'Branch.get_stacked_on_url',))
1233
1572
        client.add_expected_call(
1234
 
            'Branch.get_stacked_on_url', ('stacked/',),
1235
 
            'unknown', ('Branch.get_stacked_on_url',))
 
1573
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1574
            b'unknown', (b'Branch.get_stacked_on_url',))
1236
1575
        # this will also do vfs access, but that goes direct to the transport
1237
1576
        # and isn't seen by the FakeClient.
1238
1577
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1578
            RemoteBzrDirFormat(), _client=client)
1240
1579
        branch = bzrdir.open_branch()
1241
1580
        result = branch.get_stacked_on_url()
1242
1581
        self.assertEqual('../base', result)
1256
1595
        client = FakeClient(self.get_url())
1257
1596
        branch_network_name = self.get_branch_format().network_name()
1258
1597
        client.add_expected_call(
1259
 
            'BzrDir.open_branchV3', ('stacked/',),
1260
 
            'success', ('branch', branch_network_name))
 
1598
            b'BzrDir.open_branchV3', ('stacked/',),
 
1599
            b'success', ('branch', branch_network_name))
1261
1600
        client.add_expected_call(
1262
 
            'BzrDir.find_repositoryV3', ('stacked/',),
1263
 
            'success', ('ok', '', 'yes', 'no', 'yes', network_name))
 
1601
            b'BzrDir.find_repositoryV3', (b'stacked/',),
 
1602
            b'success', (b'ok', b'', b'yes', b'no', b'yes', network_name))
1264
1603
        # called twice, once from constructor and then again by us
1265
1604
        client.add_expected_call(
1266
 
            'Branch.get_stacked_on_url', ('stacked/',),
1267
 
            'success', ('ok', '../base'))
 
1605
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1606
            b'success', (b'ok', b'../base'))
1268
1607
        client.add_expected_call(
1269
 
            'Branch.get_stacked_on_url', ('stacked/',),
1270
 
            'success', ('ok', '../base'))
 
1608
            b'Branch.get_stacked_on_url', (b'stacked/',),
 
1609
            b'success', (b'ok', b'../base'))
1271
1610
        bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
 
            remote.RemoteBzrDirFormat(), _client=client)
 
1611
            RemoteBzrDirFormat(), _client=client)
1273
1612
        branch = bzrdir.open_branch()
1274
1613
        result = branch.get_stacked_on_url()
1275
1614
        self.assertEqual('../base', result)
1283
1622
class TestBranchSetLastRevision(RemoteBranchTestCase):
1284
1623
 
1285
1624
    def test_set_empty(self):
1286
 
        # set_revision_history([]) is translated to calling
 
1625
        # _set_last_revision_info('null:') is translated to calling
1287
1626
        # Branch.set_last_revision(path, '') on the wire.
1288
1627
        transport = MemoryTransport()
1289
1628
        transport.mkdir('branch')
1291
1630
 
1292
1631
        client = FakeClient(transport.base)
1293
1632
        client.add_expected_call(
1294
 
            'Branch.get_stacked_on_url', ('branch/',),
1295
 
            'error', ('NotStacked',))
1296
 
        client.add_expected_call(
1297
 
            'Branch.lock_write', ('branch/', '', ''),
1298
 
            'success', ('ok', 'branch token', 'repo token'))
1299
 
        client.add_expected_call(
1300
 
            'Branch.last_revision_info',
1301
 
            ('branch/',),
1302
 
            'success', ('ok', '0', 'null:'))
1303
 
        client.add_expected_call(
1304
 
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
1305
 
            'success', ('ok',))
1306
 
        client.add_expected_call(
1307
 
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1308
 
            'success', ('ok',))
 
1633
            b'Branch.get_stacked_on_url', (b'branch/',),
 
1634
            b'error', (b'NotStacked',))
 
1635
        client.add_expected_call(
 
1636
            b'Branch.lock_write', (b'branch/', b'', b''),
 
1637
            b'success', (b'ok', b'branch token', b'repo token'))
 
1638
        client.add_expected_call(
 
1639
            b'Branch.last_revision_info',
 
1640
            (b'branch/',),
 
1641
            b'success', (b'ok', b'0', b'null:'))
 
1642
        client.add_expected_call(
 
1643
            b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
 
1644
            b'success', (b'ok',))
 
1645
        client.add_expected_call(
 
1646
            b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
 
1647
            b'success', (b'ok',))
1309
1648
        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
1649
        branch.lock_write()
1314
 
        result = branch.set_revision_history([])
 
1650
        result = branch._set_last_revision(NULL_REVISION)
1315
1651
        branch.unlock()
1316
1652
        self.assertEqual(None, result)
1317
1653
        self.assertFinished(client)
1318
1654
 
1319
1655
    def test_set_nonempty(self):
1320
 
        # set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
 
1656
        # set_last_revision_info(N, rev-idN) is translated to calling
1321
1657
        # Branch.set_last_revision(path, rev-idN) on the wire.
1322
1658
        transport = MemoryTransport()
1323
1659
        transport.mkdir('branch')
1325
1661
 
1326
1662
        client = FakeClient(transport.base)
1327
1663
        client.add_expected_call(
1328
 
            'Branch.get_stacked_on_url', ('branch/',),
1329
 
            'error', ('NotStacked',))
1330
 
        client.add_expected_call(
1331
 
            'Branch.lock_write', ('branch/', '', ''),
1332
 
            'success', ('ok', 'branch token', 'repo token'))
1333
 
        client.add_expected_call(
1334
 
            'Branch.last_revision_info',
1335
 
            ('branch/',),
1336
 
            'success', ('ok', '0', 'null:'))
1337
 
        lines = ['rev-id2']
1338
 
        encoded_body = bz2.compress('\n'.join(lines))
1339
 
        client.add_success_response_with_body(encoded_body, 'ok')
1340
 
        client.add_expected_call(
1341
 
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
1342
 
            'success', ('ok',))
1343
 
        client.add_expected_call(
1344
 
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1345
 
            'success', ('ok',))
 
1664
            b'Branch.get_stacked_on_url', (b'branch/',),
 
1665
            b'error', (b'NotStacked',))
 
1666
        client.add_expected_call(
 
1667
            b'Branch.lock_write', (b'branch/', b'', b''),
 
1668
            b'success', (b'ok', b'branch token', b'repo token'))
 
1669
        client.add_expected_call(
 
1670
            b'Branch.last_revision_info',
 
1671
            (b'branch/',),
 
1672
            b'success', (b'ok', b'0', b'null:'))
 
1673
        lines = [b'rev-id2']
 
1674
        encoded_body = bz2.compress(b'\n'.join(lines))
 
1675
        client.add_success_response_with_body(encoded_body, b'ok')
 
1676
        client.add_expected_call(
 
1677
            b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
 
1678
            b'success', (b'ok',))
 
1679
        client.add_expected_call(
 
1680
            b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
 
1681
            b'success', (b'ok',))
1346
1682
        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
1683
        # Lock the branch, reset the record of remote calls.
1351
1684
        branch.lock_write()
1352
 
        result = branch.set_revision_history(['rev-id1', 'rev-id2'])
 
1685
        result = branch._set_last_revision(b'rev-id2')
1353
1686
        branch.unlock()
1354
1687
        self.assertEqual(None, result)
1355
1688
        self.assertFinished(client)
1361
1694
        # A response of 'NoSuchRevision' is translated into an exception.
1362
1695
        client = FakeClient(transport.base)
1363
1696
        client.add_expected_call(
1364
 
            'Branch.get_stacked_on_url', ('branch/',),
1365
 
            'error', ('NotStacked',))
1366
 
        client.add_expected_call(
1367
 
            'Branch.lock_write', ('branch/', '', ''),
1368
 
            'success', ('ok', 'branch token', 'repo token'))
1369
 
        client.add_expected_call(
1370
 
            'Branch.last_revision_info',
1371
 
            ('branch/',),
1372
 
            'success', ('ok', '0', 'null:'))
 
1697
            b'Branch.get_stacked_on_url', (b'branch/',),
 
1698
            b'error', (b'NotStacked',))
 
1699
        client.add_expected_call(
 
1700
            b'Branch.lock_write', (b'branch/', b'', b''),
 
1701
            b'success', (b'ok', b'branch token', b'repo token'))
 
1702
        client.add_expected_call(
 
1703
            b'Branch.last_revision_info',
 
1704
            (b'branch/',),
 
1705
            b'success', (b'ok', b'0', b'null:'))
1373
1706
        # get_graph calls to construct the revision history, for the set_rh
1374
1707
        # hook
1375
 
        lines = ['rev-id']
1376
 
        encoded_body = bz2.compress('\n'.join(lines))
1377
 
        client.add_success_response_with_body(encoded_body, 'ok')
1378
 
        client.add_expected_call(
1379
 
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1380
 
            'error', ('NoSuchRevision', 'rev-id'))
1381
 
        client.add_expected_call(
1382
 
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1383
 
            'success', ('ok',))
 
1708
        lines = [b'rev-id']
 
1709
        encoded_body = bz2.compress(b'\n'.join(lines))
 
1710
        client.add_success_response_with_body(encoded_body, b'ok')
 
1711
        client.add_expected_call(
 
1712
            b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
 
1713
            b'error', (b'NoSuchRevision', b'rev-id'))
 
1714
        client.add_expected_call(
 
1715
            b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
 
1716
            b'success', (b'ok',))
1384
1717
 
1385
1718
        branch = self.make_remote_branch(transport, client)
1386
1719
        branch.lock_write()
1387
1720
        self.assertRaises(
1388
 
            errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
 
1721
            errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1722
        branch.unlock()
1390
1723
        self.assertFinished(client)
1391
1724
 
1400
1733
        rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1734
        rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1735
        client.add_expected_call(
1403
 
            'Branch.get_stacked_on_url', ('branch/',),
1404
 
            'error', ('NotStacked',))
1405
 
        client.add_expected_call(
1406
 
            'Branch.lock_write', ('branch/', '', ''),
1407
 
            'success', ('ok', 'branch token', 'repo token'))
1408
 
        client.add_expected_call(
1409
 
            'Branch.last_revision_info',
1410
 
            ('branch/',),
1411
 
            'success', ('ok', '0', 'null:'))
1412
 
        lines = ['rev-id']
1413
 
        encoded_body = bz2.compress('\n'.join(lines))
1414
 
        client.add_success_response_with_body(encoded_body, 'ok')
1415
 
        client.add_expected_call(
1416
 
            'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1417
 
            'error', ('TipChangeRejected', rejection_msg_utf8))
1418
 
        client.add_expected_call(
1419
 
            'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1420
 
            'success', ('ok',))
 
1736
            b'Branch.get_stacked_on_url', (b'branch/',),
 
1737
            b'error', (b'NotStacked',))
 
1738
        client.add_expected_call(
 
1739
            b'Branch.lock_write', (b'branch/', b'', b''),
 
1740
            b'success', (b'ok', b'branch token', b'repo token'))
 
1741
        client.add_expected_call(
 
1742
            b'Branch.last_revision_info',
 
1743
            (b'branch/',),
 
1744
            b'success', (b'ok', b'0', b'null:'))
 
1745
        lines = [b'rev-id']
 
1746
        encoded_body = bz2.compress(b'\n'.join(lines))
 
1747
        client.add_success_response_with_body(encoded_body, b'ok')
 
1748
        client.add_expected_call(
 
1749
            b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
 
1750
            b'error', (b'TipChangeRejected', rejection_msg_utf8))
 
1751
        client.add_expected_call(
 
1752
            b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
 
1753
            b'success', (b'ok',))
1421
1754
        branch = self.make_remote_branch(transport, client)
1422
 
        branch._ensure_real = lambda: None
1423
1755
        branch.lock_write()
1424
1756
        # The 'TipChangeRejected' error response triggered by calling
1425
 
        # set_revision_history causes a TipChangeRejected exception.
 
1757
        # set_last_revision_info causes a TipChangeRejected exception.
1426
1758
        err = self.assertRaises(
1427
 
            errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
 
1759
            errors.TipChangeRejected,
 
1760
            branch._set_last_revision, b'rev-id')
1428
1761
        # The UTF-8 message from the response has been decoded into a unicode
1429
1762
        # object.
1430
 
        self.assertIsInstance(err.msg, unicode)
 
1763
        self.assertIsInstance(err.msg, text_type)
1431
1764
        self.assertEqual(rejection_msg_unicode, err.msg)
1432
1765
        branch.unlock()
1433
1766
        self.assertFinished(client)
1443
1776
        transport = transport.clone('branch')
1444
1777
        client = FakeClient(transport.base)
1445
1778
        # get_stacked_on_url
1446
 
        client.add_error_response('NotStacked')
 
1779
        client.add_error_response(b'NotStacked')
1447
1780
        # lock_write
1448
 
        client.add_success_response('ok', 'branch token', 'repo token')
 
1781
        client.add_success_response(b'ok', b'branch token', b'repo token')
1449
1782
        # query the current revision
1450
 
        client.add_success_response('ok', '0', 'null:')
 
1783
        client.add_success_response(b'ok', b'0', b'null:')
1451
1784
        # set_last_revision
1452
 
        client.add_success_response('ok')
 
1785
        client.add_success_response(b'ok')
1453
1786
        # unlock
1454
 
        client.add_success_response('ok')
 
1787
        client.add_success_response(b'ok')
1455
1788
 
1456
1789
        branch = self.make_remote_branch(transport, client)
1457
1790
        # Lock the branch, reset the record of remote calls.
1458
1791
        branch.lock_write()
1459
1792
        client._calls = []
1460
 
        result = branch.set_last_revision_info(1234, 'a-revision-id')
 
1793
        result = branch.set_last_revision_info(1234, b'a-revision-id')
1461
1794
        self.assertEqual(
1462
 
            [('call', 'Branch.last_revision_info', ('branch/',)),
1463
 
             ('call', 'Branch.set_last_revision_info',
1464
 
                ('branch/', 'branch token', 'repo token',
1465
 
                 '1234', 'a-revision-id'))],
 
1795
            [('call', b'Branch.last_revision_info', (b'branch/',)),
 
1796
             ('call', b'Branch.set_last_revision_info',
 
1797
                (b'branch/', b'branch token', b'repo token',
 
1798
                 b'1234', b'a-revision-id'))],
1466
1799
            client._calls)
1467
1800
        self.assertEqual(None, result)
1468
1801
 
1473
1806
        transport = transport.clone('branch')
1474
1807
        client = FakeClient(transport.base)
1475
1808
        # get_stacked_on_url
1476
 
        client.add_error_response('NotStacked')
 
1809
        client.add_error_response(b'NotStacked')
1477
1810
        # lock_write
1478
 
        client.add_success_response('ok', 'branch token', 'repo token')
 
1811
        client.add_success_response(b'ok', b'branch token', b'repo token')
1479
1812
        # set_last_revision
1480
 
        client.add_error_response('NoSuchRevision', 'revid')
 
1813
        client.add_error_response(b'NoSuchRevision', b'revid')
1481
1814
        # unlock
1482
 
        client.add_success_response('ok')
 
1815
        client.add_success_response(b'ok')
1483
1816
 
1484
1817
        branch = self.make_remote_branch(transport, client)
1485
1818
        # Lock the branch, reset the record of remote calls.
1487
1820
        client._calls = []
1488
1821
 
1489
1822
        self.assertRaises(
1490
 
            errors.NoSuchRevision, branch.set_last_revision_info, 123, 'revid')
 
1823
            errors.NoSuchRevision, branch.set_last_revision_info, 123, b'revid')
1491
1824
        branch.unlock()
1492
1825
 
1493
1826
    def test_backwards_compatibility(self):
1507
1840
        transport = transport.clone('branch')
1508
1841
        client = FakeClient(transport.base)
1509
1842
        client.add_expected_call(
1510
 
            'Branch.get_stacked_on_url', ('branch/',),
1511
 
            'error', ('NotStacked',))
1512
 
        client.add_expected_call(
1513
 
            'Branch.last_revision_info',
1514
 
            ('branch/',),
1515
 
            'success', ('ok', '0', 'null:'))
1516
 
        client.add_expected_call(
1517
 
            'Branch.set_last_revision_info',
1518
 
            ('branch/', 'branch token', 'repo token', '1234', 'a-revision-id',),
1519
 
            'unknown', 'Branch.set_last_revision_info')
 
1843
            b'Branch.get_stacked_on_url', (b'branch/',),
 
1844
            b'error', (b'NotStacked',))
 
1845
        client.add_expected_call(
 
1846
            b'Branch.last_revision_info',
 
1847
            (b'branch/',),
 
1848
            b'success', (b'ok', b'0', b'null:'))
 
1849
        client.add_expected_call(
 
1850
            b'Branch.set_last_revision_info',
 
1851
            (b'branch/', b'branch token', b'repo token', b'1234', b'a-revision-id',),
 
1852
            b'unknown', b'Branch.set_last_revision_info')
1520
1853
 
1521
1854
        branch = self.make_remote_branch(transport, client)
1522
1855
        class StubRealBranch(object):
1532
1865
        self.lock_remote_branch(branch)
1533
1866
 
1534
1867
        # Call set_last_revision_info, and verify it behaved as expected.
1535
 
        result = branch.set_last_revision_info(1234, 'a-revision-id')
 
1868
        result = branch.set_last_revision_info(1234, b'a-revision-id')
1536
1869
        self.assertEqual(
1537
 
            [('set_last_revision_info', 1234, 'a-revision-id')],
 
1870
            [('set_last_revision_info', 1234, b'a-revision-id')],
1538
1871
            real_branch.calls)
1539
1872
        self.assertFinished(client)
1540
1873
 
1547
1880
        transport = transport.clone('branch')
1548
1881
        client = FakeClient(transport.base)
1549
1882
        # get_stacked_on_url
1550
 
        client.add_error_response('NotStacked')
 
1883
        client.add_error_response(b'NotStacked')
1551
1884
        # lock_write
1552
 
        client.add_success_response('ok', 'branch token', 'repo token')
 
1885
        client.add_success_response(b'ok', b'branch token', b'repo token')
1553
1886
        # set_last_revision
1554
 
        client.add_error_response('UnexpectedError')
 
1887
        client.add_error_response(b'UnexpectedError')
1555
1888
        # unlock
1556
 
        client.add_success_response('ok')
 
1889
        client.add_success_response(b'ok')
1557
1890
 
1558
1891
        branch = self.make_remote_branch(transport, client)
1559
1892
        # Lock the branch, reset the record of remote calls.
1562
1895
 
1563
1896
        err = self.assertRaises(
1564
1897
            errors.UnknownErrorFromSmartServer,
1565
 
            branch.set_last_revision_info, 123, 'revid')
1566
 
        self.assertEqual(('UnexpectedError',), err.error_tuple)
 
1898
            branch.set_last_revision_info, 123, b'revid')
 
1899
        self.assertEqual((b'UnexpectedError',), err.error_tuple)
1567
1900
        branch.unlock()
1568
1901
 
1569
1902
    def test_tip_change_rejected(self):
1575
1908
        transport = transport.clone('branch')
1576
1909
        client = FakeClient(transport.base)
1577
1910
        # get_stacked_on_url
1578
 
        client.add_error_response('NotStacked')
 
1911
        client.add_error_response(b'NotStacked')
1579
1912
        # lock_write
1580
 
        client.add_success_response('ok', 'branch token', 'repo token')
 
1913
        client.add_success_response(b'ok', b'branch token', b'repo token')
1581
1914
        # set_last_revision
1582
 
        client.add_error_response('TipChangeRejected', 'rejection message')
 
1915
        client.add_error_response(b'TipChangeRejected', b'rejection message')
1583
1916
        # unlock
1584
 
        client.add_success_response('ok')
 
1917
        client.add_success_response(b'ok')
1585
1918
 
1586
1919
        branch = self.make_remote_branch(transport, client)
1587
1920
        # Lock the branch, reset the record of remote calls.
1593
1926
        # set_last_revision_info causes a TipChangeRejected exception.
1594
1927
        err = self.assertRaises(
1595
1928
            errors.TipChangeRejected,
1596
 
            branch.set_last_revision_info, 123, 'revid')
 
1929
            branch.set_last_revision_info, 123, b'revid')
1597
1930
        self.assertEqual('rejection message', err.msg)
1598
1931
 
1599
1932
 
1603
1936
        # in an empty branch we decode the response properly
1604
1937
        client = FakeClient()
1605
1938
        client.add_expected_call(
1606
 
            'Branch.get_stacked_on_url', ('memory:///',),
1607
 
            'error', ('NotStacked',),)
1608
 
        client.add_success_response_with_body('# config file body', 'ok')
 
1939
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
1940
            b'error', (b'NotStacked',),)
 
1941
        client.add_success_response_with_body(b'# config file body', b'ok')
1609
1942
        transport = MemoryTransport()
1610
1943
        branch = self.make_remote_branch(transport, client)
1611
1944
        config = branch.get_config()
1612
1945
        config.has_explicit_nickname()
1613
1946
        self.assertEqual(
1614
 
            [('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1615
 
             ('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
 
1947
            [('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
 
1948
             ('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
1616
1949
            client._calls)
1617
1950
 
1618
1951
    def test_get_multi_line_branch_conf(self):
1619
1952
        # Make sure that multiple-line branch.conf files are supported
1620
1953
        #
1621
 
        # https://bugs.edge.launchpad.net/bzr/+bug/354075
 
1954
        # https://bugs.launchpad.net/bzr/+bug/354075
1622
1955
        client = FakeClient()
1623
1956
        client.add_expected_call(
1624
 
            'Branch.get_stacked_on_url', ('memory:///',),
1625
 
            'error', ('NotStacked',),)
1626
 
        client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
 
1957
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
1958
            b'error', (b'NotStacked',),)
 
1959
        client.add_success_response_with_body(b'a = 1\nb = 2\nc = 3\n', b'ok')
1627
1960
        transport = MemoryTransport()
1628
1961
        branch = self.make_remote_branch(transport, client)
1629
1962
        config = branch.get_config()
1632
1965
    def test_set_option(self):
1633
1966
        client = FakeClient()
1634
1967
        client.add_expected_call(
1635
 
            'Branch.get_stacked_on_url', ('memory:///',),
1636
 
            'error', ('NotStacked',),)
1637
 
        client.add_expected_call(
1638
 
            'Branch.lock_write', ('memory:///', '', ''),
1639
 
            'success', ('ok', 'branch token', 'repo token'))
1640
 
        client.add_expected_call(
1641
 
            'Branch.set_config_option', ('memory:///', 'branch token',
1642
 
            'repo token', 'foo', 'bar', ''),
1643
 
            'success', ())
1644
 
        client.add_expected_call(
1645
 
            'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1646
 
            'success', ('ok',))
 
1968
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
1969
            b'error', (b'NotStacked',),)
 
1970
        client.add_expected_call(
 
1971
            b'Branch.lock_write', (b'memory:///', b'', b''),
 
1972
            b'success', (b'ok', b'branch token', b'repo token'))
 
1973
        client.add_expected_call(
 
1974
            b'Branch.set_config_option', (b'memory:///', b'branch token',
 
1975
            b'repo token', b'foo', b'bar', b''),
 
1976
            b'success', ())
 
1977
        client.add_expected_call(
 
1978
            b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
 
1979
            b'success', (b'ok',))
1647
1980
        transport = MemoryTransport()
1648
1981
        branch = self.make_remote_branch(transport, client)
1649
1982
        branch.lock_write()
1652
1985
        branch.unlock()
1653
1986
        self.assertFinished(client)
1654
1987
 
 
1988
    def test_set_option_with_dict(self):
 
1989
        client = FakeClient()
 
1990
        client.add_expected_call(
 
1991
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
1992
            b'error', (b'NotStacked',),)
 
1993
        client.add_expected_call(
 
1994
            b'Branch.lock_write', (b'memory:///', b'', b''),
 
1995
            b'success', (b'ok', b'branch token', b'repo token'))
 
1996
        encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
 
1997
        client.add_expected_call(
 
1998
            b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
 
1999
            b'repo token', encoded_dict_value, b'foo', b''),
 
2000
            b'success', ())
 
2001
        client.add_expected_call(
 
2002
            b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
 
2003
            b'success', (b'ok',))
 
2004
        transport = MemoryTransport()
 
2005
        branch = self.make_remote_branch(transport, client)
 
2006
        branch.lock_write()
 
2007
        config = branch._get_config()
 
2008
        config.set_option(
 
2009
            {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
 
2010
            'foo')
 
2011
        branch.unlock()
 
2012
        self.assertFinished(client)
 
2013
 
1655
2014
    def test_backwards_compat_set_option(self):
1656
2015
        self.setup_smart_server_with_call_log()
1657
2016
        branch = self.make_branch('.')
1658
 
        verb = 'Branch.set_config_option'
 
2017
        verb = b'Branch.set_config_option'
1659
2018
        self.disable_verb(verb)
1660
2019
        branch.lock_write()
1661
2020
        self.addCleanup(branch.unlock)
1662
2021
        self.reset_smart_call_log()
1663
2022
        branch._get_config().set_option('value', 'name')
1664
 
        self.assertLength(10, self.hpss_calls)
 
2023
        self.assertLength(11, self.hpss_calls)
1665
2024
        self.assertEqual('value', branch._get_config().get_option('name'))
1666
2025
 
 
2026
    def test_backwards_compat_set_option_with_dict(self):
 
2027
        self.setup_smart_server_with_call_log()
 
2028
        branch = self.make_branch('.')
 
2029
        verb = b'Branch.set_config_option_dict'
 
2030
        self.disable_verb(verb)
 
2031
        branch.lock_write()
 
2032
        self.addCleanup(branch.unlock)
 
2033
        self.reset_smart_call_log()
 
2034
        config = branch._get_config()
 
2035
        value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
2036
        config.set_option(value_dict, 'name')
 
2037
        self.assertLength(11, self.hpss_calls)
 
2038
        self.assertEqual(value_dict, branch._get_config().get_option('name'))
 
2039
 
 
2040
 
 
2041
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
 
2042
 
 
2043
    def test_get_branch_conf(self):
 
2044
        # in an empty branch we decode the response properly
 
2045
        client = FakeClient()
 
2046
        client.add_expected_call(
 
2047
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
2048
            b'error', (b'NotStacked',),)
 
2049
        client.add_success_response_with_body(b'# config file body', b'ok')
 
2050
        transport = MemoryTransport()
 
2051
        branch = self.make_remote_branch(transport, client)
 
2052
        config = branch.get_config_stack()
 
2053
        config.get("email")
 
2054
        config.get("log_format")
 
2055
        self.assertEqual(
 
2056
            [('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
 
2057
             ('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
 
2058
            client._calls)
 
2059
 
 
2060
    def test_set_branch_conf(self):
 
2061
        client = FakeClient()
 
2062
        client.add_expected_call(
 
2063
            b'Branch.get_stacked_on_url', (b'memory:///',),
 
2064
            b'error', (b'NotStacked',),)
 
2065
        client.add_expected_call(
 
2066
            b'Branch.lock_write', (b'memory:///', b'', b''),
 
2067
            b'success', (b'ok', b'branch token', b'repo token'))
 
2068
        client.add_expected_call(
 
2069
            b'Branch.get_config_file', (b'memory:///', ),
 
2070
            b'success', (b'ok', ), b"# line 1\n")
 
2071
        client.add_expected_call(
 
2072
            b'Branch.get_config_file', (b'memory:///', ),
 
2073
            b'success', (b'ok', ), b"# line 1\n")
 
2074
        client.add_expected_call(
 
2075
            b'Branch.put_config_file', (b'memory:///', b'branch token',
 
2076
            b'repo token'),
 
2077
            b'success', (b'ok',))
 
2078
        client.add_expected_call(
 
2079
            b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
 
2080
            b'success', (b'ok',))
 
2081
        transport = MemoryTransport()
 
2082
        branch = self.make_remote_branch(transport, client)
 
2083
        branch.lock_write()
 
2084
        config = branch.get_config_stack()
 
2085
        config.set('email', 'The Dude <lebowski@example.com>')
 
2086
        branch.unlock()
 
2087
        self.assertFinished(client)
 
2088
        self.assertEqual(
 
2089
            [('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
 
2090
             ('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
 
2091
             ('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
 
2092
             ('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
 
2093
             ('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
 
2094
                 (b'memory:///', b'branch token', b'repo token'),
 
2095
                 b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
 
2096
             ('call', b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'))],
 
2097
            client._calls)
 
2098
 
1667
2099
 
1668
2100
class TestBranchLockWrite(RemoteBranchTestCase):
1669
2101
 
1671
2103
        transport = MemoryTransport()
1672
2104
        client = FakeClient(transport.base)
1673
2105
        client.add_expected_call(
1674
 
            'Branch.get_stacked_on_url', ('quack/',),
1675
 
            'error', ('NotStacked',),)
 
2106
            b'Branch.get_stacked_on_url', (b'quack/',),
 
2107
            b'error', (b'NotStacked',),)
1676
2108
        client.add_expected_call(
1677
 
            'Branch.lock_write', ('quack/', '', ''),
1678
 
            'error', ('UnlockableTransport',))
 
2109
            b'Branch.lock_write', (b'quack/', b'', b''),
 
2110
            b'error', (b'UnlockableTransport',))
1679
2111
        transport.mkdir('quack')
1680
2112
        transport = transport.clone('quack')
1681
2113
        branch = self.make_remote_branch(transport, client)
1683
2115
        self.assertFinished(client)
1684
2116
 
1685
2117
 
 
2118
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
 
2119
 
 
2120
    def test_simple(self):
 
2121
        transport = MemoryTransport()
 
2122
        client = FakeClient(transport.base)
 
2123
        client.add_expected_call(
 
2124
            b'Branch.get_stacked_on_url', (b'quack/',),
 
2125
            b'error', (b'NotStacked',),)
 
2126
        client.add_expected_call(
 
2127
            b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
 
2128
            b'success', (b'ok', b'0',),)
 
2129
        client.add_expected_call(
 
2130
            b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
 
2131
            b'error', (b'NoSuchRevision', b'unknown',),)
 
2132
        transport.mkdir('quack')
 
2133
        transport = transport.clone('quack')
 
2134
        branch = self.make_remote_branch(transport, client)
 
2135
        self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
 
2136
        self.assertRaises(errors.NoSuchRevision,
 
2137
            branch.revision_id_to_revno, b'unknown')
 
2138
        self.assertFinished(client)
 
2139
 
 
2140
    def test_dotted(self):
 
2141
        transport = MemoryTransport()
 
2142
        client = FakeClient(transport.base)
 
2143
        client.add_expected_call(
 
2144
            b'Branch.get_stacked_on_url', (b'quack/',),
 
2145
            b'error', (b'NotStacked',),)
 
2146
        client.add_expected_call(
 
2147
            b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
 
2148
            b'success', (b'ok', b'0',),)
 
2149
        client.add_expected_call(
 
2150
            b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
 
2151
            b'error', (b'NoSuchRevision', b'unknown',),)
 
2152
        transport.mkdir('quack')
 
2153
        transport = transport.clone('quack')
 
2154
        branch = self.make_remote_branch(transport, client)
 
2155
        self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
 
2156
        self.assertRaises(errors.NoSuchRevision,
 
2157
            branch.revision_id_to_dotted_revno, b'unknown')
 
2158
        self.assertFinished(client)
 
2159
 
 
2160
    def test_dotted_no_smart_verb(self):
 
2161
        self.setup_smart_server_with_call_log()
 
2162
        branch = self.make_branch('.')
 
2163
        self.disable_verb(b'Branch.revision_id_to_revno')
 
2164
        self.reset_smart_call_log()
 
2165
        self.assertEqual((0, ),
 
2166
            branch.revision_id_to_dotted_revno(b'null:'))
 
2167
        self.assertLength(8, self.hpss_calls)
 
2168
 
 
2169
 
1686
2170
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1687
2171
 
1688
2172
    def test__get_config(self):
1689
2173
        client = FakeClient()
1690
 
        client.add_success_response_with_body('default_stack_on = /\n', 'ok')
 
2174
        client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2175
        transport = MemoryTransport()
1692
2176
        bzrdir = self.make_remote_bzrdir(transport, client)
1693
2177
        config = bzrdir.get_config()
1694
2178
        self.assertEqual('/', config.get_default_stack_on())
1695
2179
        self.assertEqual(
1696
 
            [('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
 
2180
            [('call_expecting_body', b'BzrDir.get_config_file', (b'memory:///',))],
1697
2181
            client._calls)
1698
2182
 
1699
2183
    def test_set_option_uses_vfs(self):
1700
2184
        self.setup_smart_server_with_call_log()
1701
 
        bzrdir = self.make_bzrdir('.')
 
2185
        bzrdir = self.make_controldir('.')
1702
2186
        self.reset_smart_call_log()
1703
2187
        config = bzrdir.get_config()
1704
2188
        config.set_default_stack_on('/')
1705
 
        self.assertLength(3, self.hpss_calls)
 
2189
        self.assertLength(4, self.hpss_calls)
1706
2190
 
1707
2191
    def test_backwards_compat_get_option(self):
1708
2192
        self.setup_smart_server_with_call_log()
1709
 
        bzrdir = self.make_bzrdir('.')
1710
 
        verb = 'BzrDir.get_config_file'
 
2193
        bzrdir = self.make_controldir('.')
 
2194
        verb = b'BzrDir.get_config_file'
1711
2195
        self.disable_verb(verb)
1712
2196
        self.reset_smart_call_log()
1713
2197
        self.assertEqual(None,
1714
2198
            bzrdir._get_config().get_option('default_stack_on'))
1715
 
        self.assertLength(3, self.hpss_calls)
 
2199
        self.assertLength(4, self.hpss_calls)
1716
2200
 
1717
2201
 
1718
2202
class TestTransportIsReadonly(tests.TestCase):
1719
2203
 
1720
2204
    def test_true(self):
1721
2205
        client = FakeClient()
1722
 
        client.add_success_response('yes')
 
2206
        client.add_success_response(b'yes')
1723
2207
        transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2208
                                    _client=client)
1725
2209
        self.assertEqual(True, transport.is_readonly())
1726
2210
        self.assertEqual(
1727
 
            [('call', 'Transport.is_readonly', ())],
 
2211
            [('call', b'Transport.is_readonly', ())],
1728
2212
            client._calls)
1729
2213
 
1730
2214
    def test_false(self):
1731
2215
        client = FakeClient()
1732
 
        client.add_success_response('no')
 
2216
        client.add_success_response(b'no')
1733
2217
        transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2218
                                    _client=client)
1735
2219
        self.assertEqual(False, transport.is_readonly())
1736
2220
        self.assertEqual(
1737
 
            [('call', 'Transport.is_readonly', ())],
 
2221
            [('call', b'Transport.is_readonly', ())],
1738
2222
            client._calls)
1739
2223
 
1740
2224
    def test_error_from_old_server(self):
1745
2229
        underlying filesystem could be readonly anyway).
1746
2230
        """
1747
2231
        client = FakeClient()
1748
 
        client.add_unknown_method_response('Transport.is_readonly')
 
2232
        client.add_unknown_method_response(b'Transport.is_readonly')
1749
2233
        transport = RemoteTransport('bzr://example.com/', medium=False,
1750
2234
                                    _client=client)
1751
2235
        self.assertEqual(False, transport.is_readonly())
1752
2236
        self.assertEqual(
1753
 
            [('call', 'Transport.is_readonly', ())],
 
2237
            [('call', b'Transport.is_readonly', ())],
1754
2238
            client._calls)
1755
2239
 
1756
2240
 
1758
2242
 
1759
2243
    def test_permissiondenied(self):
1760
2244
        client = FakeClient()
1761
 
        client.add_error_response('PermissionDenied', 'remote path', 'extra')
 
2245
        client.add_error_response(b'PermissionDenied', b'remote path', b'extra')
1762
2246
        transport = RemoteTransport('bzr://example.com/', medium=False,
1763
2247
                                    _client=client)
1764
2248
        exc = self.assertRaises(
1805
2289
        client = FakeClient(transport.base)
1806
2290
        transport = transport.clone(transport_path)
1807
2291
        # we do not want bzrdir to make any remote calls
1808
 
        bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
 
2292
        bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1809
2293
            _client=False)
1810
2294
        repo = RemoteRepository(bzrdir, None, _client=client)
1811
2295
        return repo, client
1819
2303
 
1820
2304
    def test_get_format_description(self):
1821
2305
        remote_format = RemoteBranchFormat()
1822
 
        real_format = branch.BranchFormat.get_default_format()
 
2306
        real_format = branch.format_registry.get_default()
1823
2307
        remote_format._network_name = real_format.network_name()
1824
2308
        self.assertEqual(remoted_description(real_format),
1825
2309
            remote_format.get_format_description())
1828
2312
class TestRepositoryFormat(TestRemoteRepository):
1829
2313
 
1830
2314
    def test_fast_delta(self):
1831
 
        true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
 
2315
        true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2316
        true_format = RemoteRepositoryFormat()
1833
2317
        true_format._network_name = true_name
1834
2318
        self.assertEqual(True, true_format.fast_deltas)
1835
 
        false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
 
2319
        false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2320
        false_format = RemoteRepositoryFormat()
1837
2321
        false_format._network_name = false_name
1838
2322
        self.assertEqual(False, false_format.fast_deltas)
1839
2323
 
1840
2324
    def test_get_format_description(self):
1841
2325
        remote_repo_format = RemoteRepositoryFormat()
1842
 
        real_format = repository.RepositoryFormat.get_default_format()
 
2326
        real_format = repository.format_registry.get_default()
1843
2327
        remote_repo_format._network_name = real_format.network_name()
1844
2328
        self.assertEqual(remoted_description(real_format),
1845
2329
            remote_repo_format.get_format_description())
1846
2330
 
1847
2331
 
 
2332
class TestRepositoryAllRevisionIds(TestRemoteRepository):
 
2333
 
 
2334
    def test_empty(self):
 
2335
        transport_path = 'quack'
 
2336
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2337
        client.add_success_response_with_body(b'', b'ok')
 
2338
        self.assertEqual([], repo.all_revision_ids())
 
2339
        self.assertEqual(
 
2340
            [('call_expecting_body', b'Repository.all_revision_ids',
 
2341
             (b'quack/',))],
 
2342
            client._calls)
 
2343
 
 
2344
    def test_with_some_content(self):
 
2345
        transport_path = 'quack'
 
2346
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2347
        client.add_success_response_with_body(
 
2348
            b'rev1\nrev2\nanotherrev\n', b'ok')
 
2349
        self.assertEqual([b"rev1", b"rev2", b"anotherrev"],
 
2350
            repo.all_revision_ids())
 
2351
        self.assertEqual(
 
2352
            [('call_expecting_body', b'Repository.all_revision_ids',
 
2353
             (b'quack/',))],
 
2354
            client._calls)
 
2355
 
 
2356
 
1848
2357
class TestRepositoryGatherStats(TestRemoteRepository):
1849
2358
 
1850
2359
    def test_revid_none(self):
1852
2361
        transport_path = 'quack'
1853
2362
        repo, client = self.setup_fake_client_and_repository(transport_path)
1854
2363
        client.add_success_response_with_body(
1855
 
            'revisions: 2\nsize: 18\n', 'ok')
 
2364
            b'revisions: 2\nsize: 18\n', b'ok')
1856
2365
        result = repo.gather_stats(None)
1857
2366
        self.assertEqual(
1858
 
            [('call_expecting_body', 'Repository.gather_stats',
1859
 
             ('quack/','','no'))],
 
2367
            [('call_expecting_body', b'Repository.gather_stats',
 
2368
             (b'quack/', b'', b'no'))],
1860
2369
            client._calls)
1861
2370
        self.assertEqual({'revisions': 2, 'size': 18}, result)
1862
2371
 
1863
2372
    def test_revid_no_committers(self):
1864
2373
        # ('ok',), body without committers
1865
 
        body = ('firstrev: 123456.300 3600\n'
1866
 
                'latestrev: 654231.400 0\n'
1867
 
                'revisions: 2\n'
1868
 
                'size: 18\n')
 
2374
        body = (b'firstrev: 123456.300 3600\n'
 
2375
                b'latestrev: 654231.400 0\n'
 
2376
                b'revisions: 2\n'
 
2377
                b'size: 18\n')
1869
2378
        transport_path = 'quick'
1870
2379
        revid = u'\xc8'.encode('utf8')
1871
2380
        repo, client = self.setup_fake_client_and_repository(transport_path)
1872
 
        client.add_success_response_with_body(body, 'ok')
 
2381
        client.add_success_response_with_body(body, b'ok')
1873
2382
        result = repo.gather_stats(revid)
1874
2383
        self.assertEqual(
1875
 
            [('call_expecting_body', 'Repository.gather_stats',
1876
 
              ('quick/', revid, 'no'))],
 
2384
            [('call_expecting_body', b'Repository.gather_stats',
 
2385
              (b'quick/', revid, b'no'))],
1877
2386
            client._calls)
1878
2387
        self.assertEqual({'revisions': 2, 'size': 18,
1879
2388
                          'firstrev': (123456.300, 3600),
1882
2391
 
1883
2392
    def test_revid_with_committers(self):
1884
2393
        # ('ok',), body with committers
1885
 
        body = ('committers: 128\n'
1886
 
                'firstrev: 123456.300 3600\n'
1887
 
                'latestrev: 654231.400 0\n'
1888
 
                'revisions: 2\n'
1889
 
                'size: 18\n')
 
2394
        body = (b'committers: 128\n'
 
2395
                b'firstrev: 123456.300 3600\n'
 
2396
                b'latestrev: 654231.400 0\n'
 
2397
                b'revisions: 2\n'
 
2398
                b'size: 18\n')
1890
2399
        transport_path = 'buick'
1891
2400
        revid = u'\xc8'.encode('utf8')
1892
2401
        repo, client = self.setup_fake_client_and_repository(transport_path)
1893
 
        client.add_success_response_with_body(body, 'ok')
 
2402
        client.add_success_response_with_body(body, b'ok')
1894
2403
        result = repo.gather_stats(revid, True)
1895
2404
        self.assertEqual(
1896
 
            [('call_expecting_body', 'Repository.gather_stats',
1897
 
              ('buick/', revid, 'yes'))],
 
2405
            [('call_expecting_body', b'Repository.gather_stats',
 
2406
              (b'buick/', revid, b'yes'))],
1898
2407
            client._calls)
1899
2408
        self.assertEqual({'revisions': 2, 'size': 18,
1900
2409
                          'committers': 128,
1903
2412
                         result)
1904
2413
 
1905
2414
 
 
2415
class TestRepositoryBreakLock(TestRemoteRepository):
 
2416
 
 
2417
    def test_break_lock(self):
 
2418
        transport_path = 'quack'
 
2419
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2420
        client.add_success_response(b'ok')
 
2421
        repo.break_lock()
 
2422
        self.assertEqual(
 
2423
            [('call', b'Repository.break_lock', (b'quack/',))],
 
2424
            client._calls)
 
2425
 
 
2426
 
 
2427
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
 
2428
 
 
2429
    def test_get_serializer_format(self):
 
2430
        transport_path = 'hill'
 
2431
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2432
        client.add_success_response(b'ok', b'7')
 
2433
        self.assertEqual(b'7', repo.get_serializer_format())
 
2434
        self.assertEqual(
 
2435
            [('call', b'VersionedFileRepository.get_serializer_format',
 
2436
              (b'hill/', ))],
 
2437
            client._calls)
 
2438
 
 
2439
 
 
2440
class TestRepositoryReconcile(TestRemoteRepository):
 
2441
 
 
2442
    def test_reconcile(self):
 
2443
        transport_path = 'hill'
 
2444
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2445
        body = (b"garbage_inventories: 2\n"
 
2446
                b"inconsistent_parents: 3\n")
 
2447
        client.add_expected_call(
 
2448
            b'Repository.lock_write', (b'hill/', b''),
 
2449
            b'success', (b'ok', b'a token'))
 
2450
        client.add_success_response_with_body(body, b'ok')
 
2451
        reconciler = repo.reconcile()
 
2452
        self.assertEqual(
 
2453
            [('call', b'Repository.lock_write', (b'hill/', b'')),
 
2454
             ('call_expecting_body', b'Repository.reconcile',
 
2455
                (b'hill/', b'a token'))],
 
2456
            client._calls)
 
2457
        self.assertEqual(2, reconciler.garbage_inventories)
 
2458
        self.assertEqual(3, reconciler.inconsistent_parents)
 
2459
 
 
2460
 
 
2461
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
 
2462
 
 
2463
    def test_text(self):
 
2464
        # ('ok',), body with signature text
 
2465
        transport_path = 'quack'
 
2466
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2467
        client.add_success_response_with_body(
 
2468
            b'THETEXT', b'ok')
 
2469
        self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
 
2470
        self.assertEqual(
 
2471
            [('call_expecting_body', b'Repository.get_revision_signature_text',
 
2472
             (b'quack/', b'revid'))],
 
2473
            client._calls)
 
2474
 
 
2475
    def test_no_signature(self):
 
2476
        transport_path = 'quick'
 
2477
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2478
        client.add_error_response(b'nosuchrevision', b'unknown')
 
2479
        self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
 
2480
                b"unknown")
 
2481
        self.assertEqual(
 
2482
            [('call_expecting_body', b'Repository.get_revision_signature_text',
 
2483
              (b'quick/', b'unknown'))],
 
2484
            client._calls)
 
2485
 
 
2486
 
1906
2487
class TestRepositoryGetGraph(TestRemoteRepository):
1907
2488
 
1908
2489
    def test_get_graph(self):
1913
2494
        self.assertNotEqual(graph._parents_provider, repo)
1914
2495
 
1915
2496
 
 
2497
class TestRepositoryAddSignatureText(TestRemoteRepository):
 
2498
 
 
2499
    def test_add_signature_text(self):
 
2500
        transport_path = 'quack'
 
2501
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2502
        client.add_expected_call(
 
2503
            b'Repository.lock_write', (b'quack/', b''),
 
2504
            b'success', (b'ok', b'a token'))
 
2505
        client.add_expected_call(
 
2506
            b'Repository.start_write_group', (b'quack/', b'a token'),
 
2507
            b'success', (b'ok', (b'token1', )))
 
2508
        client.add_expected_call(
 
2509
            b'Repository.add_signature_text', (b'quack/', b'a token', b'rev1',
 
2510
                b'token1'),
 
2511
            b'success', (b'ok', ), None)
 
2512
        repo.lock_write()
 
2513
        repo.start_write_group()
 
2514
        self.assertIs(None,
 
2515
            repo.add_signature_text(b"rev1", b"every bloody emperor"))
 
2516
        self.assertEqual(
 
2517
            ('call_with_body_bytes_expecting_body',
 
2518
              b'Repository.add_signature_text',
 
2519
                (b'quack/', b'a token', b'rev1', b'token1'),
 
2520
              b'every bloody emperor'),
 
2521
            client._calls[-1])
 
2522
 
 
2523
 
1916
2524
class TestRepositoryGetParentMap(TestRemoteRepository):
1917
2525
 
1918
2526
    def test_get_parent_map_caching(self):
1920
2528
        # setup a reponse with two revisions
1921
2529
        r1 = u'\u0e33'.encode('utf8')
1922
2530
        r2 = u'\u0dab'.encode('utf8')
1923
 
        lines = [' '.join([r2, r1]), r1]
1924
 
        encoded_body = bz2.compress('\n'.join(lines))
 
2531
        lines = [b' '.join([r2, r1]), r1]
 
2532
        encoded_body = bz2.compress(b'\n'.join(lines))
1925
2533
 
1926
2534
        transport_path = 'quack'
1927
2535
        repo, client = self.setup_fake_client_and_repository(transport_path)
1928
 
        client.add_success_response_with_body(encoded_body, 'ok')
1929
 
        client.add_success_response_with_body(encoded_body, 'ok')
 
2536
        client.add_success_response_with_body(encoded_body, b'ok')
 
2537
        client.add_success_response_with_body(encoded_body, b'ok')
1930
2538
        repo.lock_read()
1931
2539
        graph = repo.get_graph()
1932
2540
        parents = graph.get_parent_map([r2])
1938
2546
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
1939
2547
        self.assertEqual(
1940
2548
            [('call_with_body_bytes_expecting_body',
1941
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1942
 
              '\n\n0')],
 
2549
              b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
 
2550
              b'\n\n0')],
1943
2551
            client._calls)
1944
2552
        repo.unlock()
1945
2553
        # now we call again, and it should use the second response.
1949
2557
        self.assertEqual({r1: (NULL_REVISION,)}, parents)
1950
2558
        self.assertEqual(
1951
2559
            [('call_with_body_bytes_expecting_body',
1952
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
1953
 
              '\n\n0'),
 
2560
              b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
 
2561
              b'\n\n0'),
1954
2562
             ('call_with_body_bytes_expecting_body',
1955
 
              'Repository.get_parent_map', ('quack/', 'include-missing:', r1),
1956
 
              '\n\n0'),
 
2563
              b'Repository.get_parent_map', (b'quack/', b'include-missing:', r1),
 
2564
              b'\n\n0'),
1957
2565
            ],
1958
2566
            client._calls)
1959
2567
        repo.unlock()
1960
2568
 
1961
2569
    def test_get_parent_map_reconnects_if_unknown_method(self):
1962
2570
        transport_path = 'quack'
1963
 
        rev_id = 'revision-id'
 
2571
        rev_id = b'revision-id'
1964
2572
        repo, client = self.setup_fake_client_and_repository(transport_path)
1965
 
        client.add_unknown_method_response('Repository.get_parent_map')
1966
 
        client.add_success_response_with_body(rev_id, 'ok')
 
2573
        client.add_unknown_method_response(b'Repository.get_parent_map')
 
2574
        client.add_success_response_with_body(rev_id, b'ok')
1967
2575
        self.assertFalse(client._medium._is_remote_before((1, 2)))
1968
2576
        parents = repo.get_parent_map([rev_id])
1969
2577
        self.assertEqual(
1970
2578
            [('call_with_body_bytes_expecting_body',
1971
 
              'Repository.get_parent_map', ('quack/', 'include-missing:',
1972
 
              rev_id), '\n\n0'),
 
2579
              b'Repository.get_parent_map',
 
2580
              (b'quack/', b'include-missing:', rev_id), b'\n\n0'),
1973
2581
             ('disconnect medium',),
1974
 
             ('call_expecting_body', 'Repository.get_revision_graph',
1975
 
              ('quack/', ''))],
 
2582
             ('call_expecting_body', b'Repository.get_revision_graph',
 
2583
              (b'quack/', b''))],
1976
2584
            client._calls)
1977
2585
        # The medium is now marked as being connected to an older server
1978
2586
        self.assertTrue(client._medium._is_remote_before((1, 2)))
1979
 
        self.assertEqual({rev_id: ('null:',)}, parents)
 
2587
        self.assertEqual({rev_id: (b'null:',)}, parents)
1980
2588
 
1981
2589
    def test_get_parent_map_fallback_parentless_node(self):
1982
2590
        """get_parent_map falls back to get_revision_graph on old servers.  The
1989
2597
 
1990
2598
        This is the test for https://bugs.launchpad.net/bzr/+bug/214894
1991
2599
        """
1992
 
        rev_id = 'revision-id'
 
2600
        rev_id = b'revision-id'
1993
2601
        transport_path = 'quack'
1994
2602
        repo, client = self.setup_fake_client_and_repository(transport_path)
1995
 
        client.add_success_response_with_body(rev_id, 'ok')
 
2603
        client.add_success_response_with_body(rev_id, b'ok')
1996
2604
        client._medium._remember_remote_is_before((1, 2))
1997
2605
        parents = repo.get_parent_map([rev_id])
1998
2606
        self.assertEqual(
1999
 
            [('call_expecting_body', 'Repository.get_revision_graph',
2000
 
             ('quack/', ''))],
 
2607
            [('call_expecting_body', b'Repository.get_revision_graph',
 
2608
             (b'quack/', b''))],
2001
2609
            client._calls)
2002
 
        self.assertEqual({rev_id: ('null:',)}, parents)
 
2610
        self.assertEqual({rev_id: (b'null:',)}, parents)
2003
2611
 
2004
2612
    def test_get_parent_map_unexpected_response(self):
2005
2613
        repo, client = self.setup_fake_client_and_repository('path')
2006
 
        client.add_success_response('something unexpected!')
 
2614
        client.add_success_response(b'something unexpected!')
2007
2615
        self.assertRaises(
2008
2616
            errors.UnexpectedSmartServerResponse,
2009
 
            repo.get_parent_map, ['a-revision-id'])
 
2617
            repo.get_parent_map, [b'a-revision-id'])
2010
2618
 
2011
2619
    def test_get_parent_map_negative_caches_missing_keys(self):
2012
2620
        self.setup_smart_server_with_call_log()
2017
2625
        self.reset_smart_call_log()
2018
2626
        graph = repo.get_graph()
2019
2627
        self.assertEqual({},
2020
 
            graph.get_parent_map(['some-missing', 'other-missing']))
 
2628
            graph.get_parent_map([b'some-missing', b'other-missing']))
2021
2629
        self.assertLength(1, self.hpss_calls)
2022
2630
        # No call if we repeat this
2023
2631
        self.reset_smart_call_log()
2024
2632
        graph = repo.get_graph()
2025
2633
        self.assertEqual({},
2026
 
            graph.get_parent_map(['some-missing', 'other-missing']))
 
2634
            graph.get_parent_map([b'some-missing', b'other-missing']))
2027
2635
        self.assertLength(0, self.hpss_calls)
2028
2636
        # Asking for more unknown keys makes a request.
2029
2637
        self.reset_smart_call_log()
2030
2638
        graph = repo.get_graph()
2031
2639
        self.assertEqual({},
2032
 
            graph.get_parent_map(['some-missing', 'other-missing',
2033
 
                'more-missing']))
 
2640
            graph.get_parent_map([b'some-missing', b'other-missing',
 
2641
                b'more-missing']))
2034
2642
        self.assertLength(1, self.hpss_calls)
2035
2643
 
2036
2644
    def disableExtraResults(self):
2042
2650
        # Make a branch with a single revision.
2043
2651
        builder = self.make_branch_builder('foo')
2044
2652
        builder.start_series()
2045
 
        builder.build_snapshot('first', None, [
2046
 
            ('add', ('', 'root-id', 'directory', ''))])
 
2653
        builder.build_snapshot(None, [
 
2654
            ('add', ('', b'root-id', 'directory', ''))],
 
2655
            revision_id=b'first')
2047
2656
        builder.finish_series()
2048
2657
        branch = builder.get_branch()
2049
2658
        repo = branch.repository
2058
2667
        # 'first' it will be a candidate for the stop_keys of subsequent
2059
2668
        # requests, and because 'null:' was queried but not returned it will be
2060
2669
        # cached as missing.
2061
 
        self.assertEqual({'first': ('null:',)},
2062
 
            graph.get_parent_map(['first', 'null:']))
 
2670
        self.assertEqual({b'first': (b'null:',)},
 
2671
            graph.get_parent_map([b'first', b'null:']))
2063
2672
        # Now query for another key.  This request will pass along a recipe of
2064
2673
        # start and stop keys describing the already cached results, and this
2065
2674
        # recipe's revision count must be correct (or else it will trigger an
2066
2675
        # error from the server).
2067
 
        self.assertEqual({}, graph.get_parent_map(['another-key']))
 
2676
        self.assertEqual({}, graph.get_parent_map([b'another-key']))
2068
2677
        # This assertion guards against disableExtraResults silently failing to
2069
2678
        # work, thus invalidating the test.
2070
2679
        self.assertLength(2, self.hpss_calls)
2074
2683
        # ancestry.
2075
2684
        self.setup_smart_server_with_call_log()
2076
2685
        tree = self.make_branch_and_memory_tree('foo')
2077
 
        tree.lock_write()
2078
 
        try:
 
2686
        with tree.lock_write():
2079
2687
            builder = treebuilder.TreeBuilder()
2080
2688
            builder.start_tree(tree)
2081
2689
            builder.build([])
2082
2690
            builder.finish_tree()
2083
 
            tree.set_parent_ids(['non-existant'], allow_leftmost_as_ghost=True)
 
2691
            tree.set_parent_ids([b'non-existant'], allow_leftmost_as_ghost=True)
2084
2692
            rev_id = tree.commit('')
2085
 
        finally:
2086
 
            tree.unlock()
2087
2693
        tree.lock_read()
2088
2694
        self.addCleanup(tree.unlock)
2089
2695
        repo = tree.branch.repository
2092
2698
        repo.get_parent_map([rev_id])
2093
2699
        self.reset_smart_call_log()
2094
2700
        # Now asking for rev_id's ghost parent should not make calls
2095
 
        self.assertEqual({}, repo.get_parent_map(['non-existant']))
 
2701
        self.assertEqual({}, repo.get_parent_map([b'non-existant']))
2096
2702
        self.assertLength(0, self.hpss_calls)
2097
2703
 
 
2704
    def test_exposes_get_cached_parent_map(self):
 
2705
        """RemoteRepository exposes get_cached_parent_map from
 
2706
        _unstacked_provider
 
2707
        """
 
2708
        r1 = u'\u0e33'.encode('utf8')
 
2709
        r2 = u'\u0dab'.encode('utf8')
 
2710
        lines = [b' '.join([r2, r1]), r1]
 
2711
        encoded_body = bz2.compress(b'\n'.join(lines))
 
2712
 
 
2713
        transport_path = 'quack'
 
2714
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2715
        client.add_success_response_with_body(encoded_body, b'ok')
 
2716
        repo.lock_read()
 
2717
        # get_cached_parent_map should *not* trigger an RPC
 
2718
        self.assertEqual({}, repo.get_cached_parent_map([r1]))
 
2719
        self.assertEqual([], client._calls)
 
2720
        self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
 
2721
        self.assertEqual({r1: (NULL_REVISION,)},
 
2722
            repo.get_cached_parent_map([r1]))
 
2723
        self.assertEqual(
 
2724
            [('call_with_body_bytes_expecting_body',
 
2725
              b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
 
2726
              b'\n\n0')],
 
2727
            client._calls)
 
2728
        repo.unlock()
 
2729
 
2098
2730
 
2099
2731
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2100
2732
 
2109
2741
        self.addCleanup(tree.unlock)
2110
2742
        graph = tree.branch.repository.get_graph()
2111
2743
        # This provides an opportunity for the missing rev-id to be cached.
2112
 
        self.assertEqual({}, graph.get_parent_map(['rev1']))
2113
 
        tree.commit('message', rev_id='rev1')
 
2744
        self.assertEqual({}, graph.get_parent_map([b'rev1']))
 
2745
        tree.commit('message', rev_id=b'rev1')
2114
2746
        graph = tree.branch.repository.get_graph()
2115
 
        self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
 
2747
        self.assertEqual({b'rev1': (b'null:',)}, graph.get_parent_map([b'rev1']))
 
2748
 
 
2749
 
 
2750
class TestRepositoryGetRevisions(TestRemoteRepository):
 
2751
 
 
2752
    def test_hpss_missing_revision(self):
 
2753
        transport_path = 'quack'
 
2754
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2755
        client.add_success_response_with_body(
 
2756
            b'', b'ok', b'10')
 
2757
        self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
 
2758
            [b'somerev1', b'anotherrev2'])
 
2759
        self.assertEqual(
 
2760
            [('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
 
2761
             (b'quack/', ), b"somerev1\nanotherrev2")],
 
2762
            client._calls)
 
2763
 
 
2764
    def test_hpss_get_single_revision(self):
 
2765
        transport_path = 'quack'
 
2766
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2767
        somerev1 = Revision(b"somerev1")
 
2768
        somerev1.committer = "Joe Committer <joe@example.com>"
 
2769
        somerev1.timestamp = 1321828927
 
2770
        somerev1.timezone = -60
 
2771
        somerev1.inventory_sha1 = b"691b39be74c67b1212a75fcb19c433aaed903c2b"
 
2772
        somerev1.message = "Message"
 
2773
        body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
 
2774
            somerev1))
 
2775
        # Split up body into two bits to make sure the zlib compression object
 
2776
        # gets data fed twice.
 
2777
        client.add_success_response_with_body(
 
2778
                [body[:10], body[10:]], b'ok', b'10')
 
2779
        revs = repo.get_revisions([b'somerev1'])
 
2780
        self.assertEqual(revs, [somerev1])
 
2781
        self.assertEqual(
 
2782
            [('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
 
2783
             (b'quack/', ), b"somerev1")],
 
2784
            client._calls)
2116
2785
 
2117
2786
 
2118
2787
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2122
2791
        # traffic when calling it with this argument
2123
2792
        transport_path = 'empty'
2124
2793
        repo, client = self.setup_fake_client_and_repository(transport_path)
2125
 
        client.add_success_response('notused')
 
2794
        client.add_success_response(b'notused')
2126
2795
        # actual RemoteRepository.get_revision_graph is gone, but there's an
2127
2796
        # equivalent private method for testing
2128
2797
        result = repo._get_revision_graph(NULL_REVISION)
2133
2802
        # with none we want the entire graph
2134
2803
        r1 = u'\u0e33'.encode('utf8')
2135
2804
        r2 = u'\u0dab'.encode('utf8')
2136
 
        lines = [' '.join([r2, r1]), r1]
2137
 
        encoded_body = '\n'.join(lines)
 
2805
        lines = [b' '.join([r2, r1]), r1]
 
2806
        encoded_body = b'\n'.join(lines)
2138
2807
 
2139
2808
        transport_path = 'sinhala'
2140
2809
        repo, client = self.setup_fake_client_and_repository(transport_path)
2141
 
        client.add_success_response_with_body(encoded_body, 'ok')
 
2810
        client.add_success_response_with_body(encoded_body, b'ok')
2142
2811
        # actual RemoteRepository.get_revision_graph is gone, but there's an
2143
2812
        # equivalent private method for testing
2144
2813
        result = repo._get_revision_graph(None)
2145
2814
        self.assertEqual(
2146
 
            [('call_expecting_body', 'Repository.get_revision_graph',
2147
 
             ('sinhala/', ''))],
 
2815
            [('call_expecting_body', b'Repository.get_revision_graph',
 
2816
             (b'sinhala/', b''))],
2148
2817
            client._calls)
2149
2818
        self.assertEqual({r1: (), r2: (r1, )}, result)
2150
2819
 
2154
2823
        r11 = u'\u0e33'.encode('utf8')
2155
2824
        r12 = u'\xc9'.encode('utf8')
2156
2825
        r2 = u'\u0dab'.encode('utf8')
2157
 
        lines = [' '.join([r2, r11, r12]), r11, r12]
2158
 
        encoded_body = '\n'.join(lines)
 
2826
        lines = [b' '.join([r2, r11, r12]), r11, r12]
 
2827
        encoded_body = b'\n'.join(lines)
2159
2828
 
2160
2829
        transport_path = 'sinhala'
2161
2830
        repo, client = self.setup_fake_client_and_repository(transport_path)
2162
 
        client.add_success_response_with_body(encoded_body, 'ok')
 
2831
        client.add_success_response_with_body(encoded_body, b'ok')
2163
2832
        result = repo._get_revision_graph(r2)
2164
2833
        self.assertEqual(
2165
 
            [('call_expecting_body', 'Repository.get_revision_graph',
2166
 
             ('sinhala/', r2))],
 
2834
            [('call_expecting_body', b'Repository.get_revision_graph',
 
2835
             (b'sinhala/', r2))],
2167
2836
            client._calls)
2168
2837
        self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2169
2838
 
2170
2839
    def test_no_such_revision(self):
2171
 
        revid = '123'
 
2840
        revid = b'123'
2172
2841
        transport_path = 'sinhala'
2173
2842
        repo, client = self.setup_fake_client_and_repository(transport_path)
2174
 
        client.add_error_response('nosuchrevision', revid)
 
2843
        client.add_error_response(b'nosuchrevision', revid)
2175
2844
        # also check that the right revision is reported in the error
2176
2845
        self.assertRaises(errors.NoSuchRevision,
2177
2846
            repo._get_revision_graph, revid)
2178
2847
        self.assertEqual(
2179
 
            [('call_expecting_body', 'Repository.get_revision_graph',
2180
 
             ('sinhala/', revid))],
 
2848
            [('call_expecting_body', b'Repository.get_revision_graph',
 
2849
             (b'sinhala/', revid))],
2181
2850
            client._calls)
2182
2851
 
2183
2852
    def test_unexpected_error(self):
2184
2853
        revid = '123'
2185
2854
        transport_path = 'sinhala'
2186
2855
        repo, client = self.setup_fake_client_and_repository(transport_path)
2187
 
        client.add_error_response('AnUnexpectedError')
 
2856
        client.add_error_response(b'AnUnexpectedError')
2188
2857
        e = self.assertRaises(errors.UnknownErrorFromSmartServer,
2189
2858
            repo._get_revision_graph, revid)
2190
 
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
 
2859
        self.assertEqual((b'AnUnexpectedError',), e.error_tuple)
2191
2860
 
2192
2861
 
2193
2862
class TestRepositoryGetRevIdForRevno(TestRemoteRepository):
2195
2864
    def test_ok(self):
2196
2865
        repo, client = self.setup_fake_client_and_repository('quack')
2197
2866
        client.add_expected_call(
2198
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2199
 
            'success', ('ok', 'rev-five'))
2200
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2201
 
        self.assertEqual((True, 'rev-five'), result)
 
2867
            b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
 
2868
            b'success', (b'ok', b'rev-five'))
 
2869
        result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
 
2870
        self.assertEqual((True, b'rev-five'), result)
2202
2871
        self.assertFinished(client)
2203
2872
 
2204
2873
    def test_history_incomplete(self):
2205
2874
        repo, client = self.setup_fake_client_and_repository('quack')
2206
2875
        client.add_expected_call(
2207
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2208
 
            'success', ('history-incomplete', 10, 'rev-ten'))
2209
 
        result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2210
 
        self.assertEqual((False, (10, 'rev-ten')), result)
 
2876
            b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
 
2877
            b'success', (b'history-incomplete', 10, b'rev-ten'))
 
2878
        result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
 
2879
        self.assertEqual((False, (10, b'rev-ten')), result)
2211
2880
        self.assertFinished(client)
2212
2881
 
2213
2882
    def test_history_incomplete_with_fallback(self):
2216
2885
        """
2217
2886
        # Make a repo with a fallback repo, both using a FakeClient.
2218
2887
        format = remote.response_tuple_to_repo_format(
2219
 
            ('yes', 'no', 'yes', self.get_repo_format().network_name()))
 
2888
            (b'yes', b'no', b'yes', self.get_repo_format().network_name()))
2220
2889
        repo, client = self.setup_fake_client_and_repository('quack')
2221
2890
        repo._format = format
2222
2891
        fallback_repo, ignored = self.setup_fake_client_and_repository(
2226
2895
        repo.add_fallback_repository(fallback_repo)
2227
2896
        # First the client should ask the primary repo
2228
2897
        client.add_expected_call(
2229
 
            'Repository.get_rev_id_for_revno', ('quack/', 1, (42, 'rev-foo')),
2230
 
            'success', ('history-incomplete', 2, 'rev-two'))
 
2898
            b'Repository.get_rev_id_for_revno', (b'quack/', 1, (42, b'rev-foo')),
 
2899
            b'success', (b'history-incomplete', 2, b'rev-two'))
2231
2900
        # Then it should ask the fallback, using revno/revid from the
2232
2901
        # history-incomplete response as the known revno/revid.
2233
2902
        client.add_expected_call(
2234
 
            'Repository.get_rev_id_for_revno',('fallback/', 1, (2, 'rev-two')),
2235
 
            'success', ('ok', 'rev-one'))
2236
 
        result = repo.get_rev_id_for_revno(1, (42, 'rev-foo'))
2237
 
        self.assertEqual((True, 'rev-one'), result)
 
2903
            b'Repository.get_rev_id_for_revno', (b'fallback/', 1, (2, b'rev-two')),
 
2904
            b'success', (b'ok', b'rev-one'))
 
2905
        result = repo.get_rev_id_for_revno(1, (42, b'rev-foo'))
 
2906
        self.assertEqual((True, b'rev-one'), result)
2238
2907
        self.assertFinished(client)
2239
2908
 
2240
2909
    def test_nosuchrevision(self):
2242
2911
        # remote repo.  The client translates that response to NoSuchRevision.
2243
2912
        repo, client = self.setup_fake_client_and_repository('quack')
2244
2913
        client.add_expected_call(
2245
 
            'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2246
 
            'error', ('nosuchrevision', 'rev-foo'))
 
2914
            b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
 
2915
            b'error', (b'nosuchrevision', b'rev-foo'))
2247
2916
        self.assertRaises(
2248
2917
            errors.NoSuchRevision,
2249
 
            repo.get_rev_id_for_revno, 5, (42, 'rev-foo'))
 
2918
            repo.get_rev_id_for_revno, 5, (42, b'rev-foo'))
2250
2919
        self.assertFinished(client)
2251
2920
 
2252
2921
    def test_branch_fallback_locking(self):
2257
2926
        self.setup_smart_server_with_call_log()
2258
2927
        tree = self.make_branch_and_memory_tree('.')
2259
2928
        tree.lock_write()
 
2929
        tree.add('')
2260
2930
        rev1 = tree.commit('First')
2261
2931
        rev2 = tree.commit('Second')
2262
2932
        tree.unlock()
2263
2933
        branch = tree.branch
2264
2934
        self.assertFalse(branch.is_locked())
2265
2935
        self.reset_smart_call_log()
2266
 
        verb = 'Repository.get_rev_id_for_revno'
 
2936
        verb = b'Repository.get_rev_id_for_revno'
2267
2937
        self.disable_verb(verb)
2268
2938
        self.assertEqual(rev1, branch.get_rev_id(1))
2269
2939
        self.assertLength(1, [call for call in self.hpss_calls if
2270
2940
                              call.call.method == verb])
2271
2941
 
2272
2942
 
 
2943
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
 
2944
 
 
2945
    def test_has_signature_for_revision_id(self):
 
2946
        # ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
 
2947
        transport_path = 'quack'
 
2948
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2949
        client.add_success_response(b'yes')
 
2950
        result = repo.has_signature_for_revision_id(b'A')
 
2951
        self.assertEqual(
 
2952
            [('call', b'Repository.has_signature_for_revision_id',
 
2953
              (b'quack/', b'A'))],
 
2954
            client._calls)
 
2955
        self.assertEqual(True, result)
 
2956
 
 
2957
    def test_is_not_shared(self):
 
2958
        # ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
 
2959
        transport_path = 'qwack'
 
2960
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2961
        client.add_success_response(b'no')
 
2962
        result = repo.has_signature_for_revision_id(b'A')
 
2963
        self.assertEqual(
 
2964
            [('call', b'Repository.has_signature_for_revision_id',
 
2965
              (b'qwack/', b'A'))],
 
2966
            client._calls)
 
2967
        self.assertEqual(False, result)
 
2968
 
 
2969
 
 
2970
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
 
2971
 
 
2972
    def test_get_physical_lock_status_yes(self):
 
2973
        transport_path = 'qwack'
 
2974
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2975
        client.add_success_response(b'yes')
 
2976
        result = repo.get_physical_lock_status()
 
2977
        self.assertEqual(
 
2978
            [('call', b'Repository.get_physical_lock_status',
 
2979
              (b'qwack/', ))],
 
2980
            client._calls)
 
2981
        self.assertEqual(True, result)
 
2982
 
 
2983
    def test_get_physical_lock_status_no(self):
 
2984
        transport_path = 'qwack'
 
2985
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
2986
        client.add_success_response(b'no')
 
2987
        result = repo.get_physical_lock_status()
 
2988
        self.assertEqual(
 
2989
            [('call', b'Repository.get_physical_lock_status',
 
2990
              (b'qwack/', ))],
 
2991
            client._calls)
 
2992
        self.assertEqual(False, result)
 
2993
 
 
2994
 
2273
2995
class TestRepositoryIsShared(TestRemoteRepository):
2274
2996
 
2275
2997
    def test_is_shared(self):
2276
2998
        # ('yes', ) for Repository.is_shared -> 'True'.
2277
2999
        transport_path = 'quack'
2278
3000
        repo, client = self.setup_fake_client_and_repository(transport_path)
2279
 
        client.add_success_response('yes')
 
3001
        client.add_success_response(b'yes')
2280
3002
        result = repo.is_shared()
2281
3003
        self.assertEqual(
2282
 
            [('call', 'Repository.is_shared', ('quack/',))],
 
3004
            [('call', b'Repository.is_shared', (b'quack/',))],
2283
3005
            client._calls)
2284
3006
        self.assertEqual(True, result)
2285
3007
 
2287
3009
        # ('no', ) for Repository.is_shared -> 'False'.
2288
3010
        transport_path = 'qwack'
2289
3011
        repo, client = self.setup_fake_client_and_repository(transport_path)
2290
 
        client.add_success_response('no')
 
3012
        client.add_success_response(b'no')
2291
3013
        result = repo.is_shared()
2292
3014
        self.assertEqual(
2293
 
            [('call', 'Repository.is_shared', ('qwack/',))],
 
3015
            [('call', b'Repository.is_shared', (b'qwack/',))],
 
3016
            client._calls)
 
3017
        self.assertEqual(False, result)
 
3018
 
 
3019
 
 
3020
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
 
3021
 
 
3022
    def test_make_working_trees(self):
 
3023
        # ('yes', ) for Repository.make_working_trees -> 'True'.
 
3024
        transport_path = 'quack'
 
3025
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3026
        client.add_success_response(b'yes')
 
3027
        result = repo.make_working_trees()
 
3028
        self.assertEqual(
 
3029
            [('call', b'Repository.make_working_trees', (b'quack/',))],
 
3030
            client._calls)
 
3031
        self.assertEqual(True, result)
 
3032
 
 
3033
    def test_no_working_trees(self):
 
3034
        # ('no', ) for Repository.make_working_trees -> 'False'.
 
3035
        transport_path = 'qwack'
 
3036
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3037
        client.add_success_response(b'no')
 
3038
        result = repo.make_working_trees()
 
3039
        self.assertEqual(
 
3040
            [('call', b'Repository.make_working_trees', (b'qwack/',))],
2294
3041
            client._calls)
2295
3042
        self.assertEqual(False, result)
2296
3043
 
2300
3047
    def test_lock_write(self):
2301
3048
        transport_path = 'quack'
2302
3049
        repo, client = self.setup_fake_client_and_repository(transport_path)
2303
 
        client.add_success_response('ok', 'a token')
2304
 
        result = repo.lock_write()
 
3050
        client.add_success_response(b'ok', b'a token')
 
3051
        token = repo.lock_write().repository_token
2305
3052
        self.assertEqual(
2306
 
            [('call', 'Repository.lock_write', ('quack/', ''))],
 
3053
            [('call', b'Repository.lock_write', (b'quack/', b''))],
2307
3054
            client._calls)
2308
 
        self.assertEqual('a token', result)
 
3055
        self.assertEqual(b'a token', token)
2309
3056
 
2310
3057
    def test_lock_write_already_locked(self):
2311
3058
        transport_path = 'quack'
2312
3059
        repo, client = self.setup_fake_client_and_repository(transport_path)
2313
 
        client.add_error_response('LockContention')
 
3060
        client.add_error_response(b'LockContention')
2314
3061
        self.assertRaises(errors.LockContention, repo.lock_write)
2315
3062
        self.assertEqual(
2316
 
            [('call', 'Repository.lock_write', ('quack/', ''))],
 
3063
            [('call', b'Repository.lock_write', (b'quack/', b''))],
2317
3064
            client._calls)
2318
3065
 
2319
3066
    def test_lock_write_unlockable(self):
2320
3067
        transport_path = 'quack'
2321
3068
        repo, client = self.setup_fake_client_and_repository(transport_path)
2322
 
        client.add_error_response('UnlockableTransport')
 
3069
        client.add_error_response(b'UnlockableTransport')
2323
3070
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3071
        self.assertEqual(
2325
 
            [('call', 'Repository.lock_write', ('quack/', ''))],
 
3072
            [('call', b'Repository.lock_write', (b'quack/', b''))],
2326
3073
            client._calls)
2327
3074
 
2328
3075
 
 
3076
class TestRepositoryWriteGroups(TestRemoteRepository):
 
3077
 
 
3078
    def test_start_write_group(self):
 
3079
        transport_path = 'quack'
 
3080
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3081
        client.add_expected_call(
 
3082
            b'Repository.lock_write', (b'quack/', b''),
 
3083
            b'success', (b'ok', b'a token'))
 
3084
        client.add_expected_call(
 
3085
            b'Repository.start_write_group', (b'quack/', b'a token'),
 
3086
            b'success', (b'ok', (b'token1', )))
 
3087
        repo.lock_write()
 
3088
        repo.start_write_group()
 
3089
 
 
3090
    def test_start_write_group_unsuspendable(self):
 
3091
        # Some repositories do not support suspending write
 
3092
        # groups. For those, fall back to the "real" repository.
 
3093
        transport_path = 'quack'
 
3094
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3095
        def stub_ensure_real():
 
3096
            client._calls.append(('_ensure_real',))
 
3097
            repo._real_repository = _StubRealPackRepository(client._calls)
 
3098
        repo._ensure_real = stub_ensure_real
 
3099
        client.add_expected_call(
 
3100
            b'Repository.lock_write', (b'quack/', b''),
 
3101
            b'success', (b'ok', b'a token'))
 
3102
        client.add_expected_call(
 
3103
            b'Repository.start_write_group', (b'quack/', b'a token'),
 
3104
            b'error', (b'UnsuspendableWriteGroup',))
 
3105
        repo.lock_write()
 
3106
        repo.start_write_group()
 
3107
        self.assertEqual(client._calls[-2:], [
 
3108
            ('_ensure_real',),
 
3109
            ('start_write_group',)])
 
3110
 
 
3111
    def test_commit_write_group(self):
 
3112
        transport_path = 'quack'
 
3113
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3114
        client.add_expected_call(
 
3115
            b'Repository.lock_write', (b'quack/', b''),
 
3116
            b'success', (b'ok', b'a token'))
 
3117
        client.add_expected_call(
 
3118
            b'Repository.start_write_group', (b'quack/', b'a token'),
 
3119
            b'success', (b'ok', [b'token1']))
 
3120
        client.add_expected_call(
 
3121
            b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
 
3122
            b'success', (b'ok',))
 
3123
        repo.lock_write()
 
3124
        repo.start_write_group()
 
3125
        repo.commit_write_group()
 
3126
 
 
3127
    def test_abort_write_group(self):
 
3128
        transport_path = 'quack'
 
3129
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3130
        client.add_expected_call(
 
3131
            b'Repository.lock_write', (b'quack/', b''),
 
3132
            b'success', (b'ok', b'a token'))
 
3133
        client.add_expected_call(
 
3134
            b'Repository.start_write_group', (b'quack/', b'a token'),
 
3135
            b'success', (b'ok', [b'token1']))
 
3136
        client.add_expected_call(
 
3137
            b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
 
3138
            b'success', (b'ok',))
 
3139
        repo.lock_write()
 
3140
        repo.start_write_group()
 
3141
        repo.abort_write_group(False)
 
3142
 
 
3143
    def test_suspend_write_group(self):
 
3144
        transport_path = 'quack'
 
3145
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3146
        self.assertEqual([], repo.suspend_write_group())
 
3147
 
 
3148
    def test_resume_write_group(self):
 
3149
        transport_path = 'quack'
 
3150
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3151
        client.add_expected_call(
 
3152
            b'Repository.lock_write', (b'quack/', b''),
 
3153
            b'success', (b'ok', b'a token'))
 
3154
        client.add_expected_call(
 
3155
            b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
 
3156
            b'success', (b'ok',))
 
3157
        repo.lock_write()
 
3158
        repo.resume_write_group([b'token1'])
 
3159
 
 
3160
 
2329
3161
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2330
3162
 
2331
3163
    def test_backwards_compat(self):
2332
3164
        self.setup_smart_server_with_call_log()
2333
3165
        repo = self.make_repository('.')
2334
3166
        self.reset_smart_call_log()
2335
 
        verb = 'Repository.set_make_working_trees'
 
3167
        verb = b'Repository.set_make_working_trees'
2336
3168
        self.disable_verb(verb)
2337
3169
        repo.set_make_working_trees(True)
2338
3170
        call_count = len([call for call in self.hpss_calls if
2343
3175
        transport_path = 'quack'
2344
3176
        repo, client = self.setup_fake_client_and_repository(transport_path)
2345
3177
        client.add_expected_call(
2346
 
            'Repository.set_make_working_trees', ('quack/', 'True'),
2347
 
            'success', ('ok',))
 
3178
            b'Repository.set_make_working_trees', (b'quack/', b'True'),
 
3179
            b'success', (b'ok',))
2348
3180
        client.add_expected_call(
2349
 
            'Repository.set_make_working_trees', ('quack/', 'False'),
2350
 
            'success', ('ok',))
 
3181
            b'Repository.set_make_working_trees', (b'quack/', b'False'),
 
3182
            b'success', (b'ok',))
2351
3183
        repo.set_make_working_trees(True)
2352
3184
        repo.set_make_working_trees(False)
2353
3185
 
2357
3189
    def test_unlock(self):
2358
3190
        transport_path = 'quack'
2359
3191
        repo, client = self.setup_fake_client_and_repository(transport_path)
2360
 
        client.add_success_response('ok', 'a token')
2361
 
        client.add_success_response('ok')
 
3192
        client.add_success_response(b'ok', b'a token')
 
3193
        client.add_success_response(b'ok')
2362
3194
        repo.lock_write()
2363
3195
        repo.unlock()
2364
3196
        self.assertEqual(
2365
 
            [('call', 'Repository.lock_write', ('quack/', '')),
2366
 
             ('call', 'Repository.unlock', ('quack/', 'a token'))],
 
3197
            [('call', b'Repository.lock_write', (b'quack/', b'')),
 
3198
             ('call', b'Repository.unlock', (b'quack/', b'a token'))],
2367
3199
            client._calls)
2368
3200
 
2369
3201
    def test_unlock_wrong_token(self):
2370
3202
        # If somehow the token is wrong, unlock will raise TokenMismatch.
2371
3203
        transport_path = 'quack'
2372
3204
        repo, client = self.setup_fake_client_and_repository(transport_path)
2373
 
        client.add_success_response('ok', 'a token')
2374
 
        client.add_error_response('TokenMismatch')
 
3205
        client.add_success_response(b'ok', b'a token')
 
3206
        client.add_error_response(b'TokenMismatch')
2375
3207
        repo.lock_write()
2376
3208
        self.assertRaises(errors.TokenMismatch, repo.unlock)
2377
3209
 
2390
3222
        self.assertEqual([], client._calls)
2391
3223
 
2392
3224
 
 
3225
class TestRepositoryIterFilesBytes(TestRemoteRepository):
 
3226
    """Test Repository.iter_file_bytes."""
 
3227
 
 
3228
    def test_single(self):
 
3229
        transport_path = 'quack'
 
3230
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3231
        client.add_expected_call(
 
3232
            b'Repository.iter_files_bytes', (b'quack/', ),
 
3233
            b'success', (b'ok',), iter([b"ok\x000", b"\n", zlib.compress(b"mydata" * 10)]))
 
3234
        for (identifier, byte_stream) in repo.iter_files_bytes([(b"somefile",
 
3235
                b"somerev", b"myid")]):
 
3236
            self.assertEqual(b"myid", identifier)
 
3237
            self.assertEqual(b"".join(byte_stream), b"mydata" * 10)
 
3238
 
 
3239
    def test_missing(self):
 
3240
        transport_path = 'quack'
 
3241
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3242
        client.add_expected_call(
 
3243
            b'Repository.iter_files_bytes',
 
3244
                (b'quack/', ),
 
3245
            b'error', (b'RevisionNotPresent', b'somefile', b'somerev'),
 
3246
            iter([b"absent\0somefile\0somerev\n"]))
 
3247
        self.assertRaises(errors.RevisionNotPresent, list,
 
3248
                repo.iter_files_bytes(
 
3249
                [(b"somefile", b"somerev", b"myid")]))
 
3250
 
 
3251
 
2393
3252
class TestRepositoryInsertStreamBase(TestRemoteRepository):
2394
3253
    """Base class for Repository.insert_stream and .insert_stream_1.19
2395
3254
    tests.
2402
3261
        the client is finished.
2403
3262
        """
2404
3263
        sink = repo._get_sink()
2405
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3264
        fmt = repository.format_registry.get_default()
2406
3265
        resume_tokens, missing_keys = sink.insert_stream([], fmt, [])
2407
3266
        self.assertEqual([], resume_tokens)
2408
3267
        self.assertEqual(set(), missing_keys)
2417
3276
    """
2418
3277
 
2419
3278
    def setUp(self):
2420
 
        TestRemoteRepository.setUp(self)
2421
 
        self.disable_verb('Repository.insert_stream_1.19')
 
3279
        super(TestRepositoryInsertStream, self).setUp()
 
3280
        self.disable_verb(b'Repository.insert_stream_1.19')
2422
3281
 
2423
3282
    def test_unlocked_repo(self):
2424
3283
        transport_path = 'quack'
2425
3284
        repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3285
        client.add_expected_call(
2427
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2428
 
            'unknown', ('Repository.insert_stream_1.19',))
2429
 
        client.add_expected_call(
2430
 
            'Repository.insert_stream', ('quack/', ''),
2431
 
            'success', ('ok',))
2432
 
        client.add_expected_call(
2433
 
            'Repository.insert_stream', ('quack/', ''),
2434
 
            'success', ('ok',))
 
3286
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3287
            b'unknown', (b'Repository.insert_stream_1.19',))
 
3288
        client.add_expected_call(
 
3289
            b'Repository.insert_stream', (b'quack/', b''),
 
3290
            b'success', (b'ok',))
 
3291
        client.add_expected_call(
 
3292
            b'Repository.insert_stream', (b'quack/', b''),
 
3293
            b'success', (b'ok',))
2435
3294
        self.checkInsertEmptyStream(repo, client)
2436
3295
 
2437
3296
    def test_locked_repo_with_no_lock_token(self):
2438
3297
        transport_path = 'quack'
2439
3298
        repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3299
        client.add_expected_call(
2441
 
            'Repository.lock_write', ('quack/', ''),
2442
 
            'success', ('ok', ''))
2443
 
        client.add_expected_call(
2444
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2445
 
            'unknown', ('Repository.insert_stream_1.19',))
2446
 
        client.add_expected_call(
2447
 
            'Repository.insert_stream', ('quack/', ''),
2448
 
            'success', ('ok',))
2449
 
        client.add_expected_call(
2450
 
            'Repository.insert_stream', ('quack/', ''),
2451
 
            'success', ('ok',))
 
3300
            b'Repository.lock_write', (b'quack/', b''),
 
3301
            b'success', (b'ok', b''))
 
3302
        client.add_expected_call(
 
3303
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3304
            b'unknown', (b'Repository.insert_stream_1.19',))
 
3305
        client.add_expected_call(
 
3306
            b'Repository.insert_stream', (b'quack/', b''),
 
3307
            b'success', (b'ok',))
 
3308
        client.add_expected_call(
 
3309
            b'Repository.insert_stream', (b'quack/', b''),
 
3310
            b'success', (b'ok',))
2452
3311
        repo.lock_write()
2453
3312
        self.checkInsertEmptyStream(repo, client)
2454
3313
 
2456
3315
        transport_path = 'quack'
2457
3316
        repo, client = self.setup_fake_client_and_repository(transport_path)
2458
3317
        client.add_expected_call(
2459
 
            'Repository.lock_write', ('quack/', ''),
2460
 
            'success', ('ok', 'a token'))
2461
 
        client.add_expected_call(
2462
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2463
 
            'unknown', ('Repository.insert_stream_1.19',))
2464
 
        client.add_expected_call(
2465
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2466
 
            'success', ('ok',))
2467
 
        client.add_expected_call(
2468
 
            'Repository.insert_stream_locked', ('quack/', '', 'a token'),
2469
 
            'success', ('ok',))
 
3318
            b'Repository.lock_write', (b'quack/', b''),
 
3319
            b'success', (b'ok', b'a token'))
 
3320
        client.add_expected_call(
 
3321
            b'Repository.insert_stream_1.19', (b'quack/', b'', b'a token'),
 
3322
            b'unknown', (b'Repository.insert_stream_1.19',))
 
3323
        client.add_expected_call(
 
3324
            b'Repository.insert_stream_locked', (b'quack/', b'', b'a token'),
 
3325
            b'success', (b'ok',))
 
3326
        client.add_expected_call(
 
3327
            b'Repository.insert_stream_locked', (b'quack/', b'', b'a token'),
 
3328
            b'success', (b'ok',))
2470
3329
        repo.lock_write()
2471
3330
        self.checkInsertEmptyStream(repo, client)
2472
3331
 
2479
3338
        transport_path = 'quack'
2480
3339
        repo, client = self.setup_fake_client_and_repository(transport_path)
2481
3340
        client.add_expected_call(
2482
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2483
 
            'unknown', ('Repository.insert_stream_1.19',))
2484
 
        client.add_expected_call(
2485
 
            'Repository.insert_stream', ('quack/', ''),
2486
 
            'success', ('ok',))
2487
 
        client.add_expected_call(
2488
 
            'Repository.insert_stream', ('quack/', ''),
2489
 
            'success', ('ok',))
 
3341
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3342
            b'unknown', (b'Repository.insert_stream_1.19',))
 
3343
        client.add_expected_call(
 
3344
            b'Repository.insert_stream', (b'quack/', b''),
 
3345
            b'success', (b'ok',))
 
3346
        client.add_expected_call(
 
3347
            b'Repository.insert_stream', (b'quack/', b''),
 
3348
            b'success', (b'ok',))
2490
3349
        # Create a fake real repository for insert_stream to fall back on, so
2491
3350
        # that we can directly see the records the RemoteSink passes to the
2492
3351
        # real sink.
2497
3356
                for substream_kind, substream in stream:
2498
3357
                    self.records.append(
2499
3358
                        (substream_kind, [record.key for record in substream]))
2500
 
                return ['fake tokens'], ['fake missing keys']
 
3359
                return [b'fake tokens'], [b'fake missing keys']
2501
3360
        fake_real_sink = FakeRealSink()
2502
3361
        class FakeRealRepository:
2503
3362
            def _get_sink(self):
2508
3367
                return True
2509
3368
        repo._real_repository = FakeRealRepository()
2510
3369
        sink = repo._get_sink()
2511
 
        fmt = repository.RepositoryFormat.get_default_format()
 
3370
        fmt = repository.format_registry.get_default()
2512
3371
        stream = self.make_stream_with_inv_deltas(fmt)
2513
3372
        resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3373
        # Every record from the first inventory delta should have been sent to
2515
3374
        # the VFS sink.
2516
3375
        expected_records = [
2517
 
            ('inventory-deltas', [('rev2',), ('rev3',)]),
2518
 
            ('texts', [('some-rev', 'some-file')])]
 
3376
            ('inventory-deltas', [(b'rev2',), (b'rev3',)]),
 
3377
            ('texts', [(b'some-rev', b'some-file')])]
2519
3378
        self.assertEqual(expected_records, fake_real_sink.records)
2520
3379
        # The return values from the real sink's insert_stream are propagated
2521
3380
        # back to the original caller.
2522
 
        self.assertEqual(['fake tokens'], resume_tokens)
2523
 
        self.assertEqual(['fake missing keys'], missing_keys)
 
3381
        self.assertEqual([b'fake tokens'], resume_tokens)
 
3382
        self.assertEqual([b'fake missing keys'], missing_keys)
2524
3383
        self.assertFinished(client)
2525
3384
 
2526
3385
    def make_stream_with_inv_deltas(self, fmt):
2534
3393
           * texts substream: (some-rev, some-file)
2535
3394
        """
2536
3395
        # Define a stream using generators so that it isn't rewindable.
2537
 
        inv = inventory.Inventory(revision_id='rev1')
2538
 
        inv.root.revision = 'rev1'
 
3396
        inv = inventory.Inventory(revision_id=b'rev1')
 
3397
        inv.root.revision = b'rev1'
2539
3398
        def stream_with_inv_delta():
2540
3399
            yield ('inventories', inventories_substream())
2541
3400
            yield ('inventory-deltas', inventory_delta_substream())
2542
3401
            yield ('texts', [
2543
3402
                versionedfile.FulltextContentFactory(
2544
 
                    ('some-rev', 'some-file'), (), None, 'content')])
 
3403
                    (b'some-rev', 'some-file'), (), None, 'content')])
2545
3404
        def inventories_substream():
2546
3405
            # An empty inventory fulltext.  This will be streamed normally.
2547
3406
            text = fmt._serializer.write_inventory_to_string(inv)
2548
3407
            yield versionedfile.FulltextContentFactory(
2549
 
                ('rev1',), (), None, text)
 
3408
                (b'rev1',), (), None, text)
2550
3409
        def inventory_delta_substream():
2551
3410
            # An inventory delta.  This can't be streamed via this verb, so it
2552
3411
            # will trigger a fallback to VFS insert_stream.
2553
3412
            entry = inv.make_entry(
2554
 
                'directory', 'newdir', inv.root.file_id, 'newdir-id')
 
3413
                'directory', 'newdir', inv.root.file_id, b'newdir-id')
2555
3414
            entry.revision = 'ghost'
2556
 
            delta = [(None, 'newdir', 'newdir-id', entry)]
 
3415
            delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3416
            serializer = inventory_delta.InventoryDeltaSerializer(
2558
3417
                versioned_root=True, tree_references=False)
2559
 
            lines = serializer.delta_to_lines('rev1', 'rev2', delta)
 
3418
            lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3419
            yield versionedfile.ChunkedContentFactory(
2561
 
                ('rev2',), (('rev1',)), None, lines)
 
3420
                (b'rev2',), ((b'rev1',)), None, lines)
2562
3421
            # Another delta.
2563
 
            lines = serializer.delta_to_lines('rev1', 'rev3', delta)
 
3422
            lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3423
            yield versionedfile.ChunkedContentFactory(
2565
 
                ('rev3',), (('rev1',)), None, lines)
 
3424
                (b'rev3',), ((b'rev1',)), None, lines)
2566
3425
        return stream_with_inv_delta()
2567
3426
 
2568
3427
 
2572
3431
        transport_path = 'quack'
2573
3432
        repo, client = self.setup_fake_client_and_repository(transport_path)
2574
3433
        client.add_expected_call(
2575
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2576
 
            'success', ('ok',))
 
3434
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3435
            b'success', (b'ok',))
2577
3436
        client.add_expected_call(
2578
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2579
 
            'success', ('ok',))
 
3437
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3438
            b'success', (b'ok',))
2580
3439
        self.checkInsertEmptyStream(repo, client)
2581
3440
 
2582
3441
    def test_locked_repo_with_no_lock_token(self):
2583
3442
        transport_path = 'quack'
2584
3443
        repo, client = self.setup_fake_client_and_repository(transport_path)
2585
3444
        client.add_expected_call(
2586
 
            'Repository.lock_write', ('quack/', ''),
2587
 
            'success', ('ok', ''))
2588
 
        client.add_expected_call(
2589
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2590
 
            'success', ('ok',))
2591
 
        client.add_expected_call(
2592
 
            'Repository.insert_stream_1.19', ('quack/', ''),
2593
 
            'success', ('ok',))
 
3445
            b'Repository.lock_write', (b'quack/', b''),
 
3446
            b'success', (b'ok', b''))
 
3447
        client.add_expected_call(
 
3448
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3449
            b'success', (b'ok',))
 
3450
        client.add_expected_call(
 
3451
            b'Repository.insert_stream_1.19', (b'quack/', b''),
 
3452
            b'success', (b'ok',))
2594
3453
        repo.lock_write()
2595
3454
        self.checkInsertEmptyStream(repo, client)
2596
3455
 
2598
3457
        transport_path = 'quack'
2599
3458
        repo, client = self.setup_fake_client_and_repository(transport_path)
2600
3459
        client.add_expected_call(
2601
 
            'Repository.lock_write', ('quack/', ''),
2602
 
            'success', ('ok', 'a token'))
2603
 
        client.add_expected_call(
2604
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2605
 
            'success', ('ok',))
2606
 
        client.add_expected_call(
2607
 
            'Repository.insert_stream_1.19', ('quack/', '', 'a token'),
2608
 
            'success', ('ok',))
 
3460
            b'Repository.lock_write', (b'quack/', b''),
 
3461
            b'success', (b'ok', b'a token'))
 
3462
        client.add_expected_call(
 
3463
            b'Repository.insert_stream_1.19', (b'quack/', b'', b'a token'),
 
3464
            b'success', (b'ok',))
 
3465
        client.add_expected_call(
 
3466
            b'Repository.insert_stream_1.19', (b'quack/', b'', b'a token'),
 
3467
            b'success', (b'ok',))
2609
3468
        repo.lock_write()
2610
3469
        self.checkInsertEmptyStream(repo, client)
2611
3470
 
2613
3472
class TestRepositoryTarball(TestRemoteRepository):
2614
3473
 
2615
3474
    # This is a canned tarball reponse we can validate against
2616
 
    tarball_content = (
 
3475
    tarball_content = base64.b64decode(
2617
3476
        'QlpoOTFBWSZTWdGkj3wAAWF/k8aQACBIB//A9+8cIX/v33AACEAYABAECEACNz'
2618
3477
        'JqsgJJFPTSnk1A3qh6mTQAAAANPUHkagkSTEkaA09QaNAAAGgAAAcwCYCZGAEY'
2619
3478
        'mJhMJghpiaYBUkKammSHqNMZQ0NABkNAeo0AGneAevnlwQoGzEzNVzaYxp/1Uk'
2626
3485
        'QplPKp2nqBWAfwBGaOwVrz3y1T+UZZNismXHsb2Jq18T+VaD9k4P8DqE3g70qV'
2627
3486
        'JLurpnDI6VS5oqDDPVbtVjMxMxMg4rzQVipn2Bv1fVNK0iq3Gl0hhnnHKm/egy'
2628
3487
        'nWQ7QH/F3JFOFCQ0aSPfA='
2629
 
        ).decode('base64')
 
3488
        )
2630
3489
 
2631
3490
    def test_repository_tarball(self):
2632
3491
        # Test that Repository.tarball generates the right operations
2633
3492
        transport_path = 'repo'
2634
 
        expected_calls = [('call_expecting_body', 'Repository.tarball',
2635
 
                           ('repo/', 'bz2',),),
 
3493
        expected_calls = [('call_expecting_body', b'Repository.tarball',
 
3494
                           (b'repo/', b'bz2',),),
2636
3495
            ]
2637
3496
        repo, client = self.setup_fake_client_and_repository(transport_path)
2638
 
        client.add_success_response_with_body(self.tarball_content, 'ok')
 
3497
        client.add_success_response_with_body(self.tarball_content, b'ok')
2639
3498
        # Now actually ask for the tarball
2640
3499
        tarball_file = repo._get_tarball('bz2')
2641
3500
        try:
2670
3529
        self.calls = calls
2671
3530
        self._pack_collection = _StubPackCollection(calls)
2672
3531
 
 
3532
    def start_write_group(self):
 
3533
        self.calls.append(('start_write_group',))
 
3534
 
2673
3535
    def is_in_write_group(self):
2674
3536
        return False
2675
3537
 
2696
3558
        transport_path = 'quack'
2697
3559
        repo, client = self.setup_fake_client_and_repository(transport_path)
2698
3560
        client.add_expected_call(
2699
 
            'PackRepository.autopack', ('quack/',), 'success', ('ok',))
 
3561
            b'PackRepository.autopack', (b'quack/',), b'success', (b'ok',))
2700
3562
        repo.autopack()
2701
3563
        self.assertFinished(client)
2702
3564
 
2707
3569
        transport_path = 'quack'
2708
3570
        repo, client = self.setup_fake_client_and_repository(transport_path)
2709
3571
        client.add_expected_call(
2710
 
            'PackRepository.autopack', ('quack/',),
2711
 
            'success', ('ok',))
 
3572
            b'PackRepository.autopack', (b'quack/',),
 
3573
            b'success', (b'ok',))
2712
3574
        repo._real_repository = _StubRealPackRepository(client._calls)
2713
3575
        repo.autopack()
2714
3576
        self.assertEqual(
2715
 
            [('call', 'PackRepository.autopack', ('quack/',)),
 
3577
            [('call', b'PackRepository.autopack', (b'quack/',)),
2716
3578
             ('pack collection reload_pack_names',)],
2717
3579
            client._calls)
2718
3580
 
2722
3584
        """
2723
3585
        transport_path = 'quack'
2724
3586
        repo, client = self.setup_fake_client_and_repository(transport_path)
2725
 
        client.add_unknown_method_response('PackRepository.autopack')
 
3587
        client.add_unknown_method_response(b'PackRepository.autopack')
2726
3588
        def stub_ensure_real():
2727
3589
            client._calls.append(('_ensure_real',))
2728
3590
            repo._real_repository = _StubRealPackRepository(client._calls)
2729
3591
        repo._ensure_real = stub_ensure_real
2730
3592
        repo.autopack()
2731
3593
        self.assertEqual(
2732
 
            [('call', 'PackRepository.autopack', ('quack/',)),
 
3594
            [('call', b'PackRepository.autopack', (b'quack/',)),
2733
3595
             ('_ensure_real',),
2734
3596
             ('pack collection autopack',)],
2735
3597
            client._calls)
2736
3598
 
 
3599
    def test_oom_error_reporting(self):
 
3600
        """An out-of-memory condition on the server is reported clearly"""
 
3601
        transport_path = 'quack'
 
3602
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
3603
        client.add_expected_call(
 
3604
            b'PackRepository.autopack', (b'quack/',),
 
3605
            b'error', (b'MemoryError',))
 
3606
        err = self.assertRaises(errors.BzrError, repo.autopack)
 
3607
        self.assertContainsRe(str(err), "^remote server out of mem")
 
3608
 
2737
3609
 
2738
3610
class TestErrorTranslationBase(tests.TestCaseWithMemoryTransport):
2739
 
    """Base class for unit tests for bzrlib.remote._translate_error."""
 
3611
    """Base class for unit tests for breezy.bzr.remote._translate_error."""
2740
3612
 
2741
3613
    def translateTuple(self, error_tuple, **context):
2742
3614
        """Call _translate_error with an ErrorFromSmartServer built from the
2762
3634
        """
2763
3635
        try:
2764
3636
            raise error_object
2765
 
        except errors.ErrorFromSmartServer, server_error:
 
3637
        except errors.ErrorFromSmartServer as server_error:
2766
3638
            translated_error = self.assertRaises(
2767
3639
                errors.BzrError, remote._translate_error, server_error,
2768
3640
                **context)
2770
3642
 
2771
3643
 
2772
3644
class TestErrorTranslationSuccess(TestErrorTranslationBase):
2773
 
    """Unit tests for bzrlib.remote._translate_error.
 
3645
    """Unit tests for breezy.bzr.remote._translate_error.
2774
3646
 
2775
3647
    Given an ErrorFromSmartServer (which has an error tuple from a smart
2776
3648
    server) and some context, _translate_error raises more specific errors from
2777
 
    bzrlib.errors.
 
3649
    breezy.errors.
2778
3650
 
2779
3651
    This test case covers the cases where _translate_error succeeds in
2780
3652
    translating an ErrorFromSmartServer to something better.  See
2783
3655
 
2784
3656
    def test_NoSuchRevision(self):
2785
3657
        branch = self.make_branch('')
2786
 
        revid = 'revid'
 
3658
        revid = b'revid'
2787
3659
        translated_error = self.translateTuple(
2788
 
            ('NoSuchRevision', revid), branch=branch)
 
3660
            (b'NoSuchRevision', revid), branch=branch)
2789
3661
        expected_error = errors.NoSuchRevision(branch, revid)
2790
3662
        self.assertEqual(expected_error, translated_error)
2791
3663
 
2792
3664
    def test_nosuchrevision(self):
2793
3665
        repository = self.make_repository('')
2794
 
        revid = 'revid'
 
3666
        revid = b'revid'
2795
3667
        translated_error = self.translateTuple(
2796
 
            ('nosuchrevision', revid), repository=repository)
 
3668
            (b'nosuchrevision', revid), repository=repository)
2797
3669
        expected_error = errors.NoSuchRevision(repository, revid)
2798
3670
        self.assertEqual(expected_error, translated_error)
2799
3671
 
2800
3672
    def test_nobranch(self):
2801
 
        bzrdir = self.make_bzrdir('')
2802
 
        translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
 
3673
        bzrdir = self.make_controldir('')
 
3674
        translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3675
        expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3676
        self.assertEqual(expected_error, translated_error)
2805
3677
 
2806
3678
    def test_nobranch_one_arg(self):
2807
 
        bzrdir = self.make_bzrdir('')
 
3679
        bzrdir = self.make_controldir('')
2808
3680
        translated_error = self.translateTuple(
2809
 
            ('nobranch', 'extra detail'), bzrdir=bzrdir)
 
3681
            (b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3682
        expected_error = errors.NotBranchError(
2811
3683
            path=bzrdir.root_transport.base,
2812
3684
            detail='extra detail')
2813
3685
        self.assertEqual(expected_error, translated_error)
2814
3686
 
 
3687
    def test_norepository(self):
 
3688
        bzrdir = self.make_controldir('')
 
3689
        translated_error = self.translateTuple((b'norepository',),
 
3690
            bzrdir=bzrdir)
 
3691
        expected_error = errors.NoRepositoryPresent(bzrdir)
 
3692
        self.assertEqual(expected_error, translated_error)
 
3693
 
2815
3694
    def test_LockContention(self):
2816
 
        translated_error = self.translateTuple(('LockContention',))
 
3695
        translated_error = self.translateTuple((b'LockContention',))
2817
3696
        expected_error = errors.LockContention('(remote lock)')
2818
3697
        self.assertEqual(expected_error, translated_error)
2819
3698
 
2820
3699
    def test_UnlockableTransport(self):
2821
 
        bzrdir = self.make_bzrdir('')
 
3700
        bzrdir = self.make_controldir('')
2822
3701
        translated_error = self.translateTuple(
2823
 
            ('UnlockableTransport',), bzrdir=bzrdir)
 
3702
            (b'UnlockableTransport',), bzrdir=bzrdir)
2824
3703
        expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3704
        self.assertEqual(expected_error, translated_error)
2826
3705
 
2827
3706
    def test_LockFailed(self):
2828
3707
        lock = 'str() of a server lock'
2829
3708
        why = 'str() of why'
2830
 
        translated_error = self.translateTuple(('LockFailed', lock, why))
 
3709
        translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3710
        expected_error = errors.LockFailed(lock, why)
2832
3711
        self.assertEqual(expected_error, translated_error)
2833
3712
 
2834
3713
    def test_TokenMismatch(self):
2835
3714
        token = 'a lock token'
2836
 
        translated_error = self.translateTuple(('TokenMismatch',), token=token)
 
3715
        translated_error = self.translateTuple((b'TokenMismatch',), token=token)
2837
3716
        expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3717
        self.assertEqual(expected_error, translated_error)
2839
3718
 
2841
3720
        branch = self.make_branch('a')
2842
3721
        other_branch = self.make_branch('b')
2843
3722
        translated_error = self.translateTuple(
2844
 
            ('Diverged',), branch=branch, other_branch=other_branch)
 
3723
            (b'Diverged',), branch=branch, other_branch=other_branch)
2845
3724
        expected_error = errors.DivergedBranches(branch, other_branch)
2846
3725
        self.assertEqual(expected_error, translated_error)
2847
3726
 
 
3727
    def test_NotStacked(self):
 
3728
        branch = self.make_branch('')
 
3729
        translated_error = self.translateTuple((b'NotStacked',), branch=branch)
 
3730
        expected_error = errors.NotStacked(branch)
 
3731
        self.assertEqual(expected_error, translated_error)
 
3732
 
2848
3733
    def test_ReadError_no_args(self):
2849
3734
        path = 'a path'
2850
 
        translated_error = self.translateTuple(('ReadError',), path=path)
 
3735
        translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3736
        expected_error = errors.ReadError(path)
2852
3737
        self.assertEqual(expected_error, translated_error)
2853
3738
 
2854
3739
    def test_ReadError(self):
2855
3740
        path = 'a path'
2856
 
        translated_error = self.translateTuple(('ReadError', path))
 
3741
        translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
2857
3742
        expected_error = errors.ReadError(path)
2858
3743
        self.assertEqual(expected_error, translated_error)
2859
3744
 
2860
3745
    def test_IncompatibleRepositories(self):
2861
 
        translated_error = self.translateTuple(('IncompatibleRepositories',
2862
 
            "repo1", "repo2", "details here"))
 
3746
        translated_error = self.translateTuple((b'IncompatibleRepositories',
 
3747
            b"repo1", b"repo2", b"details here"))
2863
3748
        expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2864
3749
            "details here")
2865
3750
        self.assertEqual(expected_error, translated_error)
2866
3751
 
 
3752
    def test_GhostRevisionsHaveNoRevno(self):
 
3753
        translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
 
3754
            b"revid1", b"revid2"))
 
3755
        expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
 
3756
        self.assertEqual(expected_error, translated_error)
 
3757
 
2867
3758
    def test_PermissionDenied_no_args(self):
2868
3759
        path = 'a path'
2869
 
        translated_error = self.translateTuple(('PermissionDenied',), path=path)
 
3760
        translated_error = self.translateTuple((b'PermissionDenied',),
 
3761
            path=path)
2870
3762
        expected_error = errors.PermissionDenied(path)
2871
3763
        self.assertEqual(expected_error, translated_error)
2872
3764
 
2873
3765
    def test_PermissionDenied_one_arg(self):
2874
3766
        path = 'a path'
2875
 
        translated_error = self.translateTuple(('PermissionDenied', path))
 
3767
        translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
2876
3768
        expected_error = errors.PermissionDenied(path)
2877
3769
        self.assertEqual(expected_error, translated_error)
2878
3770
 
2883
3775
        local_path = 'local path'
2884
3776
        remote_path = 'remote path'
2885
3777
        translated_error = self.translateTuple(
2886
 
            ('PermissionDenied', remote_path), path=local_path)
 
3778
            (b'PermissionDenied', remote_path.encode('utf-8')), path=local_path)
2887
3779
        expected_error = errors.PermissionDenied(local_path)
2888
3780
        self.assertEqual(expected_error, translated_error)
2889
3781
 
2891
3783
        path = 'a path'
2892
3784
        extra = 'a string with extra info'
2893
3785
        translated_error = self.translateTuple(
2894
 
            ('PermissionDenied', path, extra))
 
3786
            (b'PermissionDenied', path.encode('utf-8'), extra.encode('utf-8')))
2895
3787
        expected_error = errors.PermissionDenied(path, extra)
2896
3788
        self.assertEqual(expected_error, translated_error)
2897
3789
 
 
3790
    # GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
 
3791
 
 
3792
    def test_NoSuchFile_context_path(self):
 
3793
        local_path = "local path"
 
3794
        translated_error = self.translateTuple((b'ReadError', b"remote path"),
 
3795
            path=local_path)
 
3796
        expected_error = errors.ReadError(local_path)
 
3797
        self.assertEqual(expected_error, translated_error)
 
3798
 
 
3799
    def test_NoSuchFile_without_context(self):
 
3800
        remote_path = "remote path"
 
3801
        translated_error = self.translateTuple((b'ReadError', remote_path.encode('utf-8')))
 
3802
        expected_error = errors.ReadError(remote_path)
 
3803
        self.assertEqual(expected_error, translated_error)
 
3804
 
 
3805
    def test_ReadOnlyError(self):
 
3806
        translated_error = self.translateTuple((b'ReadOnlyError',))
 
3807
        expected_error = errors.TransportNotPossible("readonly transport")
 
3808
        self.assertEqual(expected_error, translated_error)
 
3809
 
 
3810
    def test_MemoryError(self):
 
3811
        translated_error = self.translateTuple((b'MemoryError',))
 
3812
        self.assertStartsWith(str(translated_error),
 
3813
            "remote server out of memory")
 
3814
 
 
3815
    def test_generic_IndexError_no_classname(self):
 
3816
        err = errors.ErrorFromSmartServer((b'error', b"list index out of range"))
 
3817
        translated_error = self.translateErrorFromSmartServer(err)
 
3818
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3819
        self.assertEqual(expected_error, translated_error)
 
3820
 
 
3821
    # GZ 2011-03-02: TODO test generic non-ascii error string
 
3822
 
 
3823
    def test_generic_KeyError(self):
 
3824
        err = errors.ErrorFromSmartServer((b'error', b'KeyError', b"1"))
 
3825
        translated_error = self.translateErrorFromSmartServer(err)
 
3826
        expected_error = errors.UnknownErrorFromSmartServer(err)
 
3827
        self.assertEqual(expected_error, translated_error)
 
3828
 
2898
3829
 
2899
3830
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
 
    """Unit tests for bzrlib.remote._translate_error's robustness.
 
3831
    """Unit tests for breezy.bzr.remote._translate_error's robustness.
2901
3832
 
2902
3833
    TestErrorTranslationSuccess is for cases where _translate_error can
2903
3834
    translate successfully.  This class about how _translate_err behaves when
2908
3839
        """If the error code from the server is not recognised, the original
2909
3840
        ErrorFromSmartServer is propagated unmodified.
2910
3841
        """
2911
 
        error_tuple = ('An unknown error tuple',)
 
3842
        error_tuple = (b'An unknown error tuple',)
2912
3843
        server_error = errors.ErrorFromSmartServer(error_tuple)
2913
3844
        translated_error = self.translateErrorFromSmartServer(server_error)
2914
3845
        expected_error = errors.UnknownErrorFromSmartServer(server_error)
2923
3854
        # in the context dict.  So let's give it an empty context dict instead
2924
3855
        # to exercise its error recovery.
2925
3856
        empty_context = {}
2926
 
        error_tuple = ('NoSuchRevision', 'revid')
 
3857
        error_tuple = (b'NoSuchRevision', b'revid')
2927
3858
        server_error = errors.ErrorFromSmartServer(error_tuple)
2928
3859
        translated_error = self.translateErrorFromSmartServer(server_error)
2929
3860
        self.assertEqual(server_error, translated_error)
2938
3869
        'path' variable from either the wire or the local context.  If neither
2939
3870
        has it, then an error is raised.
2940
3871
        """
2941
 
        error_tuple = ('ReadError',)
 
3872
        error_tuple = (b'ReadError',)
2942
3873
        server_error = errors.ErrorFromSmartServer(error_tuple)
2943
3874
        translated_error = self.translateErrorFromSmartServer(server_error)
2944
3875
        self.assertEqual(server_error, translated_error)
2961
3892
        base_transport = self.get_transport()
2962
3893
        base_builder = self.make_branch_builder('base', format='1.9')
2963
3894
        base_builder.start_series()
2964
 
        base_revid = base_builder.build_snapshot('rev-id', None,
 
3895
        base_revid = base_builder.build_snapshot(None,
2965
3896
            [('add', ('', None, 'directory', None))],
2966
 
            'message')
 
3897
            'message', revision_id=b'rev-id')
2967
3898
        base_builder.finish_series()
2968
3899
        stacked_branch = self.make_branch('stacked', format='1.9')
2969
3900
        stacked_branch.set_stacked_on_url('../base')
2994
3925
        """Get stacked_upon and stacked branches with content in each."""
2995
3926
        self.setup_smart_server_with_call_log()
2996
3927
        tree1 = self.make_branch_and_tree('tree1', format='1.9')
2997
 
        tree1.commit('rev1', rev_id='rev1')
2998
 
        tree2 = tree1.branch.bzrdir.sprout('tree2', stacked=True
 
3928
        tree1.commit('rev1', rev_id=b'rev1')
 
3929
        tree2 = tree1.branch.controldir.sprout('tree2', stacked=True
2999
3930
            ).open_workingtree()
3000
3931
        local_tree = tree2.branch.create_checkout('local')
3001
3932
        local_tree.commit('local changes make me feel good.')
3008
3939
        # the public implementation of get_parent_map obeys stacking
3009
3940
        _, branch = self.prepare_stacked_remote_branch()
3010
3941
        repo = branch.repository
3011
 
        self.assertEqual(['rev1'], repo.get_parent_map(['rev1']).keys())
 
3942
        self.assertEqual({'rev1'}, set(repo.get_parent_map([b'rev1'])))
3012
3943
 
3013
3944
    def test_unstacked_get_parent_map(self):
3014
3945
        # _unstacked_provider.get_parent_map ignores stacking
3015
3946
        _, branch = self.prepare_stacked_remote_branch()
3016
3947
        provider = branch.repository._unstacked_provider
3017
 
        self.assertEqual([], provider.get_parent_map(['rev1']).keys())
 
3948
        self.assertEqual(set(), set(provider.get_parent_map([b'rev1'])))
3018
3949
 
3019
3950
    def fetch_stream_to_rev_order(self, stream):
3020
3951
        result = []
3036
3967
        :result: The revision ids in the stream, in the order seen,
3037
3968
            the topological order of revisions in the source.
3038
3969
        """
3039
 
        unordered_format = bzrdir.format_registry.get(format)()
 
3970
        unordered_format = controldir.format_registry.get(format)()
3040
3971
        target_repository_format = unordered_format.repository_format
3041
3972
        # Cross check
3042
3973
        self.assertEqual(order, target_repository_format._fetch_order)
3045
3976
        _, stacked = branch_factory()
3046
3977
        source = stacked.repository._get_source(target_repository_format)
3047
3978
        tip = stacked.last_revision()
3048
 
        revs = stacked.repository.get_ancestry(tip)
3049
 
        search = graph.PendingAncestryResult([tip], stacked.repository)
 
3979
        stacked.repository._ensure_real()
 
3980
        graph = stacked.repository.get_graph()
 
3981
        revs = [r for (r, ps) in graph.iter_ancestry([tip])
 
3982
                if r != NULL_REVISION]
 
3983
        revs.reverse()
 
3984
        search = vf_search.PendingAncestryResult([tip], stacked.repository)
3050
3985
        self.reset_smart_call_log()
3051
3986
        stream = source.get_stream(search)
3052
 
        if None in revs:
3053
 
            revs.remove(None)
3054
3987
        # We trust that if a revision is in the stream the rest of the new
3055
3988
        # content for it is too, as per our main fetch tests; here we are
3056
3989
        # checking that the revisions are actually included at all, and their
3072
4005
        # is itself stacked yields the full data from all three sources.
3073
4006
        def make_stacked_stacked():
3074
4007
            _, stacked = self.prepare_stacked_remote_branch()
3075
 
            tree = stacked.bzrdir.sprout('tree3', stacked=True
 
4008
            tree = stacked.controldir.sprout('tree3', stacked=True
3076
4009
                ).open_workingtree()
3077
4010
            local_tree = tree.branch.create_checkout('local-tree3')
3078
4011
            local_tree.commit('more local changes are better')
3095
4028
        self.assertEqual(expected_revs, rev_ord)
3096
4029
        # Getting topological sort requires VFS calls still - one of which is
3097
4030
        # pushing up from the bound branch.
3098
 
        self.assertLength(13, self.hpss_calls)
 
4031
        self.assertLength(14, self.hpss_calls)
3099
4032
 
3100
4033
    def test_stacked_get_stream_groupcompress(self):
3101
4034
        # Repository._get_source.get_stream() from a stacked repository with
3142
4075
 
3143
4076
    def test_copy_content_into_avoids_revision_history(self):
3144
4077
        local = self.make_branch('local')
3145
 
        remote_backing_tree = self.make_branch_and_tree('remote')
3146
 
        remote_backing_tree.commit("Commit.")
 
4078
        builder = self.make_branch_builder('remote')
 
4079
        builder.build_commit(message="Commit.")
3147
4080
        remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4081
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4082
        local.repository.fetch(remote_branch.repository)
3150
4083
        self.hpss_calls = []
3151
4084
        remote_branch.copy_content_into(local)
3152
 
        self.assertFalse('Branch.revision_history' in self.hpss_calls)
 
4085
        self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
 
4086
 
 
4087
    def test_fetch_everything_needs_just_one_call(self):
 
4088
        local = self.make_branch('local')
 
4089
        builder = self.make_branch_builder('remote')
 
4090
        builder.build_commit(message="Commit.")
 
4091
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4092
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4093
        self.hpss_calls = []
 
4094
        local.repository.fetch(
 
4095
            remote_branch.repository,
 
4096
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4097
        self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
 
4098
 
 
4099
    def override_verb(self, verb_name, verb):
 
4100
        request_handlers = request.request_handlers
 
4101
        orig_verb = request_handlers.get(verb_name)
 
4102
        orig_info = request_handlers.get_info(verb_name)
 
4103
        request_handlers.register(verb_name, verb, override_existing=True)
 
4104
        self.addCleanup(request_handlers.register, verb_name, orig_verb,
 
4105
                override_existing=True, info=orig_info)
 
4106
 
 
4107
    def test_fetch_everything_backwards_compat(self):
 
4108
        """Can fetch with EverythingResult even with pre 2.4 servers.
 
4109
        
 
4110
        Pre-2.4 do not support 'everything' searches with the
 
4111
        Repository.get_stream_1.19 verb.
 
4112
        """
 
4113
        verb_log = []
 
4114
        class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
 
4115
            """A version of the Repository.get_stream_1.19 verb patched to
 
4116
            reject 'everything' searches the way 2.3 and earlier do.
 
4117
            """
 
4118
            def recreate_search(self, repository, search_bytes,
 
4119
                                discard_excess=False):
 
4120
                verb_log.append(search_bytes.split(b'\n', 1)[0])
 
4121
                if search_bytes == b'everything':
 
4122
                    return (None,
 
4123
                            request.FailedSmartServerResponse((b'BadSearch',)))
 
4124
                return super(OldGetStreamVerb,
 
4125
                        self).recreate_search(repository, search_bytes,
 
4126
                            discard_excess=discard_excess)
 
4127
        self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
 
4128
        local = self.make_branch('local')
 
4129
        builder = self.make_branch_builder('remote')
 
4130
        builder.build_commit(message="Commit.")
 
4131
        remote_branch_url = self.smart_server.get_url() + 'remote'
 
4132
        remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
 
4133
        self.hpss_calls = []
 
4134
        local.repository.fetch(
 
4135
            remote_branch.repository,
 
4136
            fetch_spec=vf_search.EverythingResult(remote_branch.repository))
 
4137
        # make sure the overridden verb was used
 
4138
        self.assertLength(1, verb_log)
 
4139
        # more than one HPSS call is needed, but because it's a VFS callback
 
4140
        # its hard to predict exactly how many.
 
4141
        self.assertTrue(len(self.hpss_calls) > 1)
 
4142
 
 
4143
 
 
4144
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
4145
    tests.TestCaseWithTransport):
 
4146
    """Ensure correct handling of bound_location modifications.
 
4147
 
 
4148
    This is tested against a smart server as http://pad.lv/786980 was about a
 
4149
    ReadOnlyError (write attempt during a read-only transaction) which can only
 
4150
    happen in this context.
 
4151
    """
 
4152
 
 
4153
    def setUp(self):
 
4154
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
4155
        self.transport_server = test_server.SmartTCPServer_for_testing
 
4156
 
 
4157
    def make_master_and_checkout(self, master_name, checkout_name):
 
4158
        # Create the master branch and its associated checkout
 
4159
        self.master = self.make_branch_and_tree(master_name)
 
4160
        self.checkout = self.master.branch.create_checkout(checkout_name)
 
4161
        # Modify the master branch so there is something to update
 
4162
        self.master.commit('add stuff')
 
4163
        self.last_revid = self.master.commit('even more stuff')
 
4164
        self.bound_location = self.checkout.branch.get_bound_location()
 
4165
 
 
4166
    def assertUpdateSucceeds(self, new_location):
 
4167
        self.checkout.branch.set_bound_location(new_location)
 
4168
        self.checkout.update()
 
4169
        self.assertEqual(self.last_revid, self.checkout.last_revision())
 
4170
 
 
4171
    def test_without_final_slash(self):
 
4172
        self.make_master_and_checkout('master', 'checkout')
 
4173
        # For unclear reasons some users have a bound_location without a final
 
4174
        # '/', simulate that by forcing such a value
 
4175
        self.assertEndsWith(self.bound_location, '/')
 
4176
        self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
 
4177
 
 
4178
    def test_plus_sign(self):
 
4179
        self.make_master_and_checkout('+master', 'checkout')
 
4180
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
4181
 
 
4182
    def test_tilda(self):
 
4183
        # Embed ~ in the middle of the path just to avoid any $HOME
 
4184
        # interpretation
 
4185
        self.make_master_and_checkout('mas~ter', 'checkout')
 
4186
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
 
4187
 
 
4188
 
 
4189
class TestWithCustomErrorHandler(RemoteBranchTestCase):
 
4190
 
 
4191
    def test_no_context(self):
 
4192
        class OutOfCoffee(errors.BzrError):
 
4193
            """A dummy exception for testing."""
 
4194
 
 
4195
            def __init__(self, urgency):
 
4196
                self.urgency = urgency
 
4197
        remote.no_context_error_translators.register(b"OutOfCoffee",
 
4198
            lambda err: OutOfCoffee(err.error_args[0]))
 
4199
        transport = MemoryTransport()
 
4200
        client = FakeClient(transport.base)
 
4201
        client.add_expected_call(
 
4202
            b'Branch.get_stacked_on_url', (b'quack/',),
 
4203
            b'error', (b'NotStacked',))
 
4204
        client.add_expected_call(
 
4205
            b'Branch.last_revision_info',
 
4206
            (b'quack/',),
 
4207
            b'error', (b'OutOfCoffee', b'low'))
 
4208
        transport.mkdir('quack')
 
4209
        transport = transport.clone('quack')
 
4210
        branch = self.make_remote_branch(transport, client)
 
4211
        self.assertRaises(OutOfCoffee, branch.last_revision_info)
 
4212
        self.assertFinished(client)
 
4213
 
 
4214
    def test_with_context(self):
 
4215
        class OutOfTea(errors.BzrError):
 
4216
            def __init__(self, branch, urgency):
 
4217
                self.branch = branch
 
4218
                self.urgency = urgency
 
4219
        remote.error_translators.register(b"OutOfTea",
 
4220
            lambda err, find, path: OutOfTea(
 
4221
                err.error_args[0].decode('utf-8'),
 
4222
                find("branch")))
 
4223
        transport = MemoryTransport()
 
4224
        client = FakeClient(transport.base)
 
4225
        client.add_expected_call(
 
4226
            b'Branch.get_stacked_on_url', (b'quack/',),
 
4227
            b'error', (b'NotStacked',))
 
4228
        client.add_expected_call(
 
4229
            b'Branch.last_revision_info',
 
4230
            (b'quack/',),
 
4231
            b'error', (b'OutOfTea', b'low'))
 
4232
        transport.mkdir('quack')
 
4233
        transport = transport.clone('quack')
 
4234
        branch = self.make_remote_branch(transport, client)
 
4235
        self.assertRaises(OutOfTea, branch.last_revision_info)
 
4236
        self.assertFinished(client)
 
4237
 
 
4238
 
 
4239
class TestRepositoryPack(TestRemoteRepository):
 
4240
 
 
4241
    def test_pack(self):
 
4242
        transport_path = 'quack'
 
4243
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4244
        client.add_expected_call(
 
4245
            b'Repository.lock_write', (b'quack/', b''),
 
4246
            b'success', (b'ok', b'token'))
 
4247
        client.add_expected_call(
 
4248
            b'Repository.pack', (b'quack/', b'token', b'False'),
 
4249
            b'success', (b'ok',), )
 
4250
        client.add_expected_call(
 
4251
            b'Repository.unlock', (b'quack/', b'token'),
 
4252
            b'success', (b'ok', ))
 
4253
        repo.pack()
 
4254
 
 
4255
    def test_pack_with_hint(self):
 
4256
        transport_path = 'quack'
 
4257
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4258
        client.add_expected_call(
 
4259
            b'Repository.lock_write', (b'quack/', b''),
 
4260
            b'success', (b'ok', b'token'))
 
4261
        client.add_expected_call(
 
4262
            b'Repository.pack', (b'quack/', b'token', b'False'),
 
4263
            b'success', (b'ok',), )
 
4264
        client.add_expected_call(
 
4265
            b'Repository.unlock', (b'quack/', b'token', b'False'),
 
4266
            b'success', (b'ok', ))
 
4267
        repo.pack([b'hinta', b'hintb'])
 
4268
 
 
4269
 
 
4270
class TestRepositoryIterInventories(TestRemoteRepository):
 
4271
    """Test Repository.iter_inventories."""
 
4272
 
 
4273
    def _serialize_inv_delta(self, old_name, new_name, delta):
 
4274
        serializer = inventory_delta.InventoryDeltaSerializer(True, False)
 
4275
        return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
 
4276
 
 
4277
    def test_single_empty(self):
 
4278
        transport_path = 'quack'
 
4279
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4280
        fmt = controldir.format_registry.get('2a')().repository_format
 
4281
        repo._format = fmt
 
4282
        stream = [('inventory-deltas', [
 
4283
            versionedfile.FulltextContentFactory(b'somerevid', None, None,
 
4284
                self._serialize_inv_delta(b'null:', b'somerevid', []))])]
 
4285
        client.add_expected_call(
 
4286
            b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
 
4287
            b'success', (b'ok', ),
 
4288
            _stream_to_byte_stream(stream, fmt))
 
4289
        ret = list(repo.iter_inventories([b"somerevid"]))
 
4290
        self.assertLength(1, ret)
 
4291
        inv = ret[0]
 
4292
        self.assertEqual(b"somerevid", inv.revision_id)
 
4293
 
 
4294
    def test_empty(self):
 
4295
        transport_path = 'quack'
 
4296
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4297
        ret = list(repo.iter_inventories([]))
 
4298
        self.assertEqual(ret, [])
 
4299
 
 
4300
    def test_missing(self):
 
4301
        transport_path = 'quack'
 
4302
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
4303
        client.add_expected_call(
 
4304
            b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
 
4305
            b'success', (b'ok', ), iter([]))
 
4306
        self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
 
4307
            [b"somerevid"]))