/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-07-08 14:45:27 UTC
  • mto: This revision was merged to the branch mainline in revision 7036.
  • Revision ID: jelmer@jelmer.uk-20180708144527-codhlvdcdg9y0nji
Fix a bunch of merge tests.

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