103
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
104
test_server.SmartTCPServer_for_testing_v2_only}),
105
106
{'transport_server': test_server.SmartTCPServer_for_testing})]
109
109
super(BasicRemoteObjectTests, self).setUp()
110
110
self.transport = self.get_transport()
164
164
bd = self.make_controldir('unstackable', format='pack-0.92')
165
165
r = bd.create_repository()
166
166
self.assertFalse(r._format.supports_external_lookups)
167
r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
167
r = BzrDir.open_from_transport(
168
t.clone('unstackable')).open_repository()
168
169
self.assertFalse(r._format.supports_external_lookups)
169
170
bd = self.make_controldir('stackable', format='1.9')
170
171
r = bd.create_repository()
229
230
_SmartClient.__init__(self, FakeMedium(self._calls, fake_medium_base))
231
232
def add_expected_call(self, call_name, call_args, response_type,
232
response_args, response_body=None):
233
response_args, response_body=None):
233
234
if self._expected_calls is None:
234
235
self._expected_calls = []
235
236
self._expected_calls.append((call_name, call_args))
252
253
def finished_test(self):
253
254
if self._expected_calls:
254
255
raise AssertionError("%r finished but was still expecting %r"
255
% (self, self._expected_calls[0]))
256
% (self, self._expected_calls[0]))
257
258
def _get_next_response(self):
259
260
response_tuple = self.responses.pop(0)
260
except IndexError as e:
261
raise AssertionError("%r didn't expect any more calls"
262
raise AssertionError("%r didn't expect any more calls" % (self,))
263
263
if response_tuple[0] == b'unknown':
264
264
raise errors.UnknownSmartMethod(response_tuple[1])
265
265
elif response_tuple[0] == b'error':
274
274
next_call = self._expected_calls.pop(0)
275
275
except IndexError:
276
276
raise AssertionError("%r didn't expect any more calls "
278
% (self, method, args,))
278
% (self, method, args,))
279
279
if next_call is None:
281
281
if method != next_call[0] or args != next_call[1]:
282
raise AssertionError("%r expected %r%r "
284
% (self, next_call[0], next_call[1], method, args,))
282
raise AssertionError(
283
"%r expected %r%r but got %r%r" %
284
(self, next_call[0], next_call[1], method, args,))
286
286
def call(self, method, *args):
287
287
self._check_call(method, args)
304
304
def call_with_body_bytes_expecting_body(self, method, args, body):
305
305
self._check_call(method, args)
306
306
self._calls.append(('call_with_body_bytes_expecting_body', method,
308
308
result = self._get_next_response()
309
309
self.expecting_body = True
310
310
return result[1], FakeProtocol(result[2], self)
314
314
# that's what happens a real medium.
315
315
stream = list(stream)
316
316
self._check_call(args[0], args[1:])
317
self._calls.append(('call_with_body_stream', args[0], args[1:], stream))
318
('call_with_body_stream', args[0], args[1:], stream))
318
319
result = self._get_next_response()
319
320
# The second value returned from call_with_body_stream is supposed to
320
321
# be a response_handler object, but so far no tests depend on that.
321
response_handler = None
322
response_handler = None
322
323
return result[1], response_handler
448
449
self.reset_smart_call_log()
449
450
verb = b'BzrDir.cloning_metadir'
450
451
self.disable_verb(verb)
451
format = a_dir.cloning_metadir()
452
a_dir.cloning_metadir()
452
453
call_count = len([call for call in self.hpss_calls if
453
call.call.method == verb])
454
call.call.method == verb])
454
455
self.assertEqual(1, call_count)
456
457
def test_branch_reference(self):
465
466
b'BzrDir.open_branchV3', (b'quack/',),
466
467
b'success', (b'ref', self.get_url('referenced').encode('utf-8'))),
467
468
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
469
470
result = a_controldir.cloning_metadir()
470
471
# We should have got a control dir matching the referenced branch.
471
472
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
472
self.assertEqual(expected._repository_format, result._repository_format)
473
self.assertEqual(expected._repository_format,
474
result._repository_format)
473
475
self.assertEqual(expected._branch_format, result._branch_format)
474
476
self.assertFinished(client)
484
486
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
485
487
b'success', (control_name, b'', (b'branch', b''))),
486
488
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
488
490
result = a_controldir.cloning_metadir()
489
491
# We should have got a reference control dir with default branch and
490
492
# repository formats.
497
499
def test_unknown(self):
498
500
transport = self.get_transport('quack')
499
501
referenced = self.make_branch('referenced')
500
expected = referenced.controldir.cloning_metadir()
502
referenced.controldir.cloning_metadir()
501
503
client = FakeClient(transport.base)
502
504
client.add_expected_call(
503
505
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
504
506
b'success', (b'unknown', b'unknown', (b'branch', b''))),
505
507
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
507
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
509
self.assertRaises(errors.UnknownFormatError,
510
a_controldir.cloning_metadir)
510
513
class TestBzrDirCheckoutMetaDir(TestRemote):
538
541
transport.mkdir('quack')
539
542
transport = transport.clone('quack')
540
543
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
542
545
self.assertRaises(errors.UnknownFormatError,
543
a_controldir.checkout_metadir)
546
a_controldir.checkout_metadir)
544
547
self.assertFinished(client)
557
560
b"": (b"branch", branch_name)}), b"success")
558
561
client.add_success_response(
559
562
b'ok', b'', b'no', b'no', b'no',
560
reference_bzrdir_format.repository_format.network_name())
563
reference_bzrdir_format.repository_format.network_name())
561
564
client.add_error_response(b'NotStacked')
562
565
client.add_success_response(
563
566
b'ok', b'', b'no', b'no', b'no',
564
reference_bzrdir_format.repository_format.network_name())
567
reference_bzrdir_format.repository_format.network_name())
565
568
client.add_error_response(b'NotStacked')
566
569
transport.mkdir('quack')
567
570
transport = transport.clone('quack')
568
571
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
570
573
result = a_controldir.get_branches()
571
574
self.assertEqual({"", "foo"}, set(result.keys()))
572
575
self.assertEqual(
583
586
def test_destroy_default(self):
584
587
transport = self.get_transport('quack')
585
referenced = self.make_branch('referenced')
588
self.make_branch('referenced')
586
589
client = FakeClient(transport.base)
587
590
client.add_expected_call(
588
591
b'BzrDir.destroy_branch', (b'quack/', ),
589
592
b'success', (b'ok',)),
590
593
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
592
595
a_controldir.destroy_branch()
593
596
self.assertFinished(client)
602
605
b'BzrDir.has_workingtree', (b'quack/',),
603
606
b'success', (b'yes',)),
604
607
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
606
609
self.assertTrue(a_controldir.has_workingtree())
607
610
self.assertFinished(client)
613
616
b'BzrDir.has_workingtree', (b'quack/',),
614
617
b'success', (b'no',)),
615
618
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
617
620
self.assertFalse(a_controldir.has_workingtree())
618
621
self.assertFinished(client)
627
630
b'BzrDir.destroy_repository', (b'quack/',),
628
631
b'success', (b'ok',)),
629
632
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
631
634
a_controldir.destroy_repository()
632
635
self.assertFinished(client)
646
649
client.add_expected_call(
647
650
b'BzrDir.open_2.1', (b'quack/',), b'success', (b'no',))
648
651
self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
649
RemoteBzrDirFormat(), _client=client, _force_probe=True)
652
RemoteBzrDirFormat(), _client=client,
650
654
self.assertFinished(client)
652
656
def test_present_without_workingtree(self):
654
658
client.add_expected_call(
655
659
b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'no'))
656
660
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
657
_client=client, _force_probe=True)
661
_client=client, _force_probe=True)
658
662
self.assertIsInstance(bd, RemoteBzrDir)
659
663
self.assertFalse(bd.has_workingtree())
660
664
self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
665
669
client.add_expected_call(
666
670
b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'yes'))
667
671
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
_client=client, _force_probe=True)
672
_client=client, _force_probe=True)
669
673
self.assertIsInstance(bd, RemoteBzrDir)
670
674
self.assertTrue(bd.has_workingtree())
671
675
self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
674
678
def test_backwards_compat(self):
675
679
client, transport = self.make_fake_client_and_transport()
676
680
client.add_expected_call(
677
b'BzrDir.open_2.1', (b'quack/',), b'unknown', (b'BzrDir.open_2.1',))
681
b'BzrDir.open_2.1', (b'quack/',), b'unknown',
682
(b'BzrDir.open_2.1',))
678
683
client.add_expected_call(
679
684
b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
680
685
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
681
_client=client, _force_probe=True)
686
_client=client, _force_probe=True)
682
687
self.assertIsInstance(bd, RemoteBzrDir)
683
688
self.assertFinished(client)
689
694
# the version is 2 also do _remember_remote_is_before((1, 6)) before
690
695
# continuing with the RPC.
691
696
orig_check_call = client._check_call
692
698
def check_call(method, args):
693
699
client._medium._protocol_version = 2
694
700
client._medium._remember_remote_is_before((1, 6))
696
702
client._check_call(method, args)
697
703
client._check_call = check_call
698
704
client.add_expected_call(
699
b'BzrDir.open_2.1', (b'quack/',), b'unknown', (b'BzrDir.open_2.1',))
705
b'BzrDir.open_2.1', (b'quack/',), b'unknown',
706
(b'BzrDir.open_2.1',))
700
707
client.add_expected_call(
701
708
b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
702
709
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
703
_client=client, _force_probe=True)
710
_client=client, _force_probe=True)
704
711
self.assertIsInstance(bd, RemoteBzrDir)
705
712
self.assertFinished(client)
714
721
self.reset_smart_call_log()
715
722
verb = b'BzrDir.open_branchV3'
716
723
self.disable_verb(verb)
717
format = a_dir.open_branch()
718
725
call_count = len([call for call in self.hpss_calls if
719
call.call.method == verb])
726
call.call.method == verb])
720
727
self.assertEqual(1, call_count)
722
729
def test_branch_present(self):
737
744
b'Branch.get_stacked_on_url', (b'quack/',),
738
745
b'error', (b'NotStacked',))
739
746
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
741
748
result = bzrdir.open_branch()
742
749
self.assertIsInstance(result, RemoteBranch)
743
750
self.assertEqual(bzrdir, result.controldir)
750
757
client = FakeClient(transport.base)
751
758
client.add_error_response(b'nobranch')
752
759
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
761
self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
755
762
self.assertEqual(
756
763
[('call', b'BzrDir.open_branchV3', (b'quack/',))],
767
775
# no requests on the network - catches other api calls being made.
768
776
client = FakeClient(transport.base)
769
777
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
771
779
# patch the open_branch call to record that it was called.
772
780
bzrdir.open_branch = open_branch
773
781
self.assertEqual((None, "a-branch"), bzrdir._get_tree_branch())
792
800
b'Branch.get_stacked_on_url', (b'~hello/',),
793
801
b'error', (b'NotStacked',))
794
802
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
796
result = bzrdir.open_branch()
797
805
self.assertFinished(client)
799
def check_open_repository(self, rich_root, subtrees, external_lookup=b'no'):
807
def check_open_repository(self, rich_root, subtrees,
808
external_lookup=b'no'):
800
809
reference_format = self.get_repo_format()
801
810
network_name = reference_format.network_name()
802
811
transport = MemoryTransport()
815
824
b'ok', b'', rich_response, subtree_response, external_lookup,
817
826
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
819
828
result = bzrdir.open_repository()
820
829
self.assertEqual(
821
830
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
847
857
repo = self.make_repository('.')
848
858
self.reset_smart_call_log()
849
859
self.disable_verb(b'BzrDir.create_branch')
850
branch = repo.controldir.create_branch()
851
create_branch_call_count = len([call for call in self.hpss_calls if
852
call.call.method == b'BzrDir.create_branch'])
860
repo.controldir.create_branch()
861
create_branch_call_count = len(
862
[call for call in self.hpss_calls
863
if call.call.method == b'BzrDir.create_branch'])
853
864
self.assertEqual(1, create_branch_call_count)
855
866
def test_current_server(self):
865
876
client.add_expected_call(
866
877
b'BzrDir.create_branch', (b'quack/', network_name),
867
878
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
868
reference_repo_name))
879
reference_repo_name))
869
880
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
871
882
branch = a_controldir.create_branch()
872
883
# We should have got a remote branch
873
884
self.assertIsInstance(branch, remote.RemoteBranch)
893
904
client.add_expected_call(
894
905
b'BzrDir.create_branch', (b'extra/quack/', network_name),
895
906
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
896
reference_repo_name))
907
reference_repo_name))
897
908
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
899
910
branch = a_controldir.create_branch(repository=repo)
900
911
# We should have got a remote branch
901
912
self.assertIsInstance(branch, remote.RemoteBranch)
911
922
bzrdir = self.make_controldir('.')
912
923
self.reset_smart_call_log()
913
924
self.disable_verb(b'BzrDir.create_repository')
914
repo = bzrdir.create_repository()
925
bzrdir.create_repository()
915
926
create_repo_call_count = len([call for call in self.hpss_calls if
916
call.call.method == b'BzrDir.create_repository'])
927
call.call.method == b'BzrDir.create_repository'])
917
928
self.assertEqual(1, create_repo_call_count)
919
930
def test_current_server(self):
926
937
network_name = reference_format.network_name()
927
938
client.add_expected_call(
928
939
b'BzrDir.create_repository', (b'quack/',
929
b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
940
b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
931
942
b'success', (b'ok', b'yes', b'yes', b'yes', network_name))
932
943
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
934
945
repo = a_controldir.create_repository()
935
946
# We should have got a remote repository
936
947
self.assertIsInstance(repo, remote.RemoteRepository)
964
975
# PackRepository wants to do a stat
965
976
client.add_success_response(b'stat', b'0', b'65535')
966
977
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
968
979
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
970
981
repo = bzrdir.open_repository()
971
982
self.assertEqual(
972
983
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
999
1010
# PackRepository wants to do a stat
1000
1011
client.add_success_response(b'stat', b'0', b'65535')
1001
1012
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
1003
1014
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
1005
1016
repo = bzrdir.open_repository()
1006
1017
self.assertEqual(
1007
1018
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1008
1019
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1009
1020
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1010
1021
('call', b'stat', (b'/quack/.bzr',)),
1011
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
1022
('call_expecting_body', b'get',
1023
(b'/quack/.bzr/repository/format',)),
1012
1024
('call', b'stat', (b'/quack/.bzr/repository',)),
1021
1033
transport.mkdir('quack')
1022
1034
transport = transport.clone('quack')
1023
1035
client = FakeClient(transport.base)
1024
client.add_success_response(b'ok', b'', b'no', b'no', b'no', network_name)
1036
client.add_success_response(
1037
b'ok', b'', b'no', b'no', b'no', network_name)
1025
1038
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1027
1040
repo = bzrdir.open_repository()
1028
1041
self.assertEqual(
1029
1042
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
1041
1054
client = FakeClient(transport.base)
1042
1055
client.add_expected_call(
1043
1056
b'BzrDirFormat.initialize_ex_1.16',
1044
(default_format_name, b'path', b'False', b'False', b'False', b'',
1045
b'', b'', b'', b'False'),
1057
(default_format_name, b'path', b'False', b'False', b'False', b'',
1058
b'', b'', b'', b'False'),
1047
(b'.', b'no', b'no', b'yes', b'repo fmt', b'repo bzrdir fmt',
1048
b'bzrdir fmt', b'False', b'', b'', b'repo lock token'))
1060
(b'.', b'no', b'no', b'yes', b'repo fmt', b'repo bzrdir fmt',
1061
b'bzrdir fmt', b'False', b'', b'', b'repo lock token'))
1049
1062
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
1050
1063
# it's currently hard to test that without supplying a real remote
1051
1064
# transport connected to a real server.
1052
result = fmt._initialize_on_transport_ex_rpc(client, b'path',
1053
transport, False, False, False, None, None, None, None, False)
1065
fmt._initialize_on_transport_ex_rpc(
1066
client, b'path', transport, False, False, False, None, None, None,
1054
1068
self.assertFinished(client)
1056
1070
def test_error(self):
1063
1077
client = FakeClient(transport.base)
1064
1078
client.add_expected_call(
1065
1079
b'BzrDirFormat.initialize_ex_1.16',
1066
(default_format_name, b'path', b'False', b'False', b'False', b'',
1067
b'', b'', b'', b'False'),
1080
(default_format_name, b'path', b'False', b'False', b'False', b'',
1081
b'', b'', b'', b'False'),
1069
(b'PermissionDenied', b'path', b'extra info'))
1083
(b'PermissionDenied', b'path', b'extra info'))
1070
1084
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
1071
1085
# it's currently hard to test that without supplying a real remote
1072
1086
# transport connected to a real server.
1073
err = self.assertRaises(errors.PermissionDenied,
1087
err = self.assertRaises(
1088
errors.PermissionDenied,
1074
1089
fmt._initialize_on_transport_ex_rpc, client, b'path', transport,
1075
1090
False, False, False, None, None, None, None, False)
1076
1091
self.assertEqual('path', err.path)
1082
1097
transport = self.make_smart_server('foo')
1083
1098
transport = transport.clone('no-such-path')
1084
1099
fmt = RemoteBzrDirFormat()
1085
err = self.assertRaises(errors.NoSuchFile,
1086
fmt.initialize_on_transport_ex, transport, create_prefix=False)
1101
errors.NoSuchFile, fmt.initialize_on_transport_ex, transport,
1102
create_prefix=False)
1089
1105
class OldSmartClient(object):
1119
1135
def make_remote_bzrdir(self, transport, client):
1120
1136
"""Make a RemotebzrDir using 'client' as the _client."""
1121
1137
return RemoteBzrDir(transport, RemoteBzrDirFormat(),
1125
1141
class RemoteBranchTestCase(RemoteBzrDirTestCase):
1341
1356
b'Branch.get_stacked_on_url', (b'quack/',),
1342
1357
b'error', (b'NotStacked',))
1343
1358
client.add_expected_call(
1344
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1359
b'Branch.set_tags_bytes', (b'quack/',
1360
b'branch token', b'repo token'),
1345
1361
b'success', ('',))
1346
1362
transport.mkdir('quack')
1347
1363
transport = transport.clone('quack')
1358
1374
b'Branch.get_stacked_on_url', (b'quack/',),
1359
1375
b'error', (b'NotStacked',))
1360
1376
client.add_expected_call(
1361
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1377
b'Branch.set_tags_bytes', (b'quack/',
1378
b'branch token', b'repo token'),
1362
1379
b'unknown', (b'Branch.set_tags_bytes',))
1363
1380
transport.mkdir('quack')
1364
1381
transport = transport.clone('quack')
1365
1382
branch = self.make_remote_branch(transport, client)
1366
1383
self.lock_remote_branch(branch)
1367
1385
class StubRealBranch(object):
1368
1386
def __init__(self):
1369
1387
self.calls = []
1370
1389
def _set_tags_bytes(self, bytes):
1371
1390
self.calls.append(('set_tags_bytes', bytes))
1372
1391
real_branch = StubRealBranch()
1534
1553
# doesn't just open in - this test probably needs to be rewritten using
1535
1554
# a spawn()ed server.
1536
1555
stacked_branch = self.make_branch('stacked', format='1.9')
1537
memory_branch = self.make_branch('base', format='1.9')
1556
self.make_branch('base', format='1.9')
1538
1557
vfs_url = self.get_vfs_only_url('base')
1539
1558
stacked_branch.set_stacked_on_url(vfs_url)
1540
1559
transport = stacked_branch.controldir.root_transport
1548
1567
b'Branch.get_stacked_on_url', (b'stacked/',),
1549
1568
b'success', (b'ok', vfs_url.encode('utf-8')))
1550
1569
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1552
1571
repo_fmt = remote.RemoteRepositoryFormat()
1553
1572
repo_fmt._custom_format = stacked_branch.repository._format
1554
1573
branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
1556
1575
result = branch.get_stacked_on_url()
1557
1576
self.assertEqual(vfs_url, result)
1559
1578
def test_backwards_compatible(self):
1560
1579
# like with bzr1.6 with no Branch.get_stacked_on_url rpc
1561
base_branch = self.make_branch('base', format='1.6')
1580
self.make_branch('base', format='1.6')
1562
1581
stacked_branch = self.make_branch('stacked', format='1.6')
1563
1582
stacked_branch.set_stacked_on_url('../base')
1564
1583
client = FakeClient(self.get_url())
1569
1588
client.add_expected_call(
1570
1589
b'BzrDir.find_repositoryV3', (b'stacked/',),
1571
1590
b'success', (b'ok', b'', b'no', b'no', b'yes',
1572
stacked_branch.repository._format.network_name()))
1591
stacked_branch.repository._format.network_name()))
1573
1592
# called twice, once from constructor and then again by us
1574
1593
client.add_expected_call(
1575
1594
b'Branch.get_stacked_on_url', (b'stacked/',),
1580
1599
# this will also do vfs access, but that goes direct to the transport
1581
1600
# and isn't seen by the FakeClient.
1582
1601
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1583
RemoteBzrDirFormat(), _client=client)
1602
RemoteBzrDirFormat(), _client=client)
1584
1603
branch = bzrdir.open_branch()
1585
1604
result = branch.get_stacked_on_url()
1586
1605
self.assertEqual('../base', result)
1590
1609
self.assertEqual(1, len(branch.repository._fallback_repositories))
1591
1610
self.assertEqual(1,
1592
len(branch.repository._real_repository._fallback_repositories))
1611
len(branch.repository._real_repository._fallback_repositories))
1594
1613
def test_get_stacked_on_real_branch(self):
1595
base_branch = self.make_branch('base')
1614
self.make_branch('base')
1596
1615
stacked_branch = self.make_branch('stacked')
1597
1616
stacked_branch.set_stacked_on_url('../base')
1598
1617
reference_format = self.get_repo_format()
1613
1632
b'Branch.get_stacked_on_url', (b'stacked/',),
1614
1633
b'success', (b'ok', b'../base'))
1615
1634
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1616
RemoteBzrDirFormat(), _client=client)
1635
RemoteBzrDirFormat(), _client=client)
1617
1636
branch = bzrdir.open_branch()
1618
1637
result = branch.get_stacked_on_url()
1619
1638
self.assertEqual('../base', result)
1646
1665
b'success', (b'ok', b'0', b'null:'))
1647
1666
client.add_expected_call(
1648
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
1667
b'Branch.set_last_revision', (b'branch/',
1668
b'branch token', b'repo token', b'null:',),
1649
1669
b'success', (b'ok',))
1650
1670
client.add_expected_call(
1651
1671
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1679
1699
encoded_body = bz2.compress(b'\n'.join(lines))
1680
1700
client.add_success_response_with_body(encoded_body, b'ok')
1681
1701
client.add_expected_call(
1682
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
1702
b'Branch.set_last_revision', (b'branch/',
1703
b'branch token', b'repo token', b'rev-id2',),
1683
1704
b'success', (b'ok',))
1684
1705
client.add_expected_call(
1685
1706
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1714
1735
encoded_body = bz2.compress(b'\n'.join(lines))
1715
1736
client.add_success_response_with_body(encoded_body, b'ok')
1716
1737
client.add_expected_call(
1717
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1738
b'Branch.set_last_revision', (b'branch/',
1739
b'branch token', b'repo token', b'rev-id',),
1718
1740
b'error', (b'NoSuchRevision', b'rev-id'))
1719
1741
client.add_expected_call(
1720
1742
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1751
1773
encoded_body = bz2.compress(b'\n'.join(lines))
1752
1774
client.add_success_response_with_body(encoded_body, b'ok')
1753
1775
client.add_expected_call(
1754
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1776
b'Branch.set_last_revision', (b'branch/',
1777
b'branch token', b'repo token', b'rev-id',),
1755
1778
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1756
1779
client.add_expected_call(
1757
1780
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1857
1880
b'unknown', b'Branch.set_last_revision_info')
1859
1882
branch = self.make_remote_branch(transport, client)
1860
1884
class StubRealBranch(object):
1861
1885
def __init__(self):
1862
1886
self.calls = []
1863
1888
def set_last_revision_info(self, revno, revision_id):
1864
1889
self.calls.append(
1865
1890
('set_last_revision_info', revno, revision_id))
1866
1892
def _clear_cached_state(self):
1868
1894
real_branch = StubRealBranch()
1870
1896
self.lock_remote_branch(branch)
1872
1898
# Call set_last_revision_info, and verify it behaved as expected.
1873
result = branch.set_last_revision_info(1234, b'a-revision-id')
1899
branch.set_last_revision_info(1234, b'a-revision-id')
1874
1900
self.assertEqual(
1875
1901
[('set_last_revision_info', 1234, b'a-revision-id')],
1876
1902
real_branch.calls)
1977
2003
b'success', (b'ok', b'branch token', b'repo token'))
1978
2004
client.add_expected_call(
1979
2005
b'Branch.set_config_option', (b'memory:///', b'branch token',
1980
b'repo token', b'foo', b'bar', b''),
2006
b'repo token', b'foo', b'bar', b''),
1981
2007
b'success', ())
1982
2008
client.add_expected_call(
1983
2009
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2001
2027
encoded_dict_value = b'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
2002
2028
client.add_expected_call(
2003
2029
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2004
b'repo token', encoded_dict_value, b'foo', b''),
2030
b'repo token', encoded_dict_value, b'foo', b''),
2005
2031
b'success', ())
2006
2032
client.add_expected_call(
2007
2033
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2016
2042
branch.unlock()
2017
2043
self.assertFinished(client)
2045
def test_set_option_with_bool(self):
2046
client = FakeClient()
2047
client.add_expected_call(
2048
b'Branch.get_stacked_on_url', (b'memory:///',),
2049
b'error', (b'NotStacked',),)
2050
client.add_expected_call(
2051
b'Branch.lock_write', (b'memory:///', b'', b''),
2052
b'success', (b'ok', b'branch token', b'repo token'))
2053
client.add_expected_call(
2054
b'Branch.set_config_option', (b'memory:///', b'branch token',
2055
b'repo token', b'True', b'foo', b''),
2057
client.add_expected_call(
2058
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2059
b'success', (b'ok',))
2060
transport = MemoryTransport()
2061
branch = self.make_remote_branch(transport, client)
2063
config = branch._get_config()
2064
config.set_option(True, 'foo')
2066
self.assertFinished(client)
2019
2068
def test_backwards_compat_set_option(self):
2020
2069
self.setup_smart_server_with_call_log()
2021
2070
branch = self.make_branch('.')
2078
2127
b'success', (b'ok', ), b"# line 1\n")
2079
2128
client.add_expected_call(
2080
2129
b'Branch.put_config_file', (b'memory:///', b'branch token',
2082
2131
b'success', (b'ok',))
2083
2132
client.add_expected_call(
2084
2133
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2093
2142
self.assertEqual(
2094
2143
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2095
2144
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2096
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2097
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2145
('call_expecting_body', b'Branch.get_config_file',
2147
('call_expecting_body', b'Branch.get_config_file',
2098
2149
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2099
2150
(b'memory:///', b'branch token', b'repo token'),
2100
2151
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2101
('call', b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'))],
2152
('call', b'Branch.unlock',
2153
(b'memory:///', b'branch token', b'repo token'))],
2139
2191
branch = self.make_remote_branch(transport, client)
2140
2192
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2141
2193
self.assertRaises(errors.NoSuchRevision,
2142
branch.revision_id_to_revno, b'unknown')
2194
branch.revision_id_to_revno, b'unknown')
2143
2195
self.assertFinished(client)
2145
2197
def test_dotted(self):
2159
2211
branch = self.make_remote_branch(transport, client)
2160
2212
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2161
2213
self.assertRaises(errors.NoSuchRevision,
2162
branch.revision_id_to_dotted_revno, b'unknown')
2214
branch.revision_id_to_dotted_revno, b'unknown')
2163
2215
self.assertFinished(client)
2165
2217
def test_dotted_no_smart_verb(self):
2182
2234
config = bzrdir.get_config()
2183
2235
self.assertEqual('/', config.get_default_stack_on())
2184
2236
self.assertEqual(
2185
[('call_expecting_body', b'BzrDir.get_config_file', (b'memory:///',))],
2237
[('call_expecting_body', b'BzrDir.get_config_file',
2188
2241
def test_set_option_uses_vfs(self):
2248
2301
def test_permissiondenied(self):
2249
2302
client = FakeClient()
2250
client.add_error_response(b'PermissionDenied', b'remote path', b'extra')
2303
client.add_error_response(
2304
b'PermissionDenied', b'remote path', b'extra')
2251
2305
transport = RemoteTransport('bzr://example.com/', medium=False,
2252
2306
_client=client)
2253
2307
exc = self.assertRaises(
2266
2320
conf = config.AuthenticationConfig()
2267
2321
conf._get_config().update(
2268
2322
{'bzr+sshtest': {'scheme': 'ssh', 'user': 'bar', 'host':
2271
2325
t = RemoteSSHTransport('bzr+ssh://example.com')
2272
2326
self.assertEqual('bar', t._get_credentials()[0])
2295
2349
transport = transport.clone(transport_path)
2296
2350
# we do not want bzrdir to make any remote calls
2297
2351
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
2299
2353
repo = RemoteRepository(bzrdir, None, _client=client)
2300
2354
return repo, client
2311
2365
real_format = branch.format_registry.get_default()
2312
2366
remote_format._network_name = real_format.network_name()
2313
2367
self.assertEqual(remoted_description(real_format),
2314
remote_format.get_format_description())
2368
remote_format.get_format_description())
2317
2371
class TestRepositoryFormat(TestRemoteRepository):
2331
2385
real_format = repository.format_registry.get_default()
2332
2386
remote_repo_format._network_name = real_format.network_name()
2333
2387
self.assertEqual(remoted_description(real_format),
2334
remote_repo_format.get_format_description())
2388
remote_repo_format.get_format_description())
2337
2391
class TestRepositoryAllRevisionIds(TestRemoteRepository):
2371
2425
result = repo.gather_stats(None)
2372
2426
self.assertEqual(
2373
2427
[('call_expecting_body', b'Repository.gather_stats',
2374
(b'quack/', b'', b'no'))],
2428
(b'quack/', b'', b'no'))],
2376
2430
self.assertEqual({'revisions': 2, 'size': 18}, result)
2393
2447
self.assertEqual({'revisions': 2, 'size': 18,
2394
2448
'firstrev': (123456.300, 3600),
2395
'latestrev': (654231.400, 0),},
2449
'latestrev': (654231.400, 0), },
2398
2452
def test_revid_with_committers(self):
2414
2468
self.assertEqual({'revisions': 2, 'size': 18,
2415
2469
'committers': 128,
2416
2470
'firstrev': (123456.300, 3600),
2417
'latestrev': (654231.400, 0),},
2471
'latestrev': (654231.400, 0), },
2483
2537
repo, client = self.setup_fake_client_and_repository(transport_path)
2484
2538
client.add_error_response(b'nosuchrevision', b'unknown')
2485
2539
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2487
2541
self.assertEqual(
2488
2542
[('call_expecting_body', b'Repository.get_revision_signature_text',
2489
2543
(b'quick/', b'unknown'))],
2513
2567
b'success', (b'ok', (b'token1', )))
2514
2568
client.add_expected_call(
2515
2569
b'Repository.add_signature_text', (b'quack/', b'a token', b'rev1',
2517
2571
b'success', (b'ok', ), None)
2518
2572
repo.lock_write()
2519
2573
repo.start_write_group()
2521
repo.add_signature_text(b"rev1", b"every bloody emperor"))
2575
None, repo.add_signature_text(b"rev1", b"every bloody emperor"))
2522
2576
self.assertEqual(
2523
2577
('call_with_body_bytes_expecting_body',
2524
b'Repository.add_signature_text',
2578
b'Repository.add_signature_text',
2525
2579
(b'quack/', b'a token', b'rev1', b'token1'),
2526
b'every bloody emperor'),
2580
b'every bloody emperor'),
2527
2581
client._calls[-1])
2552
2606
self.assertEqual({r1: (NULL_REVISION,)}, parents)
2553
2607
self.assertEqual(
2554
2608
[('call_with_body_bytes_expecting_body',
2555
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2609
b'Repository.get_parent_map', (b'quack/',
2610
b'include-missing:', r2),
2563
2618
self.assertEqual({r1: (NULL_REVISION,)}, parents)
2564
2619
self.assertEqual(
2565
2620
[('call_with_body_bytes_expecting_body',
2566
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2621
b'Repository.get_parent_map', (b'quack/',
2622
b'include-missing:', r2),
2568
2624
('call_with_body_bytes_expecting_body',
2569
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r1),
2625
b'Repository.get_parent_map', (b'quack/',
2626
b'include-missing:', r1),
2630
2687
self.addCleanup(repo.unlock)
2631
2688
self.reset_smart_call_log()
2632
2689
graph = repo.get_graph()
2633
self.assertEqual({},
2634
graph.get_parent_map([b'some-missing', b'other-missing']))
2691
{}, graph.get_parent_map([b'some-missing', b'other-missing']))
2635
2692
self.assertLength(1, self.hpss_calls)
2636
2693
# No call if we repeat this
2637
2694
self.reset_smart_call_log()
2638
2695
graph = repo.get_graph()
2639
self.assertEqual({},
2640
graph.get_parent_map([b'some-missing', b'other-missing']))
2697
{}, graph.get_parent_map([b'some-missing', b'other-missing']))
2641
2698
self.assertLength(0, self.hpss_calls)
2642
2699
# Asking for more unknown keys makes a request.
2643
2700
self.reset_smart_call_log()
2644
2701
graph = repo.get_graph()
2645
self.assertEqual({},
2646
graph.get_parent_map([b'some-missing', b'other-missing',
2703
{}, graph.get_parent_map([b'some-missing', b'other-missing',
2648
2705
self.assertLength(1, self.hpss_calls)
2650
2707
def disableExtraResults(self):
2671
2728
graph = repo.get_graph()
2672
2729
# Query for b'first' and b'null:'. Because b'null:' is a parent of
2673
2730
# 'first' it will be a candidate for the stop_keys of subsequent
2674
# requests, and because b'null:' was queried but not returned it will be
2675
# cached as missing.
2731
# requests, and because b'null:' was queried but not returned it will
2732
# be cached as missing.
2676
2733
self.assertEqual({b'first': (b'null:',)},
2677
graph.get_parent_map([b'first', b'null:']))
2734
graph.get_parent_map([b'first', b'null:']))
2678
2735
# Now query for another key. This request will pass along a recipe of
2679
2736
# start and stop keys describing the already cached results, and this
2680
2737
# recipe's revision count must be correct (or else it will trigger an
2725
2783
self.assertEqual([], client._calls)
2726
2784
self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
2727
2785
self.assertEqual({r1: (NULL_REVISION,)},
2728
repo.get_cached_parent_map([r1]))
2786
repo.get_cached_parent_map([r1]))
2729
2787
self.assertEqual(
2730
2788
[('call_with_body_bytes_expecting_body',
2731
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2789
b'Repository.get_parent_map', (b'quack/',
2790
b'include-missing:', r2),
2750
2809
self.assertEqual({}, graph.get_parent_map([b'rev1']))
2751
2810
tree.commit('message', rev_id=b'rev1')
2752
2811
graph = tree.branch.repository.get_graph()
2753
self.assertEqual({b'rev1': (b'null:',)}, graph.get_parent_map([b'rev1']))
2812
self.assertEqual({b'rev1': (b'null:',)},
2813
graph.get_parent_map([b'rev1']))
2756
2816
class TestRepositoryGetRevisions(TestRemoteRepository):
2761
2821
client.add_success_response_with_body(
2762
2822
b'', b'ok', b'10')
2763
2823
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2764
[b'somerev1', b'anotherrev2'])
2824
[b'somerev1', b'anotherrev2'])
2765
2825
self.assertEqual(
2766
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2767
(b'quack/', ), b"somerev1\nanotherrev2")],
2826
[('call_with_body_bytes_expecting_body',
2827
b'Repository.iter_revisions', (b'quack/', ),
2828
b"somerev1\nanotherrev2")],
2770
2831
def test_hpss_get_single_revision(self):
2781
2842
# Split up body into two bits to make sure the zlib compression object
2782
2843
# gets data fed twice.
2783
2844
client.add_success_response_with_body(
2784
[body[:10], body[10:]], b'ok', b'10')
2845
[body[:10], body[10:]], b'ok', b'10')
2785
2846
revs = repo.get_revisions([b'somerev1'])
2786
2847
self.assertEqual(revs, [somerev1])
2787
2848
self.assertEqual(
2788
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2789
(b'quack/', ), b"somerev1")],
2849
[('call_with_body_bytes_expecting_body',
2850
b'Repository.iter_revisions',
2851
(b'quack/', ), b"somerev1")],
2838
2900
result = repo._get_revision_graph(r2)
2839
2901
self.assertEqual(
2840
2902
[('call_expecting_body', b'Repository.get_revision_graph',
2841
(b'sinhala/', r2))],
2903
(b'sinhala/', r2))],
2843
2905
self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2849
2911
client.add_error_response(b'nosuchrevision', revid)
2850
2912
# also check that the right revision is reported in the error
2851
2913
self.assertRaises(errors.NoSuchRevision,
2852
repo._get_revision_graph, revid)
2914
repo._get_revision_graph, revid)
2853
2915
self.assertEqual(
2854
2916
[('call_expecting_body', b'Repository.get_revision_graph',
2855
(b'sinhala/', revid))],
2917
(b'sinhala/', revid))],
2858
2920
def test_unexpected_error(self):
2861
2923
repo, client = self.setup_fake_client_and_repository(transport_path)
2862
2924
client.add_error_response(b'AnUnexpectedError')
2863
2925
e = self.assertRaises(errors.UnknownErrorFromSmartServer,
2864
repo._get_revision_graph, revid)
2926
repo._get_revision_graph, revid)
2865
2927
self.assertEqual((b'AnUnexpectedError',), e.error_tuple)
2870
2932
def test_ok(self):
2871
2933
repo, client = self.setup_fake_client_and_repository('quack')
2872
2934
client.add_expected_call(
2873
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2935
b'Repository.get_rev_id_for_revno', (b'quack/',
2936
5, (42, b'rev-foo')),
2874
2937
b'success', (b'ok', b'rev-five'))
2875
2938
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2876
2939
self.assertEqual((True, b'rev-five'), result)
2879
2942
def test_history_incomplete(self):
2880
2943
repo, client = self.setup_fake_client_and_repository('quack')
2881
2944
client.add_expected_call(
2882
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2945
b'Repository.get_rev_id_for_revno', (b'quack/',
2946
5, (42, b'rev-foo')),
2883
2947
b'success', (b'history-incomplete', 10, b'rev-ten'))
2884
2948
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2885
2949
self.assertEqual((False, (10, b'rev-ten')), result)
2901
2965
repo.add_fallback_repository(fallback_repo)
2902
2966
# First the client should ask the primary repo
2903
2967
client.add_expected_call(
2904
b'Repository.get_rev_id_for_revno', (b'quack/', 1, (42, b'rev-foo')),
2968
b'Repository.get_rev_id_for_revno', (b'quack/',
2969
1, (42, b'rev-foo')),
2905
2970
b'success', (b'history-incomplete', 2, b'rev-two'))
2906
2971
# Then it should ask the fallback, using revno/revid from the
2907
2972
# history-incomplete response as the known revno/revid.
2908
2973
client.add_expected_call(
2909
b'Repository.get_rev_id_for_revno', (b'fallback/', 1, (2, b'rev-two')),
2974
b'Repository.get_rev_id_for_revno', (
2975
b'fallback/', 1, (2, b'rev-two')),
2910
2976
b'success', (b'ok', b'rev-one'))
2911
2977
result = repo.get_rev_id_for_revno(1, (42, b'rev-foo'))
2912
2978
self.assertEqual((True, b'rev-one'), result)
2917
2983
# remote repo. The client translates that response to NoSuchRevision.
2918
2984
repo, client = self.setup_fake_client_and_repository('quack')
2919
2985
client.add_expected_call(
2920
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2986
b'Repository.get_rev_id_for_revno', (b'quack/',
2987
5, (42, b'rev-foo')),
2921
2988
b'error', (b'nosuchrevision', b'rev-foo'))
2922
2989
self.assertRaises(
2923
2990
errors.NoSuchRevision,
3124
3192
b'Repository.start_write_group', (b'quack/', b'a token'),
3125
3193
b'success', (b'ok', [b'token1']))
3126
3194
client.add_expected_call(
3127
b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
3195
b'Repository.commit_write_group', (b'quack/',
3196
b'a token', [b'token1']),
3128
3197
b'success', (b'ok',))
3129
3198
repo.lock_write()
3130
3199
repo.start_write_group()
3140
3209
b'Repository.start_write_group', (b'quack/', b'a token'),
3141
3210
b'success', (b'ok', [b'token1']))
3142
3211
client.add_expected_call(
3143
b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
3212
b'Repository.abort_write_group', (b'quack/',
3213
b'a token', [b'token1']),
3144
3214
b'success', (b'ok',))
3145
3215
repo.lock_write()
3146
3216
repo.start_write_group()
3158
3228
b'Repository.lock_write', (b'quack/', b''),
3159
3229
b'success', (b'ok', b'a token'))
3160
3230
client.add_expected_call(
3161
b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
3231
b'Repository.check_write_group', (b'quack/',
3232
b'a token', [b'token1']),
3162
3233
b'success', (b'ok',))
3163
3234
repo.lock_write()
3164
3235
repo.resume_write_group(['token1'])
3238
3309
b'Repository.iter_files_bytes', (b'quack/', ),
3239
3310
b'success', (b'ok',), iter([b"ok\x000", b"\n", zlib.compress(b"mydata" * 10)]))
3240
3311
for (identifier, byte_stream) in repo.iter_files_bytes([(b"somefile",
3241
b"somerev", b"myid")]):
3312
b"somerev", b"myid")]):
3242
3313
self.assertEqual(b"myid", identifier)
3243
3314
self.assertEqual(b"".join(byte_stream), b"mydata" * 10)
3247
3318
repo, client = self.setup_fake_client_and_repository(transport_path)
3248
3319
client.add_expected_call(
3249
3320
b'Repository.iter_files_bytes',
3251
3322
b'error', (b'RevisionNotPresent', b'somefile', b'somerev'),
3252
3323
iter([b"absent\0somefile\0somerev\n"]))
3253
3324
self.assertRaises(errors.RevisionNotPresent, list,
3254
repo.iter_files_bytes(
3255
[(b"somefile", b"somerev", b"myid")]))
3325
repo.iter_files_bytes(
3326
[(b"somefile", b"somerev", b"myid")]))
3258
3329
class TestRepositoryInsertStreamBase(TestRemoteRepository):
3259
3330
"""Base class for Repository.insert_stream and .insert_stream_1.19
3263
3334
def checkInsertEmptyStream(self, repo, client):
3264
3335
"""Insert an empty stream, checking the result.
3355
3426
# Create a fake real repository for insert_stream to fall back on, so
3356
3427
# that we can directly see the records the RemoteSink passes to the
3358
3430
class FakeRealSink:
3359
3431
def __init__(self):
3360
3432
self.records = []
3361
3434
def insert_stream(self, stream, src_format, resume_tokens):
3362
3435
for substream_kind, substream in stream:
3363
3436
self.records.append(
3364
3437
(substream_kind, [record.key for record in substream]))
3365
3438
return [b'fake tokens'], [b'fake missing keys']
3366
3439
fake_real_sink = FakeRealSink()
3367
3441
class FakeRealRepository:
3368
3442
def _get_sink(self):
3369
3443
return fake_real_sink
3370
3445
def is_in_write_group(self):
3372
3448
def refresh_data(self):
3374
3450
repo._real_repository = FakeRealRepository()
3401
3477
# Define a stream using generators so that it isn't rewindable.
3402
3478
inv = inventory.Inventory(revision_id=b'rev1')
3403
3479
inv.root.revision = b'rev1'
3404
3481
def stream_with_inv_delta():
3405
3482
yield ('inventories', inventories_substream())
3406
3483
yield ('inventory-deltas', inventory_delta_substream())
3407
3484
yield ('texts', [
3408
3485
versionedfile.FulltextContentFactory(
3409
3486
(b'some-rev', b'some-file'), (), None, b'content')])
3410
3488
def inventories_substream():
3411
3489
# An empty inventory fulltext. This will be streamed normally.
3412
3490
text = fmt._serializer.write_inventory_to_string(inv)
3413
3491
yield versionedfile.FulltextContentFactory(
3414
3492
(b'rev1',), (), None, text)
3415
3494
def inventory_delta_substream():
3416
3495
# An inventory delta. This can't be streamed via this verb, so it
3417
3496
# will trigger a fallback to VFS insert_stream.
3498
3577
transport_path = 'repo'
3499
3578
expected_calls = [('call_expecting_body', b'Repository.tarball',
3500
3579
(b'repo/', b'bz2',),),
3502
3581
repo, client = self.setup_fake_client_and_repository(transport_path)
3503
3582
client.add_success_response_with_body(self.tarball_content, b'ok')
3504
3583
# Now actually ask for the tarball
3693
3773
def test_norepository(self):
3694
3774
bzrdir = self.make_controldir('')
3695
3775
translated_error = self.translateTuple((b'norepository',),
3697
3777
expected_error = errors.NoRepositoryPresent(bzrdir)
3698
3778
self.assertEqual(expected_error, translated_error)
3712
3792
def test_LockFailed(self):
3713
3793
lock = 'str() of a server lock'
3714
3794
why = 'str() of why'
3715
translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
3795
translated_error = self.translateTuple(
3796
(b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
3716
3797
expected_error = errors.LockFailed(lock, why)
3717
3798
self.assertEqual(expected_error, translated_error)
3719
3800
def test_TokenMismatch(self):
3720
3801
token = 'a lock token'
3721
translated_error = self.translateTuple((b'TokenMismatch',), token=token)
3802
translated_error = self.translateTuple(
3803
(b'TokenMismatch',), token=token)
3722
3804
expected_error = errors.TokenMismatch(token, '(remote token)')
3723
3805
self.assertEqual(expected_error, translated_error)
3745
3827
def test_ReadError(self):
3746
3828
path = 'a path'
3747
translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
3829
translated_error = self.translateTuple(
3830
(b'ReadError', path.encode('utf-8')))
3748
3831
expected_error = errors.ReadError(path)
3749
3832
self.assertEqual(expected_error, translated_error)
3751
3834
def test_IncompatibleRepositories(self):
3752
3835
translated_error = self.translateTuple((b'IncompatibleRepositories',
3753
b"repo1", b"repo2", b"details here"))
3836
b"repo1", b"repo2", b"details here"))
3754
3837
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
3756
3839
self.assertEqual(expected_error, translated_error)
3758
3841
def test_GhostRevisionsHaveNoRevno(self):
3759
3842
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3760
b"revid1", b"revid2"))
3843
b"revid1", b"revid2"))
3761
3844
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
3762
3845
self.assertEqual(expected_error, translated_error)
3764
3847
def test_PermissionDenied_no_args(self):
3765
3848
path = 'a path'
3766
3849
translated_error = self.translateTuple((b'PermissionDenied',),
3768
3851
expected_error = errors.PermissionDenied(path)
3769
3852
self.assertEqual(expected_error, translated_error)
3771
3854
def test_PermissionDenied_one_arg(self):
3772
3855
path = 'a path'
3773
translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
3856
translated_error = self.translateTuple(
3857
(b'PermissionDenied', path.encode('utf-8')))
3774
3858
expected_error = errors.PermissionDenied(path)
3775
3859
self.assertEqual(expected_error, translated_error)
3798
3882
def test_NoSuchFile_context_path(self):
3799
3883
local_path = "local path"
3800
3884
translated_error = self.translateTuple((b'ReadError', b"remote path"),
3802
3886
expected_error = errors.ReadError(local_path)
3803
3887
self.assertEqual(expected_error, translated_error)
3805
3889
def test_NoSuchFile_without_context(self):
3806
3890
remote_path = "remote path"
3807
translated_error = self.translateTuple((b'ReadError', remote_path.encode('utf-8')))
3891
translated_error = self.translateTuple(
3892
(b'ReadError', remote_path.encode('utf-8')))
3808
3893
expected_error = errors.ReadError(remote_path)
3809
3894
self.assertEqual(expected_error, translated_error)
3816
3901
def test_MemoryError(self):
3817
3902
translated_error = self.translateTuple((b'MemoryError',))
3818
3903
self.assertStartsWith(str(translated_error),
3819
"remote server out of memory")
3904
"remote server out of memory")
3821
3906
def test_generic_IndexError_no_classname(self):
3822
err = errors.ErrorFromSmartServer((b'error', b"list index out of range"))
3907
err = errors.ErrorFromSmartServer(
3908
(b'error', b"list index out of range"))
3823
3909
translated_error = self.translateErrorFromSmartServer(err)
3824
3910
expected_error = errors.UnknownErrorFromSmartServer(err)
3825
3911
self.assertEqual(expected_error, translated_error)
3859
3945
# To translate a NoSuchRevision error _translate_error needs a 'branch'
3860
3946
# in the context dict. So let's give it an empty context dict instead
3861
3947
# to exercise its error recovery.
3863
3948
error_tuple = (b'NoSuchRevision', b'revid')
3864
3949
server_error = errors.ErrorFromSmartServer(error_tuple)
3865
3950
translated_error = self.translateErrorFromSmartServer(server_error)
3895
3980
# make a branch stacked on another repository containing an empty
3896
3981
# revision, then open it over hpss - we should be able to see that
3898
base_transport = self.get_transport()
3899
3983
base_builder = self.make_branch_builder('base', format='1.9')
3900
3984
base_builder.start_series()
3901
3985
base_revid = base_builder.build_snapshot(None,
3902
[('add', ('', None, 'directory', None))],
3903
'message', revision_id=b'rev-id')
3986
[('add', ('', None, 'directory', None))],
3987
'message', revision_id=b'rev-id')
3904
3988
base_builder.finish_series()
3905
3989
stacked_branch = self.make_branch('stacked', format='1.9')
3906
3990
stacked_branch.set_stacked_on_url('../base')
3917
4001
# be a RemoteRepository
3918
4002
self.assertLength(1, remote_repo._fallback_repositories)
3919
4003
self.assertIsInstance(remote_repo._fallback_repositories[0],
3921
4005
# and it has the revision committed to the underlying repository;
3922
4006
# these have varying implementations so we try several of them
3923
4007
self.assertTrue(remote_repo.has_revisions([base_revid]))
3924
4008
self.assertTrue(remote_repo.has_revision(base_revid))
3925
4009
self.assertEqual(remote_repo.get_revision(base_revid).message,
3928
4012
remote_repo.unlock()
3933
4017
tree1 = self.make_branch_and_tree('tree1', format='1.9')
3934
4018
tree1.commit('rev1', rev_id=b'rev1')
3935
4019
tree2 = tree1.branch.controldir.sprout('tree2', stacked=True
3936
).open_workingtree()
4020
).open_workingtree()
3937
4021
local_tree = tree2.branch.create_checkout('local')
3938
4022
local_tree.commit('local changes make me feel good.')
3939
4023
branch2 = Branch.open(self.get_url('tree2'))
4012
4096
def make_stacked_stacked():
4013
4097
_, stacked = self.prepare_stacked_remote_branch()
4014
4098
tree = stacked.controldir.sprout('tree3', stacked=True
4015
).open_workingtree()
4099
).open_workingtree()
4016
4100
local_tree = tree.branch.create_checkout('local-tree3')
4017
4101
local_tree.commit('more local changes are better')
4018
4102
branch = Branch.open(self.get_url('tree3'))
4019
4103
branch.lock_read()
4020
4104
self.addCleanup(branch.unlock)
4021
4105
return None, branch
4022
rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
4023
branch_factory=make_stacked_stacked)
4106
rev_ord, expected_revs = self.get_ordered_revs(
4107
'1.9', 'unordered', branch_factory=make_stacked_stacked)
4024
4108
self.assertEqual(set(expected_revs), set(rev_ord))
4025
4109
# Getting unordered results should have made a streaming data request
4026
4110
# from the server, and one from each backing repo
4055
4139
# branch pulling content from stacked and trunk.
4056
4140
self.setup_smart_server_with_call_log()
4057
4141
trunk = self.make_branch_and_tree('trunk', format="1.9-rich-root")
4058
r1 = trunk.commit('start')
4142
trunk.commit('start')
4059
4143
stacked_branch = trunk.branch.create_clone_on_transport(
4060
4144
self.get_transport('stacked'), stacked_on=trunk.branch.base)
4061
4145
local = self.make_branch('local', format='1.9-rich-root')
4062
4146
local.repository.fetch(stacked_branch.repository,
4063
stacked_branch.last_revision())
4147
stacked_branch.last_revision())
4066
4150
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
4108
4192
orig_info = request_handlers.get_info(verb_name)
4109
4193
request_handlers.register(verb_name, verb, override_existing=True)
4110
4194
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4111
override_existing=True, info=orig_info)
4195
override_existing=True, info=orig_info)
4113
4197
def test_fetch_everything_backwards_compat(self):
4114
4198
"""Can fetch with EverythingResult even with pre 2.4 servers.
4116
4200
Pre-2.4 do not support 'everything' searches with the
4117
4201
Repository.get_stream_1.19 verb.
4120
4205
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4121
4206
"""A version of the Repository.get_stream_1.19 verb patched to
4122
4207
reject 'everything' searches the way 2.3 and earlier do.
4124
4210
def recreate_search(self, repository, search_bytes,
4125
4211
discard_excess=False):
4126
4212
verb_log.append(search_bytes.split(b'\n', 1)[0])
4129
4215
request.FailedSmartServerResponse((b'BadSearch',)))
4130
4216
return super(OldGetStreamVerb,
4131
self).recreate_search(repository, search_bytes,
4132
discard_excess=discard_excess)
4217
self).recreate_search(repository, search_bytes,
4218
discard_excess=discard_excess)
4133
4219
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4134
4220
local = self.make_branch('local')
4135
4221
builder = self.make_branch_builder('remote')
4201
4287
def __init__(self, urgency):
4202
4288
self.urgency = urgency
4203
4289
remote.no_context_error_translators.register(b"OutOfCoffee",
4204
lambda err: OutOfCoffee(err.error_args[0]))
4290
lambda err: OutOfCoffee(err.error_args[0]))
4205
4291
transport = MemoryTransport()
4206
4292
client = FakeClient(transport.base)
4207
4293
client.add_expected_call(
4223
4309
self.branch = branch
4224
4310
self.urgency = urgency
4225
4311
remote.error_translators.register(b"OutOfTea",
4226
lambda err, find, path: OutOfTea(
4227
err.error_args[0].decode('utf-8'),
4312
lambda err, find, path: OutOfTea(
4313
err.error_args[0].decode(
4229
4316
transport = MemoryTransport()
4230
4317
client = FakeClient(transport.base)
4231
4318
client.add_expected_call(
4287
4374
repo._format = fmt
4288
4375
stream = [('inventory-deltas', [
4289
4376
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4290
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4377
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4291
4378
client.add_expected_call(
4292
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4379
b'VersionedFileRepository.get_inventories', (
4380
b'quack/', b'unordered'),
4293
4381
b'success', (b'ok', ),
4294
4382
_stream_to_byte_stream(stream, fmt))
4295
4383
ret = list(repo.iter_inventories([b"somerevid"]))
4307
4395
transport_path = 'quack'
4308
4396
repo, client = self.setup_fake_client_and_repository(transport_path)
4309
4397
client.add_expected_call(
4310
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4398
b'VersionedFileRepository.get_inventories', (
4399
b'quack/', b'unordered'),
4311
4400
b'success', (b'ok', ), iter([]))
4312
4401
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4313
4402
[b"somerevid"]))
4327
4416
repo._format = fmt
4328
4417
stream = [('inventory-deltas', [
4329
4418
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4330
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4419
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4331
4420
client.add_expected_call(
4332
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4421
b'VersionedFileRepository.get_inventories', (
4422
b'quack/', b'unordered'),
4333
4423
b'success', (b'ok', ),
4334
4424
_stream_to_byte_stream(stream, fmt))
4342
4432
info.size = len(contents)
4343
4433
tf.addfile(info, BytesIO(contents))
4344
4434
client.add_expected_call(
4345
b'Repository.revision_archive', (b'quack/', b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4435
b'Repository.revision_archive', (b'quack/',
4436
b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4346
4437
b'success', (b'ok', ),
4348
4439
tree = repo.revision_tree(b'somerevid')
4349
self.assertEqual(f.getvalue(), b''.join(tree.archive('tar', 'foo.tar')))
4440
self.assertEqual(f.getvalue(), b''.join(
4441
tree.archive('tar', 'foo.tar')))
4352
4444
class TestRepositoryAnnotate(TestRemoteRepository):
4361
4453
repo, client = self.setup_fake_client_and_repository(transport_path)
4362
4454
fmt = controldir.format_registry.get('2a')().repository_format
4363
4455
repo._format = fmt
4364
stream = [('inventory-deltas', [
4365
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4366
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4457
('inventory-deltas', [
4458
versionedfile.FulltextContentFactory(
4459
b'somerevid', None, None,
4460
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4367
4461
client.add_expected_call(
4368
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4462
b'VersionedFileRepository.get_inventories', (
4463
b'quack/', b'unordered'),
4369
4464
b'success', (b'ok', ),
4370
4465
_stream_to_byte_stream(stream, fmt))
4371
4466
client.add_expected_call(