141
141
call, using the second element of the tuple as the verb in the
144
self.responses = responses
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))
149
def add_success_response(self, *args):
150
self.responses.append(('success', args, None))
152
def add_success_response_with_body(self, body, *args):
153
self.responses.append(('success', args, body))
155
def add_error_response(self, *args):
156
self.responses.append(('error', args))
158
def add_unknown_method_response(self, verb):
159
self.responses.append(('unknown', verb))
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
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]
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)
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,
168
182
result = self._get_next_response()
169
183
self.expecting_body = True
170
return result[0], FakeProtocol(result[1], self)
173
class FakeMedium(object):
175
def __init__(self, client_calls):
176
self._remote_is_at_least_1_2 = True
184
return result[1], FakeProtocol(result[2], self)
187
class FakeMedium(medium.SmartClientMedium):
189
def __init__(self, client_calls, base):
190
medium.SmartClientMedium.__init__(self, base)
177
191
self._client_calls = client_calls
179
193
def disconnect(self):
193
208
self.assertTrue(result)
196
class Test_SmartClient_remote_path_from_transport(tests.TestCase):
197
"""Tests for the behaviour of _SmartClient.remote_path_from_transport."""
211
class Test_ClientMedium_remote_path_from_transport(tests.TestCase):
212
"""Tests for the behaviour of client_medium.remote_path_from_transport."""
199
214
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.
215
"""Assert that the result of
216
SmartClientMedium.remote_path_from_transport is the expected value for
217
a given client_base and transport_base.
203
dummy_medium = 'dummy medium'
204
client = _SmartClient(dummy_medium, client_base)
219
client_medium = medium.SmartClientMedium(client_base)
205
220
transport = get_transport(transport_base)
206
result = client.remote_path_from_transport(transport)
221
result = client_medium.remote_path_from_transport(transport)
207
222
self.assertEqual(expected, result)
209
224
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.
225
"""SmartClientMedium.remote_path_from_transport calculates a URL for
226
the given transport relative to the root of the client base URL.
213
228
self.assertRemotePath('xyz/', 'bzr://host/path', 'bzr://host/xyz')
214
229
self.assertRemotePath(
215
230
'path/xyz/', 'bzr://host/path', 'bzr://host/path/xyz')
232
def assertRemotePathHTTP(self, expected, transport_base, relpath):
233
"""Assert that the result of
234
HttpTransportBase.remote_path_from_transport is the expected value for
235
a given transport_base and relpath of that transport. (Note that
236
HttpTransportBase is a subclass of SmartClientMedium)
238
base_transport = get_transport(transport_base)
239
client_medium = base_transport.get_smart_medium()
240
cloned_transport = base_transport.clone(relpath)
241
result = client_medium.remote_path_from_transport(cloned_transport)
242
self.assertEqual(expected, result)
217
244
def test_remote_path_from_transport_http(self):
218
245
"""Remote paths for HTTP transports are calculated differently to other
219
246
transports. They are just relative to the client base, not the root
220
247
directory of the host.
222
249
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')
250
self.assertRemotePathHTTP(
251
'../xyz/', scheme + '//host/path', '../xyz/')
252
self.assertRemotePathHTTP(
253
'xyz/', scheme + '//host/path', 'xyz/')
256
class Test_ClientMedium_remote_is_at_least(tests.TestCase):
257
"""Tests for the behaviour of client_medium.remote_is_at_least."""
259
def test_initially_unlimited(self):
260
"""A fresh medium assumes that the remote side supports all
263
client_medium = medium.SmartClientMedium('dummy base')
264
self.assertFalse(client_medium._is_remote_before((99, 99)))
266
def test__remember_remote_is_before(self):
267
"""Calling _remember_remote_is_before ratchets down the known remote
270
client_medium = medium.SmartClientMedium('dummy base')
271
# Mark the remote side as being less than 1.6. The remote side may
273
client_medium._remember_remote_is_before((1, 6))
274
self.assertTrue(client_medium._is_remote_before((1, 6)))
275
self.assertFalse(client_medium._is_remote_before((1, 5)))
276
# Calling _remember_remote_is_before again with a lower value works.
277
client_medium._remember_remote_is_before((1, 5))
278
self.assertTrue(client_medium._is_remote_before((1, 5)))
279
# You cannot call _remember_remote_is_before with a larger value.
281
AssertionError, client_medium._remember_remote_is_before, (1, 9))
229
284
class TestBzrDirOpenBranch(tests.TestCase):
232
287
transport = MemoryTransport()
233
288
transport.mkdir('quack')
234
289
transport = transport.clone('quack')
235
client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
290
client = FakeClient(transport.base)
291
client.add_success_response('ok', '')
292
client.add_success_response('ok', '', 'no', 'no', 'no')
237
293
bzrdir = RemoteBzrDir(transport, _client=client)
238
294
result = bzrdir.open_branch()
239
295
self.assertEqual(
274
331
def test_url_quoting_of_path(self):
275
332
# Relpaths on the wire should not be URL-escaped. So "~" should be
276
333
# transmitted as "~", not "%7E".
277
transport = RemoteTransport('bzr://localhost/~hello/')
278
client = FakeClient([(('ok', ''), ), (('ok', '', 'no', 'no', 'no'), )],
334
transport = RemoteTCPTransport('bzr://localhost/~hello/')
335
client = FakeClient(transport.base)
336
client.add_success_response('ok', '')
337
client.add_success_response('ok', '', 'no', 'no', 'no')
280
338
bzrdir = RemoteBzrDir(transport, _client=client)
281
339
result = bzrdir.open_branch()
282
340
self.assertEqual(
330
388
transport = MemoryTransport()
331
389
transport.mkdir('quack')
332
390
transport = transport.clone('quack')
333
client = FakeClient([
334
(('unknown verb', 'RemoteRepository.find_repositoryV2'), ''),
335
(('ok', '', 'no', 'no'), ''),],
391
client = FakeClient(transport.base)
392
client.add_unknown_method_response('RemoteRepository.find_repositoryV2')
393
client.add_success_response('ok', '', 'no', 'no')
337
394
bzrdir = RemoteBzrDir(transport, _client=client)
338
395
repo = bzrdir.open_repository()
339
396
self.assertEqual(
415
474
transport.mkdir('branch')
416
475
transport = transport.clone('branch')
418
client = FakeClient([
420
(('ok', 'branch token', 'repo token'), ),
477
client = FakeClient(transport.base)
479
client.add_success_response('ok', 'branch token', 'repo token')
481
client.add_success_response('ok')
483
client.add_success_response('ok')
426
484
bzrdir = RemoteBzrDir(transport, _client=False)
427
485
branch = RemoteBranch(bzrdir, None, _client=client)
428
486
# This is a hack to work around the problem that RemoteBranch currently
445
503
transport.mkdir('branch')
446
504
transport = transport.clone('branch')
448
client = FakeClient([
450
(('ok', 'branch token', 'repo token'), ),
506
client = FakeClient(transport.base)
508
client.add_success_response('ok', 'branch token', 'repo token')
510
client.add_success_response('ok')
512
client.add_success_response('ok')
456
513
bzrdir = RemoteBzrDir(transport, _client=False)
457
514
branch = RemoteBranch(bzrdir, None, _client=client)
458
515
# This is a hack to work around the problem that RemoteBranch currently
471
528
self.assertEqual(None, result)
473
530
def test_no_such_revision(self):
474
# A response of 'NoSuchRevision' is translated into an exception.
475
client = FakeClient([
477
(('ok', 'branch token', 'repo token'), ),
479
(('NoSuchRevision', 'rev-id'), ),
482
531
transport = MemoryTransport()
483
532
transport.mkdir('branch')
484
533
transport = transport.clone('branch')
534
# A response of 'NoSuchRevision' is translated into an exception.
535
client = FakeClient(transport.base)
537
client.add_success_response('ok', 'branch token', 'repo token')
539
client.add_error_response('NoSuchRevision', 'rev-id')
541
client.add_success_response('ok')
486
543
bzrdir = RemoteBzrDir(transport, _client=False)
487
544
branch = RemoteBranch(bzrdir, None, _client=client)
502
559
transport = MemoryTransport()
503
560
transport.mkdir('branch')
504
561
transport = transport.clone('branch')
505
client = FakeClient([
507
(('ok', 'branch token', 'repo token'), ),
508
# set_last_revision_info
511
(('ok',), )], transport.base)
562
client = FakeClient(transport.base)
564
client.add_success_response('ok', 'branch token', 'repo token')
566
client.add_success_response('ok')
568
client.add_success_response('ok')
513
570
bzrdir = RemoteBzrDir(transport, _client=False)
514
571
branch = RemoteBranch(bzrdir, None, _client=client)
529
586
def test_no_such_revision(self):
530
587
# A response of 'NoSuchRevision' is translated into an exception.
531
client = FakeClient([
533
(('ok', 'branch token', 'repo token'), ),
534
# set_last_revision_info
535
(('NoSuchRevision', 'revid'), ),
539
588
transport = MemoryTransport()
540
589
transport.mkdir('branch')
541
590
transport = transport.clone('branch')
591
client = FakeClient(transport.base)
593
client.add_success_response('ok', 'branch token', 'repo token')
595
client.add_error_response('NoSuchRevision', 'revid')
597
client.add_success_response('ok')
543
599
bzrdir = RemoteBzrDir(transport, _client=False)
544
600
branch = RemoteBranch(bzrdir, None, _client=client)
601
658
[('set_last_revision_info', 1234, 'a-revision-id')],
602
659
real_branch.calls)
661
def test_unexpected_error(self):
662
# A response of 'NoSuchRevision' is translated into an exception.
663
transport = MemoryTransport()
664
transport.mkdir('branch')
665
transport = transport.clone('branch')
666
client = FakeClient(transport.base)
668
client.add_success_response('ok', 'branch token', 'repo token')
670
client.add_error_response('UnexpectedError')
672
client.add_success_response('ok')
674
bzrdir = RemoteBzrDir(transport, _client=False)
675
branch = RemoteBranch(bzrdir, None, _client=client)
676
# This is a hack to work around the problem that RemoteBranch currently
677
# unnecessarily invokes _ensure_real upon a call to lock_write.
678
branch._ensure_real = lambda: None
679
# Lock the branch, reset the record of remote calls.
683
err = self.assertRaises(
684
errors.ErrorFromSmartServer,
685
branch.set_last_revision_info, 123, 'revid')
686
self.assertEqual(('UnexpectedError',), err.error_tuple)
605
690
class TestBranchControlGetBranchConf(tests.TestCaseWithMemoryTransport):
606
691
"""Getting the branch configuration should use an abstract method not vfs.
609
694
def test_get_branch_conf(self):
610
695
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.
696
## # We should see that branch.get_config() does a single rpc to get the
697
## # remote configuration file, abstracting away where that is stored on
698
## # the server. However at the moment it always falls back to using the
699
## # vfs, and this would need some changes in config.py.
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()
627
[('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
701
## # in an empty branch we decode the response properly
702
## client = FakeClient([(('ok', ), '# config file body')], self.get_url())
703
## # we need to make a real branch because the remote_branch.control_files
704
## # will trigger _ensure_real.
705
## branch = self.make_branch('quack')
706
## transport = branch.bzrdir.root_transport
707
## # we do not want bzrdir to make any remote calls
708
## bzrdir = RemoteBzrDir(transport, _client=False)
709
## branch = RemoteBranch(bzrdir, None, _client=client)
710
## config = branch.get_config()
712
## [('call_expecting_body', 'Branch.get_config_file', ('quack/',))],
631
716
class TestBranchLockWrite(tests.TestCase):
633
718
def test_lock_write_unlockable(self):
634
719
transport = MemoryTransport()
635
client = FakeClient([(('UnlockableTransport', ), '')], transport.base)
720
client = FakeClient(transport.base)
721
client.add_error_response('UnlockableTransport')
636
722
transport.mkdir('quack')
637
723
transport = transport.clone('quack')
638
724
# we do not want bzrdir to make any remote calls
712
801
def test_revid_none(self):
713
802
# ('ok',), body with revisions and size
714
responses = [(('ok', ), 'revisions: 2\nsize: 18\n')]
715
803
transport_path = 'quack'
716
repo, client = self.setup_fake_client_and_repository(
717
responses, transport_path)
804
repo, client = self.setup_fake_client_and_repository(transport_path)
805
client.add_success_response_with_body(
806
'revisions: 2\nsize: 18\n', 'ok')
718
807
result = repo.gather_stats(None)
719
808
self.assertEqual(
720
809
[('call_expecting_body', 'Repository.gather_stats',
725
814
def test_revid_no_committers(self):
726
815
# ('ok',), body without committers
727
responses = [(('ok', ),
728
'firstrev: 123456.300 3600\n'
729
'latestrev: 654231.400 0\n'
816
body = ('firstrev: 123456.300 3600\n'
817
'latestrev: 654231.400 0\n'
732
820
transport_path = 'quick'
733
821
revid = u'\xc8'.encode('utf8')
734
repo, client = self.setup_fake_client_and_repository(
735
responses, transport_path)
822
repo, client = self.setup_fake_client_and_repository(transport_path)
823
client.add_success_response_with_body(body, 'ok')
736
824
result = repo.gather_stats(revid)
737
825
self.assertEqual(
738
826
[('call_expecting_body', 'Repository.gather_stats',
746
834
def test_revid_with_committers(self):
747
835
# ('ok',), body with committers
748
responses = [(('ok', ),
750
'firstrev: 123456.300 3600\n'
751
'latestrev: 654231.400 0\n'
836
body = ('committers: 128\n'
837
'firstrev: 123456.300 3600\n'
838
'latestrev: 654231.400 0\n'
754
841
transport_path = 'buick'
755
842
revid = u'\xc8'.encode('utf8')
756
repo, client = self.setup_fake_client_and_repository(
757
responses, transport_path)
843
repo, client = self.setup_fake_client_and_repository(transport_path)
844
client.add_success_response_with_body(body, 'ok')
758
845
result = repo.gather_stats(revid, True)
759
846
self.assertEqual(
760
847
[('call_expecting_body', 'Repository.gather_stats',
789
874
r2 = u'\u0dab'.encode('utf8')
790
875
lines = [' '.join([r2, r1]), r1]
791
876
encoded_body = bz2.compress('\n'.join(lines))
792
responses = [(('ok', ), encoded_body), (('ok', ), encoded_body)]
794
878
transport_path = 'quack'
795
repo, client = self.setup_fake_client_and_repository(
796
responses, transport_path)
879
repo, client = self.setup_fake_client_and_repository(transport_path)
880
client.add_success_response_with_body(encoded_body, 'ok')
881
client.add_success_response_with_body(encoded_body, 'ok')
798
883
graph = repo.get_graph()
799
884
parents = graph.get_parent_map([r2])
825
910
def test_get_parent_map_reconnects_if_unknown_method(self):
827
(('unknown verb', 'Repository.get_parent_map'), ''),
829
911
transport_path = 'quack'
830
repo, client = self.setup_fake_client_and_repository(
831
responses, transport_path)
832
self.assertTrue(client._medium._remote_is_at_least_1_2)
912
repo, client = self.setup_fake_client_and_repository(transport_path)
913
client.add_unknown_method_response('Repository,get_parent_map')
914
client.add_success_response_with_body('', 'ok')
915
self.assertFalse(client._medium._is_remote_before((1, 2)))
833
916
rev_id = 'revision-id'
834
917
expected_deprecations = [
835
918
'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
858
941
This is the test for https://bugs.launchpad.net/bzr/+bug/214894
860
943
rev_id = 'revision-id'
861
responses = [(('ok',), rev_id)]
862
944
transport_path = 'quack'
863
repo, client = self.setup_fake_client_and_repository(
864
responses, transport_path)
865
client._medium._remote_is_at_least_1_2 = False
945
repo, client = self.setup_fake_client_and_repository(transport_path)
946
client.add_success_response_with_body(rev_id, 'ok')
947
client._medium._remember_remote_is_before((1, 2))
866
948
expected_deprecations = [
867
949
'bzrlib.remote.RemoteRepository.get_revision_graph was deprecated '
868
950
'in version 1.4.']
888
969
def test_null_revision(self):
889
970
# a null revision has the predictable result {}, we should have no wire
890
971
# traffic when calling it with this argument
891
responses = [(('notused', ), '')]
892
972
transport_path = 'empty'
893
repo, client = self.setup_fake_client_and_repository(
894
responses, transport_path)
973
repo, client = self.setup_fake_client_and_repository(transport_path)
974
client.add_success_response('notused')
895
975
result = self.applyDeprecated(one_four, repo.get_revision_graph,
897
977
self.assertEqual([], client._calls)
904
984
lines = [' '.join([r2, r1]), r1]
905
985
encoded_body = '\n'.join(lines)
907
responses = [(('ok', ), encoded_body)]
908
987
transport_path = 'sinhala'
909
repo, client = self.setup_fake_client_and_repository(
910
responses, transport_path)
988
repo, client = self.setup_fake_client_and_repository(transport_path)
989
client.add_success_response_with_body(encoded_body, 'ok')
911
990
result = self.applyDeprecated(one_four, repo.get_revision_graph)
912
991
self.assertEqual(
913
992
[('call_expecting_body', 'Repository.get_revision_graph',
924
1003
lines = [' '.join([r2, r11, r12]), r11, r12]
925
1004
encoded_body = '\n'.join(lines)
927
responses = [(('ok', ), encoded_body)]
928
1006
transport_path = 'sinhala'
929
repo, client = self.setup_fake_client_and_repository(
930
responses, transport_path)
1007
repo, client = self.setup_fake_client_and_repository(transport_path)
1008
client.add_success_response_with_body(encoded_body, 'ok')
931
1009
result = self.applyDeprecated(one_four, repo.get_revision_graph, r2)
932
1010
self.assertEqual(
933
1011
[('call_expecting_body', 'Repository.get_revision_graph',
938
1016
def test_no_such_revision(self):
940
responses = [(('nosuchrevision', revid), '')]
941
1018
transport_path = 'sinhala'
942
repo, client = self.setup_fake_client_and_repository(
943
responses, transport_path)
1019
repo, client = self.setup_fake_client_and_repository(transport_path)
1020
client.add_error_response('nosuchrevision', revid)
944
1021
# also check that the right revision is reported in the error
945
1022
self.assertRaises(errors.NoSuchRevision,
946
1023
self.applyDeprecated, one_four, repo.get_revision_graph, revid)
949
1026
('sinhala/', revid))],
1029
def test_unexpected_error(self):
1031
transport_path = 'sinhala'
1032
repo, client = self.setup_fake_client_and_repository(transport_path)
1033
client.add_error_response('AnUnexpectedError')
1034
e = self.assertRaises(errors.ErrorFromSmartServer,
1035
self.applyDeprecated, one_four, repo.get_revision_graph, revid)
1036
self.assertEqual(('AnUnexpectedError',), e.error_tuple)
953
1039
class TestRepositoryIsShared(TestRemoteRepository):
955
1041
def test_is_shared(self):
956
1042
# ('yes', ) for Repository.is_shared -> 'True'.
957
responses = [(('yes', ), )]
958
1043
transport_path = 'quack'
959
repo, client = self.setup_fake_client_and_repository(
960
responses, transport_path)
1044
repo, client = self.setup_fake_client_and_repository(transport_path)
1045
client.add_success_response('yes')
961
1046
result = repo.is_shared()
962
1047
self.assertEqual(
963
1048
[('call', 'Repository.is_shared', ('quack/',))],
967
1052
def test_is_not_shared(self):
968
1053
# ('no', ) for Repository.is_shared -> 'False'.
969
responses = [(('no', ), )]
970
1054
transport_path = 'qwack'
971
repo, client = self.setup_fake_client_and_repository(
972
responses, transport_path)
1055
repo, client = self.setup_fake_client_and_repository(transport_path)
1056
client.add_success_response('no')
973
1057
result = repo.is_shared()
974
1058
self.assertEqual(
975
1059
[('call', 'Repository.is_shared', ('qwack/',))],
980
1064
class TestRepositoryLockWrite(TestRemoteRepository):
982
1066
def test_lock_write(self):
983
responses = [(('ok', 'a token'), '')]
984
1067
transport_path = 'quack'
985
repo, client = self.setup_fake_client_and_repository(
986
responses, transport_path)
1068
repo, client = self.setup_fake_client_and_repository(transport_path)
1069
client.add_success_response('ok', 'a token')
987
1070
result = repo.lock_write()
988
1071
self.assertEqual(
989
1072
[('call', 'Repository.lock_write', ('quack/', ''))],
991
1074
self.assertEqual('a token', result)
993
1076
def test_lock_write_already_locked(self):
994
responses = [(('LockContention', ), '')]
995
1077
transport_path = 'quack'
996
repo, client = self.setup_fake_client_and_repository(
997
responses, transport_path)
1078
repo, client = self.setup_fake_client_and_repository(transport_path)
1079
client.add_error_response('LockContention')
998
1080
self.assertRaises(errors.LockContention, repo.lock_write)
999
1081
self.assertEqual(
1000
1082
[('call', 'Repository.lock_write', ('quack/', ''))],
1003
1085
def test_lock_write_unlockable(self):
1004
responses = [(('UnlockableTransport', ), '')]
1005
1086
transport_path = 'quack'
1006
repo, client = self.setup_fake_client_and_repository(
1007
responses, transport_path)
1087
repo, client = self.setup_fake_client_and_repository(transport_path)
1088
client.add_error_response('UnlockableTransport')
1008
1089
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
1009
1090
self.assertEqual(
1010
1091
[('call', 'Repository.lock_write', ('quack/', ''))],
1029
1109
def test_unlock_wrong_token(self):
1030
1110
# If somehow the token is wrong, unlock will raise TokenMismatch.
1031
responses = [(('ok', 'a token'), ''),
1032
(('TokenMismatch',), '')]
1033
1111
transport_path = 'quack'
1034
repo, client = self.setup_fake_client_and_repository(
1035
responses, transport_path)
1112
repo, client = self.setup_fake_client_and_repository(transport_path)
1113
client.add_success_response('ok', 'a token')
1114
client.add_error_response('TokenMismatch')
1036
1115
repo.lock_write()
1037
1116
self.assertRaises(errors.TokenMismatch, repo.unlock)
1074
1151
def test_repository_tarball(self):
1075
1152
# Test that Repository.tarball generates the right operations
1076
1153
transport_path = 'repo'
1077
expected_responses = [(('ok',), self.tarball_content),
1079
1154
expected_calls = [('call_expecting_body', 'Repository.tarball',
1080
1155
('repo/', 'bz2',),),
1082
remote_repo, client = self.setup_fake_client_and_repository(
1083
expected_responses, transport_path)
1157
repo, client = self.setup_fake_client_and_repository(transport_path)
1158
client.add_success_response_with_body(self.tarball_content, 'ok')
1084
1159
# Now actually ask for the tarball
1085
tarball_file = remote_repo._get_tarball('bz2')
1160
tarball_file = repo._get_tarball('bz2')
1087
1162
self.assertEqual(expected_calls, client._calls)
1088
1163
self.assertEqual(self.tarball_content, tarball_file.read())
1107
1182
self.assertFalse(isinstance(dest_repo, RemoteRepository))
1108
1183
self.assertTrue(isinstance(src_repo, RemoteRepository))
1109
1184
src_repo.copy_content_into(dest_repo)
1112
class TestRepositoryStreamKnitData(TestRemoteRepository):
1114
def make_pack_file(self, records):
1115
pack_file = StringIO()
1116
pack_writer = pack.ContainerWriter(pack_file.write)
1118
for bytes, names in records:
1119
pack_writer.add_bytes_record(bytes, names)
1124
def make_pack_stream(self, records):
1125
pack_serialiser = pack.ContainerSerialiser()
1126
yield pack_serialiser.begin()
1127
for bytes, names in records:
1128
yield pack_serialiser.bytes_record(bytes, names)
1129
yield pack_serialiser.end()
1131
def test_bad_pack_from_server(self):
1132
"""A response with invalid data (e.g. it has a record with multiple
1133
names) triggers an exception.
1135
Not all possible errors will be caught at this stage, but obviously
1136
malformed data should be.
1138
record = ('bytes', [('name1',), ('name2',)])
1139
pack_stream = self.make_pack_stream([record])
1140
responses = [(('ok',), pack_stream), ]
1141
transport_path = 'quack'
1142
repo, client = self.setup_fake_client_and_repository(
1143
responses, transport_path)
1144
search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
1145
stream = repo.get_data_stream_for_search(search)
1146
self.assertRaises(errors.SmartProtocolError, list, stream)
1148
def test_backwards_compatibility(self):
1149
"""If the server doesn't recognise this request, fallback to VFS."""
1151
(('unknown verb', 'Repository.stream_revisions_chunked'), '')]
1152
repo, client = self.setup_fake_client_and_repository(
1154
self.mock_called = False
1155
repo._real_repository = MockRealRepository(self)
1156
search = graph.SearchResult(set(['revid']), set(), 1, set(['revid']))
1157
repo.get_data_stream_for_search(search)
1158
self.assertTrue(self.mock_called)
1159
self.failIf(client.expecting_body,
1160
"The protocol has been left in an unclean state that will cause "
1161
"TooManyConcurrentRequests errors.")
1164
class MockRealRepository(object):
1165
"""Helper class for TestRepositoryStreamKnitData.test_unknown_method."""
1167
def __init__(self, test):
1170
def get_data_stream_for_search(self, search):
1171
self.test.assertEqual(set(['revid']), search.get_keys())
1172
self.test.mock_called = True