/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 bzrlib/tests/test_remote.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

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