/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

Update to bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
from bzrlib.smart import server, medium
47
47
from bzrlib.smart.client import _SmartClient
48
48
from bzrlib.symbol_versioning import one_four
49
 
from bzrlib.transport import get_transport
 
49
from bzrlib.transport import get_transport, http
50
50
from bzrlib.transport.memory import MemoryTransport
51
 
from bzrlib.transport.remote import RemoteTransport
 
51
from bzrlib.transport.remote import RemoteTransport, RemoteTCPTransport
52
52
 
53
53
 
54
54
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
132
132
class FakeClient(_SmartClient):
133
133
    """Lookalike for _SmartClient allowing testing."""
134
134
    
135
 
    def __init__(self, responses, fake_medium_base='fake base'):
 
135
    def __init__(self, fake_medium_base='fake base'):
136
136
        """Create a FakeClient.
137
137
 
138
138
        :param responses: A list of response-tuple, body-data pairs to be sent
141
141
            call, using the second element of the tuple as the verb in the
142
142
            exception.
143
143
        """
144
 
        self.responses = responses
 
144
        self.responses = []
145
145
        self._calls = []
146
146
        self.expecting_body = False
147
 
        _SmartClient.__init__(self, FakeMedium(self._calls), fake_medium_base)
 
147
        _SmartClient.__init__(self, FakeMedium(self._calls, fake_medium_base))
 
148
 
 
149
    def add_success_response(self, *args):
 
150
        self.responses.append(('success', args, None))
 
151
 
 
152
    def add_success_response_with_body(self, body, *args):
 
153
        self.responses.append(('success', args, body))
 
154
 
 
155
    def add_error_response(self, *args):
 
156
        self.responses.append(('error', args))
 
157
 
 
158
    def add_unknown_method_response(self, verb):
 
159
        self.responses.append(('unknown', verb))
148
160
 
149
161
    def _get_next_response(self):
150
162
        response_tuple = self.responses.pop(0)
151
 
        if response_tuple[0][0] == 'unknown verb':
152
 
            raise errors.UnknownSmartMethod(response_tuple[0][1])
 
163
        if response_tuple[0] == 'unknown':
 
164
            raise errors.UnknownSmartMethod(response_tuple[1])
 
165
        elif response_tuple[0] == 'error':
 
166
            raise errors.ErrorFromSmartServer(response_tuple[1])
153
167
        return response_tuple
154
168
 
155
169
    def call(self, method, *args):
156
170
        self._calls.append(('call', method, args))
157
 
        return self._get_next_response()[0]
 
171
        return self._get_next_response()[1]
158
172
 
159
173
    def call_expecting_body(self, method, *args):
160
174
        self._calls.append(('call_expecting_body', method, args))
161
175
        result = self._get_next_response()
162
176
        self.expecting_body = True
163
 
        return result[0], FakeProtocol(result[1], self)
 
177
        return result[1], FakeProtocol(result[2], self)
164
178
 
165
179
    def call_with_body_bytes_expecting_body(self, method, args, body):
166
180
        self._calls.append(('call_with_body_bytes_expecting_body', method,
167
181
            args, body))
168
182
        result = self._get_next_response()
169
183
        self.expecting_body = True
170
 
        return result[0], FakeProtocol(result[1], self)
171
 
 
172
 
 
173
 
class FakeMedium(object):
174
 
 
175
 
    def __init__(self, client_calls):
 
184
        return result[1], FakeProtocol(result[2], self)
 
185
 
 
186
 
 
187
class FakeMedium(medium.SmartClientMedium):
 
188
 
 
189
    def __init__(self, client_calls, base):
176
190
        self._remote_is_at_least_1_2 = True
177
191
        self._client_calls = client_calls
 
192
        self.base = base
178
193
 
179
194
    def disconnect(self):
180
195
        self._client_calls.append(('disconnect medium',))
183
198
class TestVfsHas(tests.TestCase):
184
199
 
185
200
    def test_unicode_path(self):
186
 
        client = FakeClient([(('yes',), )], '/')
 
201
        client = FakeClient('/')
 
202
        client.add_success_response('yes',)
187
203
        transport = RemoteTransport('bzr://localhost/', _client=client)
188
204
        filename = u'/hell\u00d8'.encode('utf8')
189
205
        result = transport.has(filename)
193
209
        self.assertTrue(result)
194
210
 
195
211
 
196
 
class Test_SmartClient_remote_path_from_transport(tests.TestCase):
197
 
    """Tests for the behaviour of _SmartClient.remote_path_from_transport."""
 
212
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
 
213
    """Tests for the behaviour of client_medium.remote_path_from_transport."""
198
214
 
199
215
    def assertRemotePath(self, expected, client_base, transport_base):
200
 
        """Assert that the result of _SmartClient.remote_path_from_transport
201
 
        is the expected value for a given client_base and transport_base.
 
216
        """Assert that the result of
 
217
        SmartClientMedium.remote_path_from_transport is the expected value for
 
218
        a given client_base and transport_base.
202
219
        """
203
 
        dummy_medium = 'dummy medium'
204
 
        client = _SmartClient(dummy_medium, client_base)
 
220
        client_medium = medium.SmartClientMedium(client_base)
205
221
        transport = get_transport(transport_base)
206
 
        result = client.remote_path_from_transport(transport)
 
222
        result = client_medium.remote_path_from_transport(transport)
207
223
        self.assertEqual(expected, result)
208
 
        
 
224
 
209
225
    def test_remote_path_from_transport(self):
210
 
        """_SmartClient.remote_path_from_transport calculates a URL for the
211
 
        given transport relative to the root of the client base URL.
 
226
        """SmartClientMedium.remote_path_from_transport calculates a URL for
 
227
        the given transport relative to the root of the client base URL.
212
228
        """
213
229
        self.assertRemotePath('xyz/', 'bzr://host/path', 'bzr://host/xyz')
214
230
        self.assertRemotePath(
215
231
            'path/xyz/', 'bzr://host/path', 'bzr://host/path/xyz')
216
232
 
 
233
    def assertRemotePathHTTP(self, expected, transport_base, relpath):
 
234
        """Assert that the result of
 
235
        HttpTransportBase.remote_path_from_transport is the expected value for
 
236
        a given transport_base and relpath of that transport.  (Note that
 
237
        HttpTransportBase is a subclass of SmartClientMedium)
 
238
        """
 
239
        base_transport = get_transport(transport_base)
 
240
        client_medium = base_transport.get_smart_medium()
 
241
        cloned_transport = base_transport.clone(relpath)
 
242
        result = client_medium.remote_path_from_transport(cloned_transport)
 
243
        self.assertEqual(expected, result)
 
244
        
217
245
    def test_remote_path_from_transport_http(self):
218
246
        """Remote paths for HTTP transports are calculated differently to other
219
247
        transports.  They are just relative to the client base, not the root
220
248
        directory of the host.
221
249
        """
222
250
        for scheme in ['http:', 'https:', 'bzr+http:', 'bzr+https:']:
223
 
            self.assertRemotePath(
224
 
                '../xyz/', scheme + '//host/path', scheme + '//host/xyz')
225
 
            self.assertRemotePath(
226
 
                'xyz/', scheme + '//host/path', scheme + '//host/path/xyz')
 
251
            self.assertRemotePathHTTP(
 
252
                '../xyz/', scheme + '//host/path', '../xyz/')
 
253
            self.assertRemotePathHTTP(
 
254
                'xyz/', scheme + '//host/path', 'xyz/')
227
255
 
228
256
 
229
257
class TestBzrDirOpenBranch(tests.TestCase):
232
260
        transport = MemoryTransport()
233
261
        transport.mkdir('quack')
234
262
        transport = transport.clone('quack')
235
 
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
236
 
                            transport.base)
 
263
        client = FakeClient(transport.base)
 
264
        client.add_success_response('ok', '')
 
265
        client.add_success_response('ok', '', 'no', 'no', 'no')
237
266
        bzrdir = RemoteBzrDir(transport, _client=client)
238
267
        result = bzrdir.open_branch()
239
268
        self.assertEqual(
247
276
        transport = MemoryTransport()
248
277
        transport.mkdir('quack')
249
278
        transport = transport.clone('quack')
250
 
        client = FakeClient([(('nobranch',), )], transport.base)
 
279
        client = FakeClient(transport.base)
 
280
        client.add_error_response('nobranch')
251
281
        bzrdir = RemoteBzrDir(transport, _client=client)
252
282
        self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
253
283
        self.assertEqual(
263
293
            return "a-branch"
264
294
        transport = MemoryTransport()
265
295
        # no requests on the network - catches other api calls being made.
266
 
        client = FakeClient([], transport.base)
 
296
        client = FakeClient(transport.base)
267
297
        bzrdir = RemoteBzrDir(transport, _client=client)
268
298
        # patch the open_branch call to record that it was called.
269
299
        bzrdir.open_branch = open_branch
274
304
    def test_url_quoting_of_path(self):
275
305
        # Relpaths on the wire should not be URL-escaped.  So "~" should be
276
306
        # transmitted as "~", not "%7E".
277
 
        transport = RemoteTransport('bzr://localhost/~hello/')
278
 
        client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
279
 
                            transport.base)
 
307
        transport = RemoteTCPTransport('bzr://localhost/~hello/')
 
308
        client = FakeClient(transport.base)
 
309
        client.add_success_response('ok', '')
 
310
        client.add_success_response('ok', '', 'no', 'no', 'no')
280
311
        bzrdir = RemoteBzrDir(transport, _client=client)
281
312
        result = bzrdir.open_branch()
282
313
        self.assertEqual(
296
327
            subtree_response = 'yes'
297
328
        else:
298
329
            subtree_response = 'no'
299
 
        client = FakeClient(
300
 
            [(('ok', '', rich_response, subtree_response, external_lookup), ),],
301
 
            transport.base)
 
330
        client = FakeClient(transport.base)
 
331
        client.add_success_response(
 
332
            'ok', '', rich_response, subtree_response, external_lookup)
302
333
        bzrdir = RemoteBzrDir(transport, _client=client)
303
334
        result = bzrdir.open_repository()
304
335
        self.assertEqual(
330
361
        transport = MemoryTransport()
331
362
        transport.mkdir('quack')
332
363
        transport = transport.clone('quack')
333
 
        client = FakeClient([
334
 
            (('unknown verb', 'RemoteRepository.find_repositoryV2'), ''),
335
 
            (('ok', '', 'no', 'no'), ''),],
336
 
            transport.base)
 
364
        client = FakeClient(transport.base)
 
365
        client.add_unknown_method_response('RemoteRepository.find_repositoryV2')
 
366
        client.add_success_response('ok', '', 'no', 'no')
337
367
        bzrdir = RemoteBzrDir(transport, _client=client)
338
368
        repo = bzrdir.open_repository()
339
369
        self.assertEqual(
375
405
    def test_empty_branch(self):
376
406
        # in an empty branch we decode the response properly
377
407
        transport = MemoryTransport()
378
 
        client = FakeClient([(('ok', '0', 'null:'), )], transport.base)
 
408
        client = FakeClient(transport.base)
 
409
        client.add_success_response('ok', '0', 'null:')
379
410
        transport.mkdir('quack')
380
411
        transport = transport.clone('quack')
381
412
        # we do not want bzrdir to make any remote calls
392
423
        # in a non-empty branch we also decode the response properly
393
424
        revid = u'\xc8'.encode('utf8')
394
425
        transport = MemoryTransport()
395
 
        client = FakeClient([(('ok', '2', revid), )], transport.base)
 
426
        client = FakeClient(transport.base)
 
427
        client.add_success_response('ok', '2', revid)
396
428
        transport.mkdir('kwaak')
397
429
        transport = transport.clone('kwaak')
398
430
        # we do not want bzrdir to make any remote calls
415
447
        transport.mkdir('branch')
416
448
        transport = transport.clone('branch')
417
449
 
418
 
        client = FakeClient([
419
 
            # lock_write
420
 
            (('ok', 'branch token', 'repo token'), ),
421
 
            # set_last_revision
422
 
            (('ok',), ),
423
 
            # unlock
424
 
            (('ok',), )],
425
 
            transport.base)
 
450
        client = FakeClient(transport.base)
 
451
        # lock_write
 
452
        client.add_success_response('ok', 'branch token', 'repo token')
 
453
        # set_last_revision
 
454
        client.add_success_response('ok')
 
455
        # unlock
 
456
        client.add_success_response('ok')
426
457
        bzrdir = RemoteBzrDir(transport, _client=False)
427
458
        branch = RemoteBranch(bzrdir, None, _client=client)
428
459
        # This is a hack to work around the problem that RemoteBranch currently
445
476
        transport.mkdir('branch')
446
477
        transport = transport.clone('branch')
447
478
 
448
 
        client = FakeClient([
449
 
            # lock_write
450
 
            (('ok', 'branch token', 'repo token'), ),
451
 
            # set_last_revision
452
 
            (('ok',), ),
453
 
            # unlock
454
 
            (('ok',), )],
455
 
            transport.base)
 
479
        client = FakeClient(transport.base)
 
480
        # lock_write
 
481
        client.add_success_response('ok', 'branch token', 'repo token')
 
482
        # set_last_revision
 
483
        client.add_success_response('ok')
 
484
        # unlock
 
485
        client.add_success_response('ok')
456
486
        bzrdir = RemoteBzrDir(transport, _client=False)
457
487
        branch = RemoteBranch(bzrdir, None, _client=client)
458
488
        # This is a hack to work around the problem that RemoteBranch currently
471
501
        self.assertEqual(None, result)
472
502
 
473
503
    def test_no_such_revision(self):
474
 
        # A response of 'NoSuchRevision' is translated into an exception.
475
 
        client = FakeClient([
476
 
            # lock_write
477
 
            (('ok', 'branch token', 'repo token'), ),
478
 
            # set_last_revision
479
 
            (('NoSuchRevision', 'rev-id'), ),
480
 
            # unlock
481
 
            (('ok',), )])
482
504
        transport = MemoryTransport()
483
505
        transport.mkdir('branch')
484
506
        transport = transport.clone('branch')
 
507
        # A response of 'NoSuchRevision' is translated into an exception.
 
508
        client = FakeClient(transport.base)
 
509
        # lock_write
 
510
        client.add_success_response('ok', 'branch token', 'repo token')
 
511
        # set_last_revision
 
512
        client.add_error_response('NoSuchRevision', 'rev-id')
 
513
        # unlock
 
514
        client.add_success_response('ok')
485
515
 
486
516
        bzrdir = RemoteBzrDir(transport, _client=False)
487
517
        branch = RemoteBranch(bzrdir, None, _client=client)
502
532
        transport = MemoryTransport()
503
533
        transport.mkdir('branch')
504
534
        transport = transport.clone('branch')
505
 
        client = FakeClient([
506
 
            # lock_write
507
 
            (('ok', 'branch token', 'repo token'), ),
508
 
            # set_last_revision_info
509
 
            (('ok',), ),
510
 
            # unlock
511
 
            (('ok',), )], transport.base)
 
535
        client = FakeClient(transport.base)
 
536
        # lock_write
 
537
        client.add_success_response('ok', 'branch token', 'repo token')
 
538
        # set_last_revision
 
539
        client.add_success_response('ok')
 
540
        # unlock
 
541
        client.add_success_response('ok')
512
542
 
513
543
        bzrdir = RemoteBzrDir(transport, _client=False)
514
544
        branch = RemoteBranch(bzrdir, None, _client=client)
528
558
 
529
559
    def test_no_such_revision(self):
530
560
        # A response of 'NoSuchRevision' is translated into an exception.
531
 
        client = FakeClient([
532
 
            # lock_write
533
 
            (('ok', 'branch token', 'repo token'), ),
534
 
            # set_last_revision_info
535
 
            (('NoSuchRevision', 'revid'), ),
536
 
            # unlock
537
 
            (('ok',), ),
538
 
            ])
539
561
        transport = MemoryTransport()
540
562
        transport.mkdir('branch')
541
563
        transport = transport.clone('branch')
 
564
        client = FakeClient(transport.base)
 
565
        # lock_write
 
566
        client.add_success_response('ok', 'branch token', 'repo token')
 
567
        # set_last_revision
 
568
        client.add_error_response('NoSuchRevision', 'revid')
 
569
        # unlock
 
570
        client.add_success_response('ok')
542
571
 
543
572
        bzrdir = RemoteBzrDir(transport, _client=False)
544
573
        branch = RemoteBranch(bzrdir, None, _client=client)
575
604
        transport = MemoryTransport()
576
605
        transport.mkdir('branch')
577
606
        transport = transport.clone('branch')
578
 
        client = FakeClient(
579
 
            [(('unknown verb', 'Branch.set_last_revision_info',), ),],
580
 
            transport.base)
 
607
        client = FakeClient(transport.base)
 
608
        client.add_unknown_method_response('Branch.set_last_revision_info')
581
609
        bzrdir = RemoteBzrDir(transport, _client=False)
582
610
        branch = RemoteBranch(bzrdir, None, _client=client)
583
611
        class StubRealBranch(object):
601
629
            [('set_last_revision_info', 1234, 'a-revision-id')],
602
630
            real_branch.calls)
603
631
 
 
632
    def test_unexpected_error(self):
 
633
        # A response of 'NoSuchRevision' is translated into an exception.
 
634
        transport = MemoryTransport()
 
635
        transport.mkdir('branch')
 
636
        transport = transport.clone('branch')
 
637
        client = FakeClient(transport.base)
 
638
        # lock_write
 
639
        client.add_success_response('ok', 'branch token', 'repo token')
 
640
        # set_last_revision
 
641
        client.add_error_response('UnexpectedError')
 
642
        # unlock
 
643
        client.add_success_response('ok')
 
644
 
 
645
        bzrdir = RemoteBzrDir(transport, _client=False)
 
646
        branch = RemoteBranch(bzrdir, None, _client=client)
 
647
        # This is a hack to work around the problem that RemoteBranch currently
 
648
        # unnecessarily invokes _ensure_real upon a call to lock_write.
 
649
        branch._ensure_real = lambda: None
 
650
        # Lock the branch, reset the record of remote calls.
 
651
        branch.lock_write()
 
652
        client._calls = []
 
653
 
 
654
        err = self.assertRaises(
 
655
            errors.ErrorFromSmartServer,
 
656
            branch.set_last_revision_info, 123, 'revid')
 
657
        self.assertEqual(('UnexpectedError',), err.error_tuple)
 
658
        branch.unlock()
 
659
 
604
660
 
605
661
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
606
662
    """Getting the branch configuration should use an abstract method not vfs.
608
664
 
609
665
    def test_get_branch_conf(self):
610
666
        raise tests.KnownFailure('branch.conf is not retrieved by get_config_file')
611
 
        # We should see that branch.get_config() does a single rpc to get the
612
 
        # remote configuration file, abstracting away where that is stored on
613
 
        # the server.  However at the moment it always falls back to using the
614
 
        # vfs, and this would need some changes in config.py.
 
667
        ## # We should see that branch.get_config() does a single rpc to get the
 
668
        ## # remote configuration file, abstracting away where that is stored on
 
669
        ## # the server.  However at the moment it always falls back to using the
 
670
        ## # vfs, and this would need some changes in config.py.
615
671
 
616
 
        # in an empty branch we decode the response properly
617
 
        client = FakeClient([(('ok', ), '# config file body')], self.get_url())
618
 
        # we need to make a real branch because the remote_branch.control_files
619
 
        # will trigger _ensure_real.
620
 
        branch = self.make_branch('quack')
621
 
        transport = branch.bzrdir.root_transport
622
 
        # we do not want bzrdir to make any remote calls
623
 
        bzrdir = RemoteBzrDir(transport, _client=False)
624
 
        branch = RemoteBranch(bzrdir, None, _client=client)
625
 
        config = branch.get_config()
626
 
        self.assertEqual(
627
 
            [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
628
 
            client._calls)
 
672
        ## # in an empty branch we decode the response properly
 
673
        ## client = FakeClient([(('ok', ), '# config file body')], self.get_url())
 
674
        ## # we need to make a real branch because the remote_branch.control_files
 
675
        ## # will trigger _ensure_real.
 
676
        ## branch = self.make_branch('quack')
 
677
        ## transport = branch.bzrdir.root_transport
 
678
        ## # we do not want bzrdir to make any remote calls
 
679
        ## bzrdir = RemoteBzrDir(transport, _client=False)
 
680
        ## branch = RemoteBranch(bzrdir, None, _client=client)
 
681
        ## config = branch.get_config()
 
682
        ## self.assertEqual(
 
683
        ##     [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
 
684
        ##     client._calls)
629
685
 
630
686
 
631
687
class TestBranchLockWrite(tests.TestCase):
632
688
 
633
689
    def test_lock_write_unlockable(self):
634
690
        transport = MemoryTransport()
635
 
        client = FakeClient([(('UnlockableTransport', ), '')], transport.base)
 
691
        client = FakeClient(transport.base)
 
692
        client.add_error_response('UnlockableTransport')
636
693
        transport.mkdir('quack')
637
694
        transport = transport.clone('quack')
638
695
        # we do not want bzrdir to make any remote calls
647
704
class TestTransportIsReadonly(tests.TestCase):
648
705
 
649
706
    def test_true(self):
650
 
        client = FakeClient([(('yes',), '')])
 
707
        client = FakeClient()
 
708
        client.add_success_response('yes')
651
709
        transport = RemoteTransport('bzr://example.com/', medium=False,
652
710
                                    _client=client)
653
711
        self.assertEqual(True, transport.is_readonly())
656
714
            client._calls)
657
715
 
658
716
    def test_false(self):
659
 
        client = FakeClient([(('no',), '')])
 
717
        client = FakeClient()
 
718
        client.add_success_response('no')
660
719
        transport = RemoteTransport('bzr://example.com/', medium=False,
661
720
                                    _client=client)
662
721
        self.assertEqual(False, transport.is_readonly())
671
730
        advisory anyway (a transport could be read-write, but then the
672
731
        underlying filesystem could be readonly anyway).
673
732
        """
674
 
        client = FakeClient([(('unknown verb', 'Transport.is_readonly'), '')])
 
733
        client = FakeClient()
 
734
        client.add_unknown_method_response('Transport.is_readonly')
675
735
        transport = RemoteTransport('bzr://example.com/', medium=False,
676
736
                                    _client=client)
677
737
        self.assertEqual(False, transport.is_readonly())
688
748
    because they might break compatibility with different-versioned servers.
689
749
    """
690
750
 
691
 
    def setup_fake_client_and_repository(self, responses, transport_path):
 
751
    def setup_fake_client_and_repository(self, transport_path):
692
752
        """Create the fake client and repository for testing with.
693
753
        
694
754
        There's no real server here; we just have canned responses sent
699
759
        """
700
760
        transport = MemoryTransport()
701
761
        transport.mkdir(transport_path)
702
 
        client = FakeClient(responses, transport.base)
 
762
        client = FakeClient(transport.base)
703
763
        transport = transport.clone(transport_path)
704
764
        # we do not want bzrdir to make any remote calls
705
765
        bzrdir = RemoteBzrDir(transport, _client=False)
711
771
 
712
772
    def test_revid_none(self):
713
773
        # ('ok',), body with revisions and size
714
 
        responses = [(('ok', ), 'revisions: 2\nsize: 18\n')]
715
774
        transport_path = 'quack'
716
 
        repo, client = self.setup_fake_client_and_repository(
717
 
            responses, transport_path)
 
775
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
776
        client.add_success_response_with_body(
 
777
            'revisions: 2\nsize: 18\n', 'ok')
718
778
        result = repo.gather_stats(None)
719
779
        self.assertEqual(
720
780
            [('call_expecting_body', 'Repository.gather_stats',
724
784
 
725
785
    def test_revid_no_committers(self):
726
786
        # ('ok',), body without committers
727
 
        responses = [(('ok', ),
728
 
                      'firstrev: 123456.300 3600\n'
729
 
                      'latestrev: 654231.400 0\n'
730
 
                      'revisions: 2\n'
731
 
                      'size: 18\n')]
 
787
        body = ('firstrev: 123456.300 3600\n'
 
788
                'latestrev: 654231.400 0\n'
 
789
                'revisions: 2\n'
 
790
                'size: 18\n')
732
791
        transport_path = 'quick'
733
792
        revid = u'\xc8'.encode('utf8')
734
 
        repo, client = self.setup_fake_client_and_repository(
735
 
            responses, transport_path)
 
793
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
794
        client.add_success_response_with_body(body, 'ok')
736
795
        result = repo.gather_stats(revid)
737
796
        self.assertEqual(
738
797
            [('call_expecting_body', 'Repository.gather_stats',
745
804
 
746
805
    def test_revid_with_committers(self):
747
806
        # ('ok',), body with committers
748
 
        responses = [(('ok', ),
749
 
                      'committers: 128\n'
750
 
                      'firstrev: 123456.300 3600\n'
751
 
                      'latestrev: 654231.400 0\n'
752
 
                      'revisions: 2\n'
753
 
                      'size: 18\n')]
 
807
        body = ('committers: 128\n'
 
808
                'firstrev: 123456.300 3600\n'
 
809
                'latestrev: 654231.400 0\n'
 
810
                'revisions: 2\n'
 
811
                'size: 18\n')
754
812
        transport_path = 'buick'
755
813
        revid = u'\xc8'.encode('utf8')
756
 
        repo, client = self.setup_fake_client_and_repository(
757
 
            responses, transport_path)
 
814
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
815
        client.add_success_response_with_body(body, 'ok')
758
816
        result = repo.gather_stats(revid, True)
759
817
        self.assertEqual(
760
818
            [('call_expecting_body', 'Repository.gather_stats',
772
830
    def test_get_graph(self):
773
831
        # get_graph returns a graph with the repository as the
774
832
        # parents_provider.
775
 
        responses = []
776
833
        transport_path = 'quack'
777
 
        repo, client = self.setup_fake_client_and_repository(
778
 
            responses, transport_path)
 
834
        repo, client = self.setup_fake_client_and_repository(transport_path)
779
835
        graph = repo.get_graph()
780
836
        self.assertEqual(graph._parents_provider, repo)
781
837
 
789
845
        r2 = u'\u0dab'.encode('utf8')
790
846
        lines = [' '.join([r2, r1]), r1]
791
847
        encoded_body = bz2.compress('\n'.join(lines))
792
 
        responses = [(('ok', ), encoded_body), (('ok', ), encoded_body)]
793
848
 
794
849
        transport_path = 'quack'
795
 
        repo, client = self.setup_fake_client_and_repository(
796
 
            responses, transport_path)
 
850
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
851
        client.add_success_response_with_body(encoded_body, 'ok')
 
852
        client.add_success_response_with_body(encoded_body, 'ok')
797
853
        repo.lock_read()
798
854
        graph = repo.get_graph()
799
855
        parents = graph.get_parent_map([r2])
823
879
        repo.unlock()
824
880
 
825
881
    def test_get_parent_map_reconnects_if_unknown_method(self):
826
 
        responses = [
827
 
            (('unknown verb', 'Repository.get_parent_map'), ''),
828
 
            (('ok',), '')]
829
882
        transport_path = 'quack'
830
 
        repo, client = self.setup_fake_client_and_repository(
831
 
            responses, transport_path)
 
883
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
884
        client.add_unknown_method_response('Repository,get_parent_map')
 
885
        client.add_success_response_with_body('', 'ok')
832
886
        self.assertTrue(client._medium._remote_is_at_least_1_2)
833
887
        rev_id = 'revision-id'
834
888
        expected_deprecations = [
858
912
        This is the test for https://bugs.launchpad.net/bzr/+bug/214894
859
913
        """
860
914
        rev_id = 'revision-id'
861
 
        responses = [(('ok',), rev_id)]
862
915
        transport_path = 'quack'
863
 
        repo, client = self.setup_fake_client_and_repository(
864
 
            responses, transport_path)
 
916
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
917
        client.add_success_response_with_body(rev_id, 'ok')
865
918
        client._medium._remote_is_at_least_1_2 = False
866
919
        expected_deprecations = [
867
920
            'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
875
928
        self.assertEqual({rev_id: ('null:',)}, parents)
876
929
 
877
930
    def test_get_parent_map_unexpected_response(self):
878
 
        responses = [
879
 
            (('something unexpected!',), '')]
880
 
        repo, client = self.setup_fake_client_and_repository(responses, 'path')
 
931
        repo, client = self.setup_fake_client_and_repository('path')
 
932
        client.add_success_response('something unexpected!')
881
933
        self.assertRaises(
882
934
            errors.UnexpectedSmartServerResponse,
883
935
            repo.get_parent_map, ['a-revision-id'])
888
940
    def test_null_revision(self):
889
941
        # a null revision has the predictable result {}, we should have no wire
890
942
        # traffic when calling it with this argument
891
 
        responses = [(('notused', ), '')]
892
943
        transport_path = 'empty'
893
 
        repo, client = self.setup_fake_client_and_repository(
894
 
            responses, transport_path)
 
944
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
945
        client.add_success_response('notused')
895
946
        result = self.applyDeprecated(one_four, repo.get_revision_graph,
896
947
            NULL_REVISION)
897
948
        self.assertEqual([], client._calls)
904
955
        lines = [' '.join([r2, r1]), r1]
905
956
        encoded_body = '\n'.join(lines)
906
957
 
907
 
        responses = [(('ok', ), encoded_body)]
908
958
        transport_path = 'sinhala'
909
 
        repo, client = self.setup_fake_client_and_repository(
910
 
            responses, transport_path)
 
959
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
960
        client.add_success_response_with_body(encoded_body, 'ok')
911
961
        result = self.applyDeprecated(one_four, repo.get_revision_graph)
912
962
        self.assertEqual(
913
963
            [('call_expecting_body', 'Repository.get_revision_graph',
924
974
        lines = [' '.join([r2, r11, r12]), r11, r12]
925
975
        encoded_body = '\n'.join(lines)
926
976
 
927
 
        responses = [(('ok', ), encoded_body)]
928
977
        transport_path = 'sinhala'
929
 
        repo, client = self.setup_fake_client_and_repository(
930
 
            responses, transport_path)
 
978
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
979
        client.add_success_response_with_body(encoded_body, 'ok')
931
980
        result = self.applyDeprecated(one_four, repo.get_revision_graph, r2)
932
981
        self.assertEqual(
933
982
            [('call_expecting_body', 'Repository.get_revision_graph',
937
986
 
938
987
    def test_no_such_revision(self):
939
988
        revid = '123'
940
 
        responses = [(('nosuchrevision', revid), '')]
941
989
        transport_path = 'sinhala'
942
 
        repo, client = self.setup_fake_client_and_repository(
943
 
            responses, transport_path)
 
990
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
991
        client.add_error_response('nosuchrevision', revid)
944
992
        # also check that the right revision is reported in the error
945
993
        self.assertRaises(errors.NoSuchRevision,
946
994
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
949
997
             ('sinhala/', revid))],
950
998
            client._calls)
951
999
 
 
1000
    def test_unexpected_error(self):
 
1001
        revid = '123'
 
1002
        transport_path = 'sinhala'
 
1003
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1004
        client.add_error_response('AnUnexpectedError')
 
1005
        e = self.assertRaises(errors.ErrorFromSmartServer,
 
1006
            self.applyDeprecated, one_four, repo.get_revision_graph, revid)
 
1007
        self.assertEqual(('AnUnexpectedError',), e.error_tuple)
 
1008
 
952
1009
        
953
1010
class TestRepositoryIsShared(TestRemoteRepository):
954
1011
 
955
1012
    def test_is_shared(self):
956
1013
        # ('yes', ) for Repository.is_shared -> 'True'.
957
 
        responses = [(('yes', ), )]
958
1014
        transport_path = 'quack'
959
 
        repo, client = self.setup_fake_client_and_repository(
960
 
            responses, transport_path)
 
1015
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1016
        client.add_success_response('yes')
961
1017
        result = repo.is_shared()
962
1018
        self.assertEqual(
963
1019
            [('call', 'Repository.is_shared', ('quack/',))],
966
1022
 
967
1023
    def test_is_not_shared(self):
968
1024
        # ('no', ) for Repository.is_shared -> 'False'.
969
 
        responses = [(('no', ), )]
970
1025
        transport_path = 'qwack'
971
 
        repo, client = self.setup_fake_client_and_repository(
972
 
            responses, transport_path)
 
1026
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1027
        client.add_success_response('no')
973
1028
        result = repo.is_shared()
974
1029
        self.assertEqual(
975
1030
            [('call', 'Repository.is_shared', ('qwack/',))],
980
1035
class TestRepositoryLockWrite(TestRemoteRepository):
981
1036
 
982
1037
    def test_lock_write(self):
983
 
        responses = [(('ok', 'a token'), '')]
984
1038
        transport_path = 'quack'
985
 
        repo, client = self.setup_fake_client_and_repository(
986
 
            responses, transport_path)
 
1039
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1040
        client.add_success_response('ok', 'a token')
987
1041
        result = repo.lock_write()
988
1042
        self.assertEqual(
989
1043
            [('call', 'Repository.lock_write', ('quack/', ''))],
991
1045
        self.assertEqual('a token', result)
992
1046
 
993
1047
    def test_lock_write_already_locked(self):
994
 
        responses = [(('LockContention', ), '')]
995
1048
        transport_path = 'quack'
996
 
        repo, client = self.setup_fake_client_and_repository(
997
 
            responses, transport_path)
 
1049
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1050
        client.add_error_response('LockContention')
998
1051
        self.assertRaises(errors.LockContention, repo.lock_write)
999
1052
        self.assertEqual(
1000
1053
            [('call', 'Repository.lock_write', ('quack/', ''))],
1001
1054
            client._calls)
1002
1055
 
1003
1056
    def test_lock_write_unlockable(self):
1004
 
        responses = [(('UnlockableTransport', ), '')]
1005
1057
        transport_path = 'quack'
1006
 
        repo, client = self.setup_fake_client_and_repository(
1007
 
            responses, transport_path)
 
1058
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1059
        client.add_error_response('UnlockableTransport')
1008
1060
        self.assertRaises(errors.UnlockableTransport, repo.lock_write)
1009
1061
        self.assertEqual(
1010
1062
            [('call', 'Repository.lock_write', ('quack/', ''))],
1014
1066
class TestRepositoryUnlock(TestRemoteRepository):
1015
1067
 
1016
1068
    def test_unlock(self):
1017
 
        responses = [(('ok', 'a token'), ''),
1018
 
                     (('ok',), '')]
1019
1069
        transport_path = 'quack'
1020
 
        repo, client = self.setup_fake_client_and_repository(
1021
 
            responses, transport_path)
 
1070
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1071
        client.add_success_response('ok', 'a token')
 
1072
        client.add_success_response('ok')
1022
1073
        repo.lock_write()
1023
1074
        repo.unlock()
1024
1075
        self.assertEqual(
1028
1079
 
1029
1080
    def test_unlock_wrong_token(self):
1030
1081
        # If somehow the token is wrong, unlock will raise TokenMismatch.
1031
 
        responses = [(('ok', 'a token'), ''),
1032
 
                     (('TokenMismatch',), '')]
1033
1082
        transport_path = 'quack'
1034
 
        repo, client = self.setup_fake_client_and_repository(
1035
 
            responses, transport_path)
 
1083
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1084
        client.add_success_response('ok', 'a token')
 
1085
        client.add_error_response('TokenMismatch')
1036
1086
        repo.lock_write()
1037
1087
        self.assertRaises(errors.TokenMismatch, repo.unlock)
1038
1088
 
1042
1092
    def test_none(self):
1043
1093
        # repo.has_revision(None) should not cause any traffic.
1044
1094
        transport_path = 'quack'
1045
 
        responses = None
1046
 
        repo, client = self.setup_fake_client_and_repository(
1047
 
            responses, transport_path)
 
1095
        repo, client = self.setup_fake_client_and_repository(transport_path)
1048
1096
 
1049
1097
        # The null revision is always there, so has_revision(None) == True.
1050
1098
        self.assertEqual(True, repo.has_revision(NULL_REVISION))
1074
1122
    def test_repository_tarball(self):
1075
1123
        # Test that Repository.tarball generates the right operations
1076
1124
        transport_path = 'repo'
1077
 
        expected_responses = [(('ok',), self.tarball_content),
1078
 
            ]
1079
1125
        expected_calls = [('call_expecting_body', 'Repository.tarball',
1080
1126
                           ('repo/', 'bz2',),),
1081
1127
            ]
1082
 
        remote_repo, client = self.setup_fake_client_and_repository(
1083
 
            expected_responses, transport_path)
 
1128
        repo, client = self.setup_fake_client_and_repository(transport_path)
 
1129
        client.add_success_response_with_body(self.tarball_content, 'ok')
1084
1130
        # Now actually ask for the tarball
1085
 
        tarball_file = remote_repo._get_tarball('bz2')
 
1131
        tarball_file = repo._get_tarball('bz2')
1086
1132
        try:
1087
1133
            self.assertEqual(expected_calls, client._calls)
1088
1134
            self.assertEqual(self.tarball_content, tarball_file.read())