164
163
bd = self.make_controldir('unstackable', format='pack-0.92')
165
164
r = bd.create_repository()
166
165
self.assertFalse(r._format.supports_external_lookups)
167
r = BzrDir.open_from_transport(t.clone('unstackable')).open_repository()
166
r = BzrDir.open_from_transport(
167
t.clone('unstackable')).open_repository()
168
168
self.assertFalse(r._format.supports_external_lookups)
169
169
bd = self.make_controldir('stackable', format='1.9')
170
170
r = bd.create_repository()
229
229
_SmartClient.__init__(self, FakeMedium(self._calls, fake_medium_base))
231
231
def add_expected_call(self, call_name, call_args, response_type,
232
response_args, response_body=None):
232
response_args, response_body=None):
233
233
if self._expected_calls is None:
234
234
self._expected_calls = []
235
235
self._expected_calls.append((call_name, call_args))
252
252
def finished_test(self):
253
253
if self._expected_calls:
254
254
raise AssertionError("%r finished but was still expecting %r"
255
% (self, self._expected_calls[0]))
255
% (self, self._expected_calls[0]))
257
257
def _get_next_response(self):
259
259
response_tuple = self.responses.pop(0)
260
260
except IndexError as e:
261
261
raise AssertionError("%r didn't expect any more calls"
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
282
raise AssertionError("%r expected %r%r "
284
% (self, next_call[0], next_call[1], method, args,))
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
450
451
self.disable_verb(verb)
451
452
format = 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.
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(
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, _force_probe=True)
650
653
self.assertFinished(client)
652
655
def test_present_without_workingtree(self):
654
657
client.add_expected_call(
655
658
b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'no'))
656
659
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
657
_client=client, _force_probe=True)
660
_client=client, _force_probe=True)
658
661
self.assertIsInstance(bd, RemoteBzrDir)
659
662
self.assertFalse(bd.has_workingtree())
660
663
self.assertRaises(errors.NoWorkingTree, bd.open_workingtree)
665
668
client.add_expected_call(
666
669
b'BzrDir.open_2.1', (b'quack/',), b'success', (b'yes', b'yes'))
667
670
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
_client=client, _force_probe=True)
671
_client=client, _force_probe=True)
669
672
self.assertIsInstance(bd, RemoteBzrDir)
670
673
self.assertTrue(bd.has_workingtree())
671
674
self.assertRaises(errors.NotLocalUrl, bd.open_workingtree)
678
681
client.add_expected_call(
679
682
b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
680
683
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
681
_client=client, _force_probe=True)
684
_client=client, _force_probe=True)
682
685
self.assertIsInstance(bd, RemoteBzrDir)
683
686
self.assertFinished(client)
689
692
# the version is 2 also do _remember_remote_is_before((1, 6)) before
690
693
# continuing with the RPC.
691
694
orig_check_call = client._check_call
692
696
def check_call(method, args):
693
697
client._medium._protocol_version = 2
694
698
client._medium._remember_remote_is_before((1, 6))
700
704
client.add_expected_call(
701
705
b'BzrDir.open', (b'quack/',), b'success', (b'yes',))
702
706
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
703
_client=client, _force_probe=True)
707
_client=client, _force_probe=True)
704
708
self.assertIsInstance(bd, RemoteBzrDir)
705
709
self.assertFinished(client)
716
720
self.disable_verb(verb)
717
721
format = a_dir.open_branch()
718
722
call_count = len([call for call in self.hpss_calls if
719
call.call.method == verb])
723
call.call.method == verb])
720
724
self.assertEqual(1, call_count)
722
726
def test_branch_present(self):
737
741
b'Branch.get_stacked_on_url', (b'quack/',),
738
742
b'error', (b'NotStacked',))
739
743
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
741
745
result = bzrdir.open_branch()
742
746
self.assertIsInstance(result, RemoteBranch)
743
747
self.assertEqual(bzrdir, result.controldir)
750
754
client = FakeClient(transport.base)
751
755
client.add_error_response(b'nobranch')
752
756
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
754
758
self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
755
759
self.assertEqual(
756
760
[('call', b'BzrDir.open_branchV3', (b'quack/',))],
767
772
# no requests on the network - catches other api calls being made.
768
773
client = FakeClient(transport.base)
769
774
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
771
776
# patch the open_branch call to record that it was called.
772
777
bzrdir.open_branch = open_branch
773
778
self.assertEqual((None, "a-branch"), bzrdir._get_tree_branch())
792
797
b'Branch.get_stacked_on_url', (b'~hello/',),
793
798
b'error', (b'NotStacked',))
794
799
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
796
801
result = bzrdir.open_branch()
797
802
self.assertFinished(client)
815
820
b'ok', b'', rich_response, subtree_response, external_lookup,
817
822
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
819
824
result = bzrdir.open_repository()
820
825
self.assertEqual(
821
826
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
849
854
self.disable_verb(b'BzrDir.create_branch')
850
855
branch = repo.controldir.create_branch()
851
856
create_branch_call_count = len([call for call in self.hpss_calls if
852
call.call.method == b'BzrDir.create_branch'])
857
call.call.method == b'BzrDir.create_branch'])
853
858
self.assertEqual(1, create_branch_call_count)
855
860
def test_current_server(self):
865
870
client.add_expected_call(
866
871
b'BzrDir.create_branch', (b'quack/', network_name),
867
872
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
868
reference_repo_name))
873
reference_repo_name))
869
874
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
871
876
branch = a_controldir.create_branch()
872
877
# We should have got a remote branch
873
878
self.assertIsInstance(branch, remote.RemoteBranch)
893
898
client.add_expected_call(
894
899
b'BzrDir.create_branch', (b'extra/quack/', network_name),
895
900
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
896
reference_repo_name))
901
reference_repo_name))
897
902
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
899
904
branch = a_controldir.create_branch(repository=repo)
900
905
# We should have got a remote branch
901
906
self.assertIsInstance(branch, remote.RemoteBranch)
913
918
self.disable_verb(b'BzrDir.create_repository')
914
919
repo = bzrdir.create_repository()
915
920
create_repo_call_count = len([call for call in self.hpss_calls if
916
call.call.method == b'BzrDir.create_repository'])
921
call.call.method == b'BzrDir.create_repository'])
917
922
self.assertEqual(1, create_repo_call_count)
919
924
def test_current_server(self):
926
931
network_name = reference_format.network_name()
927
932
client.add_expected_call(
928
933
b'BzrDir.create_repository', (b'quack/',
929
b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
934
b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
931
936
b'success', (b'ok', b'yes', b'yes', b'yes', network_name))
932
937
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
934
939
repo = a_controldir.create_repository()
935
940
# We should have got a remote repository
936
941
self.assertIsInstance(repo, remote.RemoteRepository)
964
969
# PackRepository wants to do a stat
965
970
client.add_success_response(b'stat', b'0', b'65535')
966
971
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
968
973
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
970
975
repo = bzrdir.open_repository()
971
976
self.assertEqual(
972
977
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
999
1004
# PackRepository wants to do a stat
1000
1005
client.add_success_response(b'stat', b'0', b'65535')
1001
1006
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
1003
1008
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
1005
1010
repo = bzrdir.open_repository()
1006
1011
self.assertEqual(
1007
1012
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1021
1026
transport.mkdir('quack')
1022
1027
transport = transport.clone('quack')
1023
1028
client = FakeClient(transport.base)
1024
client.add_success_response(b'ok', b'', b'no', b'no', b'no', network_name)
1029
client.add_success_response(
1030
b'ok', b'', b'no', b'no', b'no', network_name)
1025
1031
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1027
1033
repo = bzrdir.open_repository()
1028
1034
self.assertEqual(
1029
1035
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
1041
1047
client = FakeClient(transport.base)
1042
1048
client.add_expected_call(
1043
1049
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'),
1050
(default_format_name, b'path', b'False', b'False', b'False', b'',
1051
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'))
1053
(b'.', b'no', b'no', b'yes', b'repo fmt', b'repo bzrdir fmt',
1054
b'bzrdir fmt', b'False', b'', b'', b'repo lock token'))
1049
1055
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
1050
1056
# it's currently hard to test that without supplying a real remote
1051
1057
# transport connected to a real server.
1052
1058
result = fmt._initialize_on_transport_ex_rpc(client, b'path',
1053
transport, False, False, False, None, None, None, None, False)
1059
transport, False, False, False, None, None, None, None, False)
1054
1060
self.assertFinished(client)
1056
1062
def test_error(self):
1063
1069
client = FakeClient(transport.base)
1064
1070
client.add_expected_call(
1065
1071
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'),
1072
(default_format_name, b'path', b'False', b'False', b'False', b'',
1073
b'', b'', b'', b'False'),
1069
(b'PermissionDenied', b'path', b'extra info'))
1075
(b'PermissionDenied', b'path', b'extra info'))
1070
1076
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
1071
1077
# it's currently hard to test that without supplying a real remote
1072
1078
# transport connected to a real server.
1073
1079
err = self.assertRaises(errors.PermissionDenied,
1074
fmt._initialize_on_transport_ex_rpc, client, b'path', transport,
1075
False, False, False, None, None, None, None, False)
1080
fmt._initialize_on_transport_ex_rpc, client, b'path', transport,
1081
False, False, False, None, None, None, None, False)
1076
1082
self.assertEqual('path', err.path)
1077
1083
self.assertEqual(': extra info', err.extra)
1078
1084
self.assertFinished(client)
1083
1089
transport = transport.clone('no-such-path')
1084
1090
fmt = RemoteBzrDirFormat()
1085
1091
err = self.assertRaises(errors.NoSuchFile,
1086
fmt.initialize_on_transport_ex, transport, create_prefix=False)
1092
fmt.initialize_on_transport_ex, transport, create_prefix=False)
1089
1095
class OldSmartClient(object):
1119
1125
def make_remote_bzrdir(self, transport, client):
1120
1126
"""Make a RemotebzrDir using 'client' as the _client."""
1121
1127
return RemoteBzrDir(transport, RemoteBzrDirFormat(),
1125
1131
class RemoteBranchTestCase(RemoteBzrDirTestCase):
1341
1347
b'Branch.get_stacked_on_url', (b'quack/',),
1342
1348
b'error', (b'NotStacked',))
1343
1349
client.add_expected_call(
1344
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1350
b'Branch.set_tags_bytes', (b'quack/',
1351
b'branch token', b'repo token'),
1345
1352
b'success', ('',))
1346
1353
transport.mkdir('quack')
1347
1354
transport = transport.clone('quack')
1358
1365
b'Branch.get_stacked_on_url', (b'quack/',),
1359
1366
b'error', (b'NotStacked',))
1360
1367
client.add_expected_call(
1361
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1368
b'Branch.set_tags_bytes', (b'quack/',
1369
b'branch token', b'repo token'),
1362
1370
b'unknown', (b'Branch.set_tags_bytes',))
1363
1371
transport.mkdir('quack')
1364
1372
transport = transport.clone('quack')
1365
1373
branch = self.make_remote_branch(transport, client)
1366
1374
self.lock_remote_branch(branch)
1367
1376
class StubRealBranch(object):
1368
1377
def __init__(self):
1369
1378
self.calls = []
1370
1380
def _set_tags_bytes(self, bytes):
1371
1381
self.calls.append(('set_tags_bytes', bytes))
1372
1382
real_branch = StubRealBranch()
1548
1558
b'Branch.get_stacked_on_url', (b'stacked/',),
1549
1559
b'success', (b'ok', vfs_url.encode('utf-8')))
1550
1560
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1552
1562
repo_fmt = remote.RemoteRepositoryFormat()
1553
1563
repo_fmt._custom_format = stacked_branch.repository._format
1554
1564
branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
1556
1566
result = branch.get_stacked_on_url()
1557
1567
self.assertEqual(vfs_url, result)
1569
1579
client.add_expected_call(
1570
1580
b'BzrDir.find_repositoryV3', (b'stacked/',),
1571
1581
b'success', (b'ok', b'', b'no', b'no', b'yes',
1572
stacked_branch.repository._format.network_name()))
1582
stacked_branch.repository._format.network_name()))
1573
1583
# called twice, once from constructor and then again by us
1574
1584
client.add_expected_call(
1575
1585
b'Branch.get_stacked_on_url', (b'stacked/',),
1580
1590
# this will also do vfs access, but that goes direct to the transport
1581
1591
# and isn't seen by the FakeClient.
1582
1592
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1583
RemoteBzrDirFormat(), _client=client)
1593
RemoteBzrDirFormat(), _client=client)
1584
1594
branch = bzrdir.open_branch()
1585
1595
result = branch.get_stacked_on_url()
1586
1596
self.assertEqual('../base', result)
1590
1600
self.assertEqual(1, len(branch.repository._fallback_repositories))
1591
1601
self.assertEqual(1,
1592
len(branch.repository._real_repository._fallback_repositories))
1602
len(branch.repository._real_repository._fallback_repositories))
1594
1604
def test_get_stacked_on_real_branch(self):
1595
1605
base_branch = self.make_branch('base')
1613
1623
b'Branch.get_stacked_on_url', (b'stacked/',),
1614
1624
b'success', (b'ok', b'../base'))
1615
1625
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1616
RemoteBzrDirFormat(), _client=client)
1626
RemoteBzrDirFormat(), _client=client)
1617
1627
branch = bzrdir.open_branch()
1618
1628
result = branch.get_stacked_on_url()
1619
1629
self.assertEqual('../base', result)
1646
1656
b'success', (b'ok', b'0', b'null:'))
1647
1657
client.add_expected_call(
1648
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
1658
b'Branch.set_last_revision', (b'branch/',
1659
b'branch token', b'repo token', b'null:',),
1649
1660
b'success', (b'ok',))
1650
1661
client.add_expected_call(
1651
1662
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1679
1690
encoded_body = bz2.compress(b'\n'.join(lines))
1680
1691
client.add_success_response_with_body(encoded_body, b'ok')
1681
1692
client.add_expected_call(
1682
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
1693
b'Branch.set_last_revision', (b'branch/',
1694
b'branch token', b'repo token', b'rev-id2',),
1683
1695
b'success', (b'ok',))
1684
1696
client.add_expected_call(
1685
1697
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1714
1726
encoded_body = bz2.compress(b'\n'.join(lines))
1715
1727
client.add_success_response_with_body(encoded_body, b'ok')
1716
1728
client.add_expected_call(
1717
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1729
b'Branch.set_last_revision', (b'branch/',
1730
b'branch token', b'repo token', b'rev-id',),
1718
1731
b'error', (b'NoSuchRevision', b'rev-id'))
1719
1732
client.add_expected_call(
1720
1733
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1751
1764
encoded_body = bz2.compress(b'\n'.join(lines))
1752
1765
client.add_success_response_with_body(encoded_body, b'ok')
1753
1766
client.add_expected_call(
1754
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1767
b'Branch.set_last_revision', (b'branch/',
1768
b'branch token', b'repo token', b'rev-id',),
1755
1769
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1756
1770
client.add_expected_call(
1757
1771
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1857
1871
b'unknown', b'Branch.set_last_revision_info')
1859
1873
branch = self.make_remote_branch(transport, client)
1860
1875
class StubRealBranch(object):
1861
1876
def __init__(self):
1862
1877
self.calls = []
1863
1879
def set_last_revision_info(self, revno, revision_id):
1864
1880
self.calls.append(
1865
1881
('set_last_revision_info', revno, revision_id))
1866
1883
def _clear_cached_state(self):
1868
1885
real_branch = StubRealBranch()
1977
1994
b'success', (b'ok', b'branch token', b'repo token'))
1978
1995
client.add_expected_call(
1979
1996
b'Branch.set_config_option', (b'memory:///', b'branch token',
1980
b'repo token', b'foo', b'bar', b''),
1997
b'repo token', b'foo', b'bar', b''),
1981
1998
b'success', ())
1982
1999
client.add_expected_call(
1983
2000
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2001
2018
encoded_dict_value = b'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
2002
2019
client.add_expected_call(
2003
2020
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2004
b'repo token', encoded_dict_value, b'foo', b''),
2021
b'repo token', encoded_dict_value, b'foo', b''),
2005
2022
b'success', ())
2006
2023
client.add_expected_call(
2007
2024
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2078
2095
b'success', (b'ok', ), b"# line 1\n")
2079
2096
client.add_expected_call(
2080
2097
b'Branch.put_config_file', (b'memory:///', b'branch token',
2082
2099
b'success', (b'ok',))
2083
2100
client.add_expected_call(
2084
2101
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2139
2156
branch = self.make_remote_branch(transport, client)
2140
2157
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2141
2158
self.assertRaises(errors.NoSuchRevision,
2142
branch.revision_id_to_revno, b'unknown')
2159
branch.revision_id_to_revno, b'unknown')
2143
2160
self.assertFinished(client)
2145
2162
def test_dotted(self):
2159
2176
branch = self.make_remote_branch(transport, client)
2160
2177
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2161
2178
self.assertRaises(errors.NoSuchRevision,
2162
branch.revision_id_to_dotted_revno, b'unknown')
2179
branch.revision_id_to_dotted_revno, b'unknown')
2163
2180
self.assertFinished(client)
2165
2182
def test_dotted_no_smart_verb(self):
2168
2185
self.disable_verb(b'Branch.revision_id_to_revno')
2169
2186
self.reset_smart_call_log()
2170
2187
self.assertEqual((0, ),
2171
branch.revision_id_to_dotted_revno(b'null:'))
2188
branch.revision_id_to_dotted_revno(b'null:'))
2172
2189
self.assertLength(8, self.hpss_calls)
2248
2265
def test_permissiondenied(self):
2249
2266
client = FakeClient()
2250
client.add_error_response(b'PermissionDenied', b'remote path', b'extra')
2267
client.add_error_response(
2268
b'PermissionDenied', b'remote path', b'extra')
2251
2269
transport = RemoteTransport('bzr://example.com/', medium=False,
2252
2270
_client=client)
2253
2271
exc = self.assertRaises(
2266
2284
conf = config.AuthenticationConfig()
2267
2285
conf._get_config().update(
2268
2286
{'bzr+sshtest': {'scheme': 'ssh', 'user': 'bar', 'host':
2271
2289
t = RemoteSSHTransport('bzr+ssh://example.com')
2272
2290
self.assertEqual('bar', t._get_credentials()[0])
2295
2313
transport = transport.clone(transport_path)
2296
2314
# we do not want bzrdir to make any remote calls
2297
2315
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
2299
2317
repo = RemoteRepository(bzrdir, None, _client=client)
2300
2318
return repo, client
2311
2329
real_format = branch.format_registry.get_default()
2312
2330
remote_format._network_name = real_format.network_name()
2313
2331
self.assertEqual(remoted_description(real_format),
2314
remote_format.get_format_description())
2332
remote_format.get_format_description())
2317
2335
class TestRepositoryFormat(TestRemoteRepository):
2331
2349
real_format = repository.format_registry.get_default()
2332
2350
remote_repo_format._network_name = real_format.network_name()
2333
2351
self.assertEqual(remoted_description(real_format),
2334
remote_repo_format.get_format_description())
2352
remote_repo_format.get_format_description())
2337
2355
class TestRepositoryAllRevisionIds(TestRemoteRepository):
2371
2389
result = repo.gather_stats(None)
2372
2390
self.assertEqual(
2373
2391
[('call_expecting_body', b'Repository.gather_stats',
2374
(b'quack/', b'', b'no'))],
2392
(b'quack/', b'', b'no'))],
2376
2394
self.assertEqual({'revisions': 2, 'size': 18}, result)
2393
2411
self.assertEqual({'revisions': 2, 'size': 18,
2394
2412
'firstrev': (123456.300, 3600),
2395
'latestrev': (654231.400, 0),},
2413
'latestrev': (654231.400, 0), },
2398
2416
def test_revid_with_committers(self):
2414
2432
self.assertEqual({'revisions': 2, 'size': 18,
2415
2433
'committers': 128,
2416
2434
'firstrev': (123456.300, 3600),
2417
'latestrev': (654231.400, 0),},
2435
'latestrev': (654231.400, 0), },
2483
2501
repo, client = self.setup_fake_client_and_repository(transport_path)
2484
2502
client.add_error_response(b'nosuchrevision', b'unknown')
2485
2503
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2487
2505
self.assertEqual(
2488
2506
[('call_expecting_body', b'Repository.get_revision_signature_text',
2489
2507
(b'quick/', b'unknown'))],
2513
2531
b'success', (b'ok', (b'token1', )))
2514
2532
client.add_expected_call(
2515
2533
b'Repository.add_signature_text', (b'quack/', b'a token', b'rev1',
2517
2535
b'success', (b'ok', ), None)
2518
2536
repo.lock_write()
2519
2537
repo.start_write_group()
2520
2538
self.assertIs(None,
2521
repo.add_signature_text(b"rev1", b"every bloody emperor"))
2539
repo.add_signature_text(b"rev1", b"every bloody emperor"))
2522
2540
self.assertEqual(
2523
2541
('call_with_body_bytes_expecting_body',
2524
b'Repository.add_signature_text',
2542
b'Repository.add_signature_text',
2525
2543
(b'quack/', b'a token', b'rev1', b'token1'),
2526
b'every bloody emperor'),
2544
b'every bloody emperor'),
2527
2545
client._calls[-1])
2552
2570
self.assertEqual({r1: (NULL_REVISION,)}, parents)
2553
2571
self.assertEqual(
2554
2572
[('call_with_body_bytes_expecting_body',
2555
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2573
b'Repository.get_parent_map', (b'quack/',
2574
b'include-missing:', r2),
2563
2582
self.assertEqual({r1: (NULL_REVISION,)}, parents)
2564
2583
self.assertEqual(
2565
2584
[('call_with_body_bytes_expecting_body',
2566
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2585
b'Repository.get_parent_map', (b'quack/',
2586
b'include-missing:', r2),
2568
2588
('call_with_body_bytes_expecting_body',
2569
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r1),
2589
b'Repository.get_parent_map', (b'quack/',
2590
b'include-missing:', r1),
2631
2652
self.reset_smart_call_log()
2632
2653
graph = repo.get_graph()
2633
2654
self.assertEqual({},
2634
graph.get_parent_map([b'some-missing', b'other-missing']))
2655
graph.get_parent_map([b'some-missing', b'other-missing']))
2635
2656
self.assertLength(1, self.hpss_calls)
2636
2657
# No call if we repeat this
2637
2658
self.reset_smart_call_log()
2638
2659
graph = repo.get_graph()
2639
2660
self.assertEqual({},
2640
graph.get_parent_map([b'some-missing', b'other-missing']))
2661
graph.get_parent_map([b'some-missing', b'other-missing']))
2641
2662
self.assertLength(0, self.hpss_calls)
2642
2663
# Asking for more unknown keys makes a request.
2643
2664
self.reset_smart_call_log()
2644
2665
graph = repo.get_graph()
2645
2666
self.assertEqual({},
2646
graph.get_parent_map([b'some-missing', b'other-missing',
2667
graph.get_parent_map([b'some-missing', b'other-missing',
2648
2669
self.assertLength(1, self.hpss_calls)
2650
2671
def disableExtraResults(self):
2674
2695
# requests, and because b'null:' was queried but not returned it will be
2675
2696
# cached as missing.
2676
2697
self.assertEqual({b'first': (b'null:',)},
2677
graph.get_parent_map([b'first', b'null:']))
2698
graph.get_parent_map([b'first', b'null:']))
2678
2699
# Now query for another key. This request will pass along a recipe of
2679
2700
# start and stop keys describing the already cached results, and this
2680
2701
# recipe's revision count must be correct (or else it will trigger an
2725
2747
self.assertEqual([], client._calls)
2726
2748
self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
2727
2749
self.assertEqual({r1: (NULL_REVISION,)},
2728
repo.get_cached_parent_map([r1]))
2750
repo.get_cached_parent_map([r1]))
2729
2751
self.assertEqual(
2730
2752
[('call_with_body_bytes_expecting_body',
2731
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
2753
b'Repository.get_parent_map', (b'quack/',
2754
b'include-missing:', r2),
2750
2773
self.assertEqual({}, graph.get_parent_map([b'rev1']))
2751
2774
tree.commit('message', rev_id=b'rev1')
2752
2775
graph = tree.branch.repository.get_graph()
2753
self.assertEqual({b'rev1': (b'null:',)}, graph.get_parent_map([b'rev1']))
2776
self.assertEqual({b'rev1': (b'null:',)},
2777
graph.get_parent_map([b'rev1']))
2756
2780
class TestRepositoryGetRevisions(TestRemoteRepository):
2761
2785
client.add_success_response_with_body(
2762
2786
b'', b'ok', b'10')
2763
2787
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2764
[b'somerev1', b'anotherrev2'])
2788
[b'somerev1', b'anotherrev2'])
2765
2789
self.assertEqual(
2766
2790
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2767
(b'quack/', ), b"somerev1\nanotherrev2")],
2791
(b'quack/', ), b"somerev1\nanotherrev2")],
2770
2794
def test_hpss_get_single_revision(self):
2781
2805
# Split up body into two bits to make sure the zlib compression object
2782
2806
# gets data fed twice.
2783
2807
client.add_success_response_with_body(
2784
[body[:10], body[10:]], b'ok', b'10')
2808
[body[:10], body[10:]], b'ok', b'10')
2785
2809
revs = repo.get_revisions([b'somerev1'])
2786
2810
self.assertEqual(revs, [somerev1])
2787
2811
self.assertEqual(
2788
2812
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2789
(b'quack/', ), b"somerev1")],
2813
(b'quack/', ), b"somerev1")],
2838
2862
result = repo._get_revision_graph(r2)
2839
2863
self.assertEqual(
2840
2864
[('call_expecting_body', b'Repository.get_revision_graph',
2841
(b'sinhala/', r2))],
2865
(b'sinhala/', r2))],
2843
2867
self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2849
2873
client.add_error_response(b'nosuchrevision', revid)
2850
2874
# also check that the right revision is reported in the error
2851
2875
self.assertRaises(errors.NoSuchRevision,
2852
repo._get_revision_graph, revid)
2876
repo._get_revision_graph, revid)
2853
2877
self.assertEqual(
2854
2878
[('call_expecting_body', b'Repository.get_revision_graph',
2855
(b'sinhala/', revid))],
2879
(b'sinhala/', revid))],
2858
2882
def test_unexpected_error(self):
2861
2885
repo, client = self.setup_fake_client_and_repository(transport_path)
2862
2886
client.add_error_response(b'AnUnexpectedError')
2863
2887
e = self.assertRaises(errors.UnknownErrorFromSmartServer,
2864
repo._get_revision_graph, revid)
2888
repo._get_revision_graph, revid)
2865
2889
self.assertEqual((b'AnUnexpectedError',), e.error_tuple)
2870
2894
def test_ok(self):
2871
2895
repo, client = self.setup_fake_client_and_repository('quack')
2872
2896
client.add_expected_call(
2873
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2897
b'Repository.get_rev_id_for_revno', (b'quack/',
2898
5, (42, b'rev-foo')),
2874
2899
b'success', (b'ok', b'rev-five'))
2875
2900
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2876
2901
self.assertEqual((True, b'rev-five'), result)
2879
2904
def test_history_incomplete(self):
2880
2905
repo, client = self.setup_fake_client_and_repository('quack')
2881
2906
client.add_expected_call(
2882
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2907
b'Repository.get_rev_id_for_revno', (b'quack/',
2908
5, (42, b'rev-foo')),
2883
2909
b'success', (b'history-incomplete', 10, b'rev-ten'))
2884
2910
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2885
2911
self.assertEqual((False, (10, b'rev-ten')), result)
2901
2927
repo.add_fallback_repository(fallback_repo)
2902
2928
# First the client should ask the primary repo
2903
2929
client.add_expected_call(
2904
b'Repository.get_rev_id_for_revno', (b'quack/', 1, (42, b'rev-foo')),
2930
b'Repository.get_rev_id_for_revno', (b'quack/',
2931
1, (42, b'rev-foo')),
2905
2932
b'success', (b'history-incomplete', 2, b'rev-two'))
2906
2933
# Then it should ask the fallback, using revno/revid from the
2907
2934
# history-incomplete response as the known revno/revid.
2908
2935
client.add_expected_call(
2909
b'Repository.get_rev_id_for_revno', (b'fallback/', 1, (2, b'rev-two')),
2936
b'Repository.get_rev_id_for_revno', (
2937
b'fallback/', 1, (2, b'rev-two')),
2910
2938
b'success', (b'ok', b'rev-one'))
2911
2939
result = repo.get_rev_id_for_revno(1, (42, b'rev-foo'))
2912
2940
self.assertEqual((True, b'rev-one'), result)
2917
2945
# remote repo. The client translates that response to NoSuchRevision.
2918
2946
repo, client = self.setup_fake_client_and_repository('quack')
2919
2947
client.add_expected_call(
2920
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2948
b'Repository.get_rev_id_for_revno', (b'quack/',
2949
5, (42, b'rev-foo')),
2921
2950
b'error', (b'nosuchrevision', b'rev-foo'))
2922
2951
self.assertRaises(
2923
2952
errors.NoSuchRevision,
3098
3127
# groups. For those, fall back to the "real" repository.
3099
3128
transport_path = 'quack'
3100
3129
repo, client = self.setup_fake_client_and_repository(transport_path)
3101
3131
def stub_ensure_real():
3102
3132
client._calls.append(('_ensure_real',))
3103
3133
repo._real_repository = _StubRealPackRepository(client._calls)
3124
3154
b'Repository.start_write_group', (b'quack/', b'a token'),
3125
3155
b'success', (b'ok', [b'token1']))
3126
3156
client.add_expected_call(
3127
b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
3157
b'Repository.commit_write_group', (b'quack/',
3158
b'a token', [b'token1']),
3128
3159
b'success', (b'ok',))
3129
3160
repo.lock_write()
3130
3161
repo.start_write_group()
3140
3171
b'Repository.start_write_group', (b'quack/', b'a token'),
3141
3172
b'success', (b'ok', [b'token1']))
3142
3173
client.add_expected_call(
3143
b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
3174
b'Repository.abort_write_group', (b'quack/',
3175
b'a token', [b'token1']),
3144
3176
b'success', (b'ok',))
3145
3177
repo.lock_write()
3146
3178
repo.start_write_group()
3158
3190
b'Repository.lock_write', (b'quack/', b''),
3159
3191
b'success', (b'ok', b'a token'))
3160
3192
client.add_expected_call(
3161
b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
3193
b'Repository.check_write_group', (b'quack/',
3194
b'a token', [b'token1']),
3162
3195
b'success', (b'ok',))
3163
3196
repo.lock_write()
3164
3197
repo.resume_write_group(['token1'])
3238
3271
b'Repository.iter_files_bytes', (b'quack/', ),
3239
3272
b'success', (b'ok',), iter([b"ok\x000", b"\n", zlib.compress(b"mydata" * 10)]))
3240
3273
for (identifier, byte_stream) in repo.iter_files_bytes([(b"somefile",
3241
b"somerev", b"myid")]):
3274
b"somerev", b"myid")]):
3242
3275
self.assertEqual(b"myid", identifier)
3243
3276
self.assertEqual(b"".join(byte_stream), b"mydata" * 10)
3247
3280
repo, client = self.setup_fake_client_and_repository(transport_path)
3248
3281
client.add_expected_call(
3249
3282
b'Repository.iter_files_bytes',
3251
3284
b'error', (b'RevisionNotPresent', b'somefile', b'somerev'),
3252
3285
iter([b"absent\0somefile\0somerev\n"]))
3253
3286
self.assertRaises(errors.RevisionNotPresent, list,
3254
repo.iter_files_bytes(
3255
[(b"somefile", b"somerev", b"myid")]))
3287
repo.iter_files_bytes(
3288
[(b"somefile", b"somerev", b"myid")]))
3258
3291
class TestRepositoryInsertStreamBase(TestRemoteRepository):
3259
3292
"""Base class for Repository.insert_stream and .insert_stream_1.19
3263
3296
def checkInsertEmptyStream(self, repo, client):
3264
3297
"""Insert an empty stream, checking the result.
3355
3388
# Create a fake real repository for insert_stream to fall back on, so
3356
3389
# that we can directly see the records the RemoteSink passes to the
3358
3392
class FakeRealSink:
3359
3393
def __init__(self):
3360
3394
self.records = []
3361
3396
def insert_stream(self, stream, src_format, resume_tokens):
3362
3397
for substream_kind, substream in stream:
3363
3398
self.records.append(
3364
3399
(substream_kind, [record.key for record in substream]))
3365
3400
return [b'fake tokens'], [b'fake missing keys']
3366
3401
fake_real_sink = FakeRealSink()
3367
3403
class FakeRealRepository:
3368
3404
def _get_sink(self):
3369
3405
return fake_real_sink
3370
3407
def is_in_write_group(self):
3372
3410
def refresh_data(self):
3374
3412
repo._real_repository = FakeRealRepository()
3401
3439
# Define a stream using generators so that it isn't rewindable.
3402
3440
inv = inventory.Inventory(revision_id=b'rev1')
3403
3441
inv.root.revision = b'rev1'
3404
3443
def stream_with_inv_delta():
3405
3444
yield ('inventories', inventories_substream())
3406
3445
yield ('inventory-deltas', inventory_delta_substream())
3407
3446
yield ('texts', [
3408
3447
versionedfile.FulltextContentFactory(
3409
3448
(b'some-rev', b'some-file'), (), None, b'content')])
3410
3450
def inventories_substream():
3411
3451
# An empty inventory fulltext. This will be streamed normally.
3412
3452
text = fmt._serializer.write_inventory_to_string(inv)
3413
3453
yield versionedfile.FulltextContentFactory(
3414
3454
(b'rev1',), (), None, text)
3415
3456
def inventory_delta_substream():
3416
3457
# An inventory delta. This can't be streamed via this verb, so it
3417
3458
# will trigger a fallback to VFS insert_stream.
3498
3539
transport_path = 'repo'
3499
3540
expected_calls = [('call_expecting_body', b'Repository.tarball',
3500
3541
(b'repo/', b'bz2',),),
3502
3543
repo, client = self.setup_fake_client_and_repository(transport_path)
3503
3544
client.add_success_response_with_body(self.tarball_content, b'ok')
3504
3545
# Now actually ask for the tarball
3693
3735
def test_norepository(self):
3694
3736
bzrdir = self.make_controldir('')
3695
3737
translated_error = self.translateTuple((b'norepository',),
3697
3739
expected_error = errors.NoRepositoryPresent(bzrdir)
3698
3740
self.assertEqual(expected_error, translated_error)
3712
3754
def test_LockFailed(self):
3713
3755
lock = 'str() of a server lock'
3714
3756
why = 'str() of why'
3715
translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
3757
translated_error = self.translateTuple(
3758
(b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
3716
3759
expected_error = errors.LockFailed(lock, why)
3717
3760
self.assertEqual(expected_error, translated_error)
3719
3762
def test_TokenMismatch(self):
3720
3763
token = 'a lock token'
3721
translated_error = self.translateTuple((b'TokenMismatch',), token=token)
3764
translated_error = self.translateTuple(
3765
(b'TokenMismatch',), token=token)
3722
3766
expected_error = errors.TokenMismatch(token, '(remote token)')
3723
3767
self.assertEqual(expected_error, translated_error)
3745
3789
def test_ReadError(self):
3746
3790
path = 'a path'
3747
translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
3791
translated_error = self.translateTuple(
3792
(b'ReadError', path.encode('utf-8')))
3748
3793
expected_error = errors.ReadError(path)
3749
3794
self.assertEqual(expected_error, translated_error)
3751
3796
def test_IncompatibleRepositories(self):
3752
3797
translated_error = self.translateTuple((b'IncompatibleRepositories',
3753
b"repo1", b"repo2", b"details here"))
3798
b"repo1", b"repo2", b"details here"))
3754
3799
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
3756
3801
self.assertEqual(expected_error, translated_error)
3758
3803
def test_GhostRevisionsHaveNoRevno(self):
3759
3804
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3760
b"revid1", b"revid2"))
3805
b"revid1", b"revid2"))
3761
3806
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
3762
3807
self.assertEqual(expected_error, translated_error)
3764
3809
def test_PermissionDenied_no_args(self):
3765
3810
path = 'a path'
3766
3811
translated_error = self.translateTuple((b'PermissionDenied',),
3768
3813
expected_error = errors.PermissionDenied(path)
3769
3814
self.assertEqual(expected_error, translated_error)
3771
3816
def test_PermissionDenied_one_arg(self):
3772
3817
path = 'a path'
3773
translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
3818
translated_error = self.translateTuple(
3819
(b'PermissionDenied', path.encode('utf-8')))
3774
3820
expected_error = errors.PermissionDenied(path)
3775
3821
self.assertEqual(expected_error, translated_error)
3798
3844
def test_NoSuchFile_context_path(self):
3799
3845
local_path = "local path"
3800
3846
translated_error = self.translateTuple((b'ReadError', b"remote path"),
3802
3848
expected_error = errors.ReadError(local_path)
3803
3849
self.assertEqual(expected_error, translated_error)
3805
3851
def test_NoSuchFile_without_context(self):
3806
3852
remote_path = "remote path"
3807
translated_error = self.translateTuple((b'ReadError', remote_path.encode('utf-8')))
3853
translated_error = self.translateTuple(
3854
(b'ReadError', remote_path.encode('utf-8')))
3808
3855
expected_error = errors.ReadError(remote_path)
3809
3856
self.assertEqual(expected_error, translated_error)
3816
3863
def test_MemoryError(self):
3817
3864
translated_error = self.translateTuple((b'MemoryError',))
3818
3865
self.assertStartsWith(str(translated_error),
3819
"remote server out of memory")
3866
"remote server out of memory")
3821
3868
def test_generic_IndexError_no_classname(self):
3822
err = errors.ErrorFromSmartServer((b'error', b"list index out of range"))
3869
err = errors.ErrorFromSmartServer(
3870
(b'error', b"list index out of range"))
3823
3871
translated_error = self.translateErrorFromSmartServer(err)
3824
3872
expected_error = errors.UnknownErrorFromSmartServer(err)
3825
3873
self.assertEqual(expected_error, translated_error)
3899
3947
base_builder = self.make_branch_builder('base', format='1.9')
3900
3948
base_builder.start_series()
3901
3949
base_revid = base_builder.build_snapshot(None,
3902
[('add', ('', None, 'directory', None))],
3903
'message', revision_id=b'rev-id')
3950
[('add', ('', None, 'directory', None))],
3951
'message', revision_id=b'rev-id')
3904
3952
base_builder.finish_series()
3905
3953
stacked_branch = self.make_branch('stacked', format='1.9')
3906
3954
stacked_branch.set_stacked_on_url('../base')
3917
3965
# be a RemoteRepository
3918
3966
self.assertLength(1, remote_repo._fallback_repositories)
3919
3967
self.assertIsInstance(remote_repo._fallback_repositories[0],
3921
3969
# and it has the revision committed to the underlying repository;
3922
3970
# these have varying implementations so we try several of them
3923
3971
self.assertTrue(remote_repo.has_revisions([base_revid]))
3924
3972
self.assertTrue(remote_repo.has_revision(base_revid))
3925
3973
self.assertEqual(remote_repo.get_revision(base_revid).message,
3928
3976
remote_repo.unlock()
3933
3981
tree1 = self.make_branch_and_tree('tree1', format='1.9')
3934
3982
tree1.commit('rev1', rev_id=b'rev1')
3935
3983
tree2 = tree1.branch.controldir.sprout('tree2', stacked=True
3936
).open_workingtree()
3984
).open_workingtree()
3937
3985
local_tree = tree2.branch.create_checkout('local')
3938
3986
local_tree.commit('local changes make me feel good.')
3939
3987
branch2 = Branch.open(self.get_url('tree2'))
4012
4060
def make_stacked_stacked():
4013
4061
_, stacked = self.prepare_stacked_remote_branch()
4014
4062
tree = stacked.controldir.sprout('tree3', stacked=True
4015
).open_workingtree()
4063
).open_workingtree()
4016
4064
local_tree = tree.branch.create_checkout('local-tree3')
4017
4065
local_tree.commit('more local changes are better')
4018
4066
branch = Branch.open(self.get_url('tree3'))
4020
4068
self.addCleanup(branch.unlock)
4021
4069
return None, branch
4022
4070
rev_ord, expected_revs = self.get_ordered_revs('1.9', 'unordered',
4023
branch_factory=make_stacked_stacked)
4071
branch_factory=make_stacked_stacked)
4024
4072
self.assertEqual(set(expected_revs), set(rev_ord))
4025
4073
# Getting unordered results should have made a streaming data request
4026
4074
# from the server, and one from each backing repo
4060
4108
self.get_transport('stacked'), stacked_on=trunk.branch.base)
4061
4109
local = self.make_branch('local', format='1.9-rich-root')
4062
4110
local.repository.fetch(stacked_branch.repository,
4063
stacked_branch.last_revision())
4111
stacked_branch.last_revision())
4066
4114
class TestRemoteBranchEffort(tests.TestCaseWithTransport):
4108
4156
orig_info = request_handlers.get_info(verb_name)
4109
4157
request_handlers.register(verb_name, verb, override_existing=True)
4110
4158
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4111
override_existing=True, info=orig_info)
4159
override_existing=True, info=orig_info)
4113
4161
def test_fetch_everything_backwards_compat(self):
4114
4162
"""Can fetch with EverythingResult even with pre 2.4 servers.
4116
4164
Pre-2.4 do not support 'everything' searches with the
4117
4165
Repository.get_stream_1.19 verb.
4120
4169
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4121
4170
"""A version of the Repository.get_stream_1.19 verb patched to
4122
4171
reject 'everything' searches the way 2.3 and earlier do.
4124
4174
def recreate_search(self, repository, search_bytes,
4125
4175
discard_excess=False):
4126
4176
verb_log.append(search_bytes.split(b'\n', 1)[0])
4129
4179
request.FailedSmartServerResponse((b'BadSearch',)))
4130
4180
return super(OldGetStreamVerb,
4131
self).recreate_search(repository, search_bytes,
4132
discard_excess=discard_excess)
4181
self).recreate_search(repository, search_bytes,
4182
discard_excess=discard_excess)
4133
4183
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4134
4184
local = self.make_branch('local')
4135
4185
builder = self.make_branch_builder('remote')
4201
4251
def __init__(self, urgency):
4202
4252
self.urgency = urgency
4203
4253
remote.no_context_error_translators.register(b"OutOfCoffee",
4204
lambda err: OutOfCoffee(err.error_args[0]))
4254
lambda err: OutOfCoffee(err.error_args[0]))
4205
4255
transport = MemoryTransport()
4206
4256
client = FakeClient(transport.base)
4207
4257
client.add_expected_call(
4223
4273
self.branch = branch
4224
4274
self.urgency = urgency
4225
4275
remote.error_translators.register(b"OutOfTea",
4226
lambda err, find, path: OutOfTea(
4227
err.error_args[0].decode('utf-8'),
4276
lambda err, find, path: OutOfTea(
4277
err.error_args[0].decode(
4229
4280
transport = MemoryTransport()
4230
4281
client = FakeClient(transport.base)
4231
4282
client.add_expected_call(
4287
4338
repo._format = fmt
4288
4339
stream = [('inventory-deltas', [
4289
4340
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4290
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4341
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4291
4342
client.add_expected_call(
4292
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4343
b'VersionedFileRepository.get_inventories', (
4344
b'quack/', b'unordered'),
4293
4345
b'success', (b'ok', ),
4294
4346
_stream_to_byte_stream(stream, fmt))
4295
4347
ret = list(repo.iter_inventories([b"somerevid"]))
4307
4359
transport_path = 'quack'
4308
4360
repo, client = self.setup_fake_client_and_repository(transport_path)
4309
4361
client.add_expected_call(
4310
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4362
b'VersionedFileRepository.get_inventories', (
4363
b'quack/', b'unordered'),
4311
4364
b'success', (b'ok', ), iter([]))
4312
4365
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4313
4366
[b"somerevid"]))
4327
4380
repo._format = fmt
4328
4381
stream = [('inventory-deltas', [
4329
4382
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4330
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4383
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4331
4384
client.add_expected_call(
4332
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4385
b'VersionedFileRepository.get_inventories', (
4386
b'quack/', b'unordered'),
4333
4387
b'success', (b'ok', ),
4334
4388
_stream_to_byte_stream(stream, fmt))
4342
4396
info.size = len(contents)
4343
4397
tf.addfile(info, BytesIO(contents))
4344
4398
client.add_expected_call(
4345
b'Repository.revision_archive', (b'quack/', b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4399
b'Repository.revision_archive', (b'quack/',
4400
b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4346
4401
b'success', (b'ok', ),
4348
4403
tree = repo.revision_tree(b'somerevid')
4349
self.assertEqual(f.getvalue(), b''.join(tree.archive('tar', 'foo.tar')))
4404
self.assertEqual(f.getvalue(), b''.join(
4405
tree.archive('tar', 'foo.tar')))
4352
4408
class TestRepositoryAnnotate(TestRemoteRepository):
4363
4419
repo._format = fmt
4364
4420
stream = [('inventory-deltas', [
4365
4421
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4366
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4422
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4367
4423
client.add_expected_call(
4368
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4424
b'VersionedFileRepository.get_inventories', (
4425
b'quack/', b'unordered'),
4369
4426
b'success', (b'ok', ),
4370
4427
_stream_to_byte_stream(stream, fmt))
4371
4428
client.add_expected_call(