/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: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2018-11-16 07:18:33 UTC
  • mfrom: (7141.3.3 fix1799482)
  • Revision ID: breezy.the.bot@gmail.com-20181116071833-e01b0833f3hkc3et
Report correct paths when running "brz add" in git repositories.

Merged from https://code.launchpad.net/~jelmer/brz/fix1799482/+merge/357734

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