53
65
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
58
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
60
from bzrlib.tests import (
62
split_suite_by_condition,
67
from ..bzr import groupcompress_repo, knitpack_repo
68
from ..revision import (
72
from ..sixish import (
77
from ..bzr.smart import medium, request
78
from ..bzr.smart.client import _SmartClient
79
from ..bzr.smart.repository import (
80
SmartServerRepositoryGetParentMap,
81
SmartServerRepositoryGetStream_1_19,
82
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
87
from .scenarios import load_tests_apply_scenarios
88
from ..transport.memory import MemoryTransport
89
from ..transport.remote import (
70
91
RemoteSSHTransport,
71
92
RemoteTCPTransport,
74
def load_tests(standard_tests, module, loader):
75
to_adapt, result = split_suite_by_condition(
76
standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
smart_server_version_scenarios = [
96
load_tests = load_tests_apply_scenarios
99
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
104
test_server.SmartTCPServer_for_testing_v2_only}),
81
{'transport_server': test_server.SmartTCPServer_for_testing})]
82
return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
106
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
109
super(BasicRemoteObjectTests, self).setUp()
89
110
self.transport = self.get_transport()
90
111
# make a branch that can be opened over the smart transport
91
112
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
113
self.addCleanup(self.transport.disconnect)
97
115
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
116
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
117
self.assertIsInstance(b, BzrDir)
101
119
def test_open_remote_branch(self):
102
120
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
121
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
122
branch = b.open_branch()
105
123
self.assertIsInstance(branch, Branch)
431
446
def test_backwards_compat(self):
432
447
self.setup_smart_server_with_call_log()
433
a_dir = self.make_bzrdir('.')
448
a_dir = self.make_controldir('.')
434
449
self.reset_smart_call_log()
435
verb = 'BzrDir.cloning_metadir'
450
verb = b'BzrDir.cloning_metadir'
436
451
self.disable_verb(verb)
437
format = a_dir.cloning_metadir()
452
a_dir.cloning_metadir()
438
453
call_count = len([call for call in self.hpss_calls if
439
call.call.method == verb])
454
call.call.method == verb])
440
455
self.assertEqual(1, call_count)
442
457
def test_branch_reference(self):
443
458
transport = self.get_transport('quack')
444
459
referenced = self.make_branch('referenced')
445
expected = referenced.bzrdir.cloning_metadir()
460
expected = referenced.controldir.cloning_metadir()
446
461
client = FakeClient(transport.base)
447
462
client.add_expected_call(
448
'BzrDir.cloning_metadir', ('quack/', 'False'),
449
'error', ('BranchReference',)),
463
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
464
b'error', (b'BranchReference',)),
450
465
client.add_expected_call(
451
'BzrDir.open_branchV3', ('quack/',),
452
'success', ('ref', self.get_url('referenced'))),
453
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
455
result = a_bzrdir.cloning_metadir()
466
b'BzrDir.open_branchV3', (b'quack/',),
467
b'success', (b'ref', self.get_url('referenced').encode('utf-8'))),
468
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
470
result = a_controldir.cloning_metadir()
456
471
# We should have got a control dir matching the referenced branch.
457
472
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
458
self.assertEqual(expected._repository_format, result._repository_format)
473
self.assertEqual(expected._repository_format,
474
result._repository_format)
459
475
self.assertEqual(expected._branch_format, result._branch_format)
460
476
self.assertFinished(client)
462
478
def test_current_server(self):
463
479
transport = self.get_transport('.')
464
480
transport = transport.clone('quack')
465
self.make_bzrdir('quack')
481
self.make_controldir('quack')
466
482
client = FakeClient(transport.base)
467
reference_bzrdir_format = bzrdir.format_registry.get('default')()
483
reference_bzrdir_format = controldir.format_registry.get('default')()
468
484
control_name = reference_bzrdir_format.network_name()
469
485
client.add_expected_call(
470
'BzrDir.cloning_metadir', ('quack/', 'False'),
471
'success', (control_name, '', ('branch', ''))),
472
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
474
result = a_bzrdir.cloning_metadir()
486
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
487
b'success', (control_name, b'', (b'branch', b''))),
488
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
490
result = a_controldir.cloning_metadir()
475
491
# We should have got a reference control dir with default branch and
476
492
# repository formats.
477
493
# This pokes a little, just to be sure.
480
496
self.assertEqual(None, result._branch_format)
481
497
self.assertFinished(client)
499
def test_unknown(self):
500
transport = self.get_transport('quack')
501
referenced = self.make_branch('referenced')
502
referenced.controldir.cloning_metadir()
503
client = FakeClient(transport.base)
504
client.add_expected_call(
505
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
506
b'success', (b'unknown', b'unknown', (b'branch', b''))),
507
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
509
self.assertRaises(errors.UnknownFormatError,
510
a_controldir.cloning_metadir)
513
class TestBzrDirCheckoutMetaDir(TestRemote):
515
def test__get_checkout_format(self):
516
transport = MemoryTransport()
517
client = FakeClient(transport.base)
518
reference_bzrdir_format = controldir.format_registry.get('default')()
519
control_name = reference_bzrdir_format.network_name()
520
client.add_expected_call(
521
b'BzrDir.checkout_metadir', (b'quack/', ),
522
b'success', (control_name, b'', b''))
523
transport.mkdir('quack')
524
transport = transport.clone('quack')
525
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
527
result = a_controldir.checkout_metadir()
528
# We should have got a reference control dir with default branch and
529
# repository formats.
530
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
531
self.assertEqual(None, result._repository_format)
532
self.assertEqual(None, result._branch_format)
533
self.assertFinished(client)
535
def test_unknown_format(self):
536
transport = MemoryTransport()
537
client = FakeClient(transport.base)
538
client.add_expected_call(
539
b'BzrDir.checkout_metadir', (b'quack/',),
540
b'success', (b'dontknow', b'', b''))
541
transport.mkdir('quack')
542
transport = transport.clone('quack')
543
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
545
self.assertRaises(errors.UnknownFormatError,
546
a_controldir.checkout_metadir)
547
self.assertFinished(client)
550
class TestBzrDirGetBranches(TestRemote):
552
def test_get_branches(self):
553
transport = MemoryTransport()
554
client = FakeClient(transport.base)
555
reference_bzrdir_format = controldir.format_registry.get('default')()
556
branch_name = reference_bzrdir_format.get_branch_format().network_name()
557
client.add_success_response_with_body(
559
b"foo": (b"branch", branch_name),
560
b"": (b"branch", branch_name)}), b"success")
561
client.add_success_response(
562
b'ok', b'', b'no', b'no', b'no',
563
reference_bzrdir_format.repository_format.network_name())
564
client.add_error_response(b'NotStacked')
565
client.add_success_response(
566
b'ok', b'', b'no', b'no', b'no',
567
reference_bzrdir_format.repository_format.network_name())
568
client.add_error_response(b'NotStacked')
569
transport.mkdir('quack')
570
transport = transport.clone('quack')
571
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
573
result = a_controldir.get_branches()
574
self.assertEqual({"", "foo"}, set(result.keys()))
576
[('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
577
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
578
('call', b'Branch.get_stacked_on_url', (b'quack/', )),
579
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
580
('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
584
class TestBzrDirDestroyBranch(TestRemote):
586
def test_destroy_default(self):
587
transport = self.get_transport('quack')
588
self.make_branch('referenced')
589
client = FakeClient(transport.base)
590
client.add_expected_call(
591
b'BzrDir.destroy_branch', (b'quack/', ),
592
b'success', (b'ok',)),
593
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
595
a_controldir.destroy_branch()
596
self.assertFinished(client)
599
class TestBzrDirHasWorkingTree(TestRemote):
601
def test_has_workingtree(self):
602
transport = self.get_transport('quack')
603
client = FakeClient(transport.base)
604
client.add_expected_call(
605
b'BzrDir.has_workingtree', (b'quack/',),
606
b'success', (b'yes',)),
607
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
609
self.assertTrue(a_controldir.has_workingtree())
610
self.assertFinished(client)
612
def test_no_workingtree(self):
613
transport = self.get_transport('quack')
614
client = FakeClient(transport.base)
615
client.add_expected_call(
616
b'BzrDir.has_workingtree', (b'quack/',),
617
b'success', (b'no',)),
618
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
620
self.assertFalse(a_controldir.has_workingtree())
621
self.assertFinished(client)
624
class TestBzrDirDestroyRepository(TestRemote):
626
def test_destroy_repository(self):
627
transport = self.get_transport('quack')
628
client = FakeClient(transport.base)
629
client.add_expected_call(
630
b'BzrDir.destroy_repository', (b'quack/',),
631
b'success', (b'ok',)),
632
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
634
a_controldir.destroy_repository()
635
self.assertFinished(client)
484
638
class TestBzrDirOpen(TestRemote):
632
791
network_name = reference_format.network_name()
633
792
branch_network_name = self.get_branch_format().network_name()
634
793
client.add_expected_call(
635
'BzrDir.open_branchV3', ('~hello/',),
636
'success', ('branch', branch_network_name))
637
client.add_expected_call(
638
'BzrDir.find_repositoryV3', ('~hello/',),
639
'success', ('ok', '', 'no', 'no', 'no', network_name))
640
client.add_expected_call(
641
'Branch.get_stacked_on_url', ('~hello/',),
642
'error', ('NotStacked',))
643
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
645
result = bzrdir.open_branch()
794
b'BzrDir.open_branchV3', (b'~hello/',),
795
b'success', (b'branch', branch_network_name))
796
client.add_expected_call(
797
b'BzrDir.find_repositoryV3', (b'~hello/',),
798
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
799
client.add_expected_call(
800
b'Branch.get_stacked_on_url', (b'~hello/',),
801
b'error', (b'NotStacked',))
802
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
646
805
self.assertFinished(client)
648
def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
807
def check_open_repository(self, rich_root, subtrees,
808
external_lookup=b'no'):
649
809
reference_format = self.get_repo_format()
650
810
network_name = reference_format.network_name()
651
811
transport = MemoryTransport()
652
812
transport.mkdir('quack')
653
813
transport = transport.clone('quack')
655
rich_response = 'yes'
815
rich_response = b'yes'
817
rich_response = b'no'
659
subtree_response = 'yes'
819
subtree_response = b'yes'
661
subtree_response = 'no'
821
subtree_response = b'no'
662
822
client = FakeClient(transport.base)
663
823
client.add_success_response(
664
'ok', '', rich_response, subtree_response, external_lookup,
824
b'ok', b'', rich_response, subtree_response, external_lookup,
666
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
826
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
828
result = bzrdir.open_repository()
669
829
self.assertEqual(
670
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
830
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
672
832
self.assertIsInstance(result, RemoteRepository)
673
self.assertEqual(bzrdir, result.bzrdir)
833
self.assertEqual(bzrdir, result.controldir)
674
834
self.assertEqual(rich_root, result._format.rich_root_data)
675
835
self.assertEqual(subtrees, result._format.supports_tree_reference)
706
868
transport = transport.clone('quack')
707
869
self.make_repository('quack')
708
870
client = FakeClient(transport.base)
709
reference_bzrdir_format = bzrdir.format_registry.get('default')()
710
reference_format = reference_bzrdir_format.get_branch_format()
711
network_name = reference_format.network_name()
712
reference_repo_fmt = reference_bzrdir_format.repository_format
713
reference_repo_name = reference_repo_fmt.network_name()
714
client.add_expected_call(
715
'BzrDir.create_branch', ('quack/', network_name),
716
'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
reference_repo_name))
718
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
branch = a_bzrdir.create_branch()
871
reference_bzrdir_format = controldir.format_registry.get('default')()
872
reference_format = reference_bzrdir_format.get_branch_format()
873
network_name = reference_format.network_name()
874
reference_repo_fmt = reference_bzrdir_format.repository_format
875
reference_repo_name = reference_repo_fmt.network_name()
876
client.add_expected_call(
877
b'BzrDir.create_branch', (b'quack/', network_name),
878
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
879
reference_repo_name))
880
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
882
branch = a_controldir.create_branch()
883
# We should have got a remote branch
884
self.assertIsInstance(branch, remote.RemoteBranch)
885
# its format should have the settings from the response
886
format = branch._format
887
self.assertEqual(network_name, format.network_name())
889
def test_already_open_repo_and_reused_medium(self):
890
"""Bug 726584: create_branch(..., repository=repo) should work
891
regardless of what the smart medium's base URL is.
893
self.transport_server = test_server.SmartTCPServer_for_testing
894
transport = self.get_transport('.')
895
repo = self.make_repository('quack')
896
# Client's medium rooted a transport root (not at the bzrdir)
897
client = FakeClient(transport.base)
898
transport = transport.clone('quack')
899
reference_bzrdir_format = controldir.format_registry.get('default')()
900
reference_format = reference_bzrdir_format.get_branch_format()
901
network_name = reference_format.network_name()
902
reference_repo_fmt = reference_bzrdir_format.repository_format
903
reference_repo_name = reference_repo_fmt.network_name()
904
client.add_expected_call(
905
b'BzrDir.create_branch', (b'extra/quack/', network_name),
906
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
907
reference_repo_name))
908
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
910
branch = a_controldir.create_branch(repository=repo)
721
911
# We should have got a remote branch
722
912
self.assertIsInstance(branch, remote.RemoteBranch)
723
913
# its format should have the settings from the response
772
962
server_url = 'bzr://example.com/'
773
963
self.permit_url(server_url)
774
964
client = FakeClient(server_url)
775
client.add_unknown_method_response('BzrDir.find_repositoryV3')
776
client.add_unknown_method_response('BzrDir.find_repositoryV2')
777
client.add_success_response('ok', '', 'no', 'no')
965
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
966
client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
967
client.add_success_response(b'ok', b'', b'no', b'no')
778
968
# A real repository instance will be created to determine the network
780
970
client.add_success_response_with_body(
781
"Bazaar-NG meta directory, format 1\n", 'ok')
971
b"Bazaar-NG meta directory, format 1\n", b'ok')
972
client.add_success_response(b'stat', b'0', b'65535')
782
973
client.add_success_response_with_body(
783
reference_format.get_format_string(), 'ok')
974
reference_format.get_format_string(), b'ok')
784
975
# PackRepository wants to do a stat
785
client.add_success_response('stat', '0', '65535')
976
client.add_success_response(b'stat', b'0', b'65535')
786
977
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
788
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
979
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
790
981
repo = bzrdir.open_repository()
791
982
self.assertEqual(
792
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
793
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
('call', 'BzrDir.find_repository', ('quack/',)),
795
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
796
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
('call', 'stat', ('/quack/.bzr/repository',)),
983
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
984
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
985
('call', b'BzrDir.find_repository', (b'quack/',)),
986
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
987
('call', b'stat', (b'/quack/.bzr',)),
988
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
989
('call', b'stat', (b'/quack/.bzr/repository',)),
800
992
self.assertEqual(network_name, repo._format.network_name())
806
998
server_url = 'bzr://example.com/'
807
999
self.permit_url(server_url)
808
1000
client = FakeClient(server_url)
809
client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
client.add_success_response('ok', '', 'no', 'no', 'no')
1001
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
1002
client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
1003
# A real repository instance will be created to determine the network
813
1005
client.add_success_response_with_body(
814
"Bazaar-NG meta directory, format 1\n", 'ok')
1006
b"Bazaar-NG meta directory, format 1\n", b'ok')
1007
client.add_success_response(b'stat', b'0', b'65535')
815
1008
client.add_success_response_with_body(
816
reference_format.get_format_string(), 'ok')
1009
reference_format.get_format_string(), b'ok')
817
1010
# PackRepository wants to do a stat
818
client.add_success_response('stat', '0', '65535')
1011
client.add_success_response(b'stat', b'0', b'65535')
819
1012
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
821
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
1014
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
823
1016
repo = bzrdir.open_repository()
824
1017
self.assertEqual(
825
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
828
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
('call', 'stat', ('/quack/.bzr/repository',)),
1018
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1019
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1020
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1021
('call', b'stat', (b'/quack/.bzr',)),
1022
('call_expecting_body', b'get',
1023
(b'/quack/.bzr/repository/format',)),
1024
('call', b'stat', (b'/quack/.bzr/repository',)),
832
1027
self.assertEqual(network_name, repo._format.network_name())
853
1049
def test_success(self):
854
1050
"""Simple test for typical successful call."""
855
fmt = bzrdir.RemoteBzrDirFormat()
1051
fmt = RemoteBzrDirFormat()
856
1052
default_format_name = BzrDirFormat.get_default_format().network_name()
857
1053
transport = self.get_transport()
858
1054
client = FakeClient(transport.base)
859
1055
client.add_expected_call(
860
'BzrDirFormat.initialize_ex_1.16',
861
(default_format_name, 'path', 'False', 'False', 'False', '',
862
'', '', '', 'False'),
864
('.', 'no', 'no', 'yes', 'repo fmt', 'repo bzrdir fmt',
865
'bzrdir fmt', 'False', '', '', 'repo lock token'))
1056
b'BzrDirFormat.initialize_ex_1.16',
1057
(default_format_name, b'path', b'False', b'False', b'False', b'',
1058
b'', b'', b'', b'False'),
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'))
866
1062
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
867
1063
# it's currently hard to test that without supplying a real remote
868
1064
# transport connected to a real server.
869
result = fmt._initialize_on_transport_ex_rpc(client, 'path',
870
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,
871
1068
self.assertFinished(client)
873
1070
def test_error(self):
874
1071
"""Error responses are translated, e.g. 'PermissionDenied' raises the
875
1072
corresponding error from the client.
877
fmt = bzrdir.RemoteBzrDirFormat()
1074
fmt = RemoteBzrDirFormat()
878
1075
default_format_name = BzrDirFormat.get_default_format().network_name()
879
1076
transport = self.get_transport()
880
1077
client = FakeClient(transport.base)
881
1078
client.add_expected_call(
882
'BzrDirFormat.initialize_ex_1.16',
883
(default_format_name, 'path', 'False', 'False', 'False', '',
884
'', '', '', 'False'),
886
('PermissionDenied', 'path', 'extra info'))
1079
b'BzrDirFormat.initialize_ex_1.16',
1080
(default_format_name, b'path', b'False', b'False', b'False', b'',
1081
b'', b'', b'', b'False'),
1083
(b'PermissionDenied', b'path', b'extra info'))
887
1084
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
888
1085
# it's currently hard to test that without supplying a real remote
889
1086
# transport connected to a real server.
890
err = self.assertRaises(errors.PermissionDenied,
891
fmt._initialize_on_transport_ex_rpc, client, 'path', transport,
1087
err = self.assertRaises(
1088
errors.PermissionDenied,
1089
fmt._initialize_on_transport_ex_rpc, client, b'path', transport,
892
1090
False, False, False, None, None, None, None, False)
893
1091
self.assertEqual('path', err.path)
894
1092
self.assertEqual(': extra info', err.extra)
1101
1353
transport = MemoryTransport()
1102
1354
client = FakeClient(transport.base)
1103
1355
client.add_expected_call(
1104
'Branch.get_stacked_on_url', ('quack/',),
1105
'error', ('NotStacked',))
1356
b'Branch.get_stacked_on_url', (b'quack/',),
1357
b'error', (b'NotStacked',))
1106
1358
client.add_expected_call(
1107
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1359
b'Branch.set_tags_bytes', (b'quack/',
1360
b'branch token', b'repo token'),
1109
1362
transport.mkdir('quack')
1110
1363
transport = transport.clone('quack')
1111
1364
branch = self.make_remote_branch(transport, client)
1112
1365
self.lock_remote_branch(branch)
1113
branch._set_tags_bytes('tags bytes')
1366
branch._set_tags_bytes(b'tags bytes')
1114
1367
self.assertFinished(client)
1115
self.assertEqual('tags bytes', client._calls[-1][-1])
1368
self.assertEqual(b'tags bytes', client._calls[-1][-1])
1117
1370
def test_backwards_compatible(self):
1118
1371
transport = MemoryTransport()
1119
1372
client = FakeClient(transport.base)
1120
1373
client.add_expected_call(
1121
'Branch.get_stacked_on_url', ('quack/',),
1122
'error', ('NotStacked',))
1374
b'Branch.get_stacked_on_url', (b'quack/',),
1375
b'error', (b'NotStacked',))
1123
1376
client.add_expected_call(
1124
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1125
'unknown', ('Branch.set_tags_bytes',))
1377
b'Branch.set_tags_bytes', (b'quack/',
1378
b'branch token', b'repo token'),
1379
b'unknown', (b'Branch.set_tags_bytes',))
1126
1380
transport.mkdir('quack')
1127
1381
transport = transport.clone('quack')
1128
1382
branch = self.make_remote_branch(transport, client)
1129
1383
self.lock_remote_branch(branch)
1130
1385
class StubRealBranch(object):
1131
1386
def __init__(self):
1132
1387
self.calls = []
1133
1389
def _set_tags_bytes(self, bytes):
1134
1390
self.calls.append(('set_tags_bytes', bytes))
1135
1391
real_branch = StubRealBranch()
1136
1392
branch._real_branch = real_branch
1137
branch._set_tags_bytes('tags bytes')
1393
branch._set_tags_bytes(b'tags bytes')
1138
1394
# Call a second time, to exercise the 'remote version already inferred'
1140
branch._set_tags_bytes('tags bytes')
1141
self.assertFinished(client)
1143
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1396
branch._set_tags_bytes(b'tags bytes')
1397
self.assertFinished(client)
1399
[('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
1402
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1404
def test_uses_last_revision_info_and_tags_by_default(self):
1405
transport = MemoryTransport()
1406
client = FakeClient(transport.base)
1407
client.add_expected_call(
1408
b'Branch.get_stacked_on_url', (b'quack/',),
1409
b'error', (b'NotStacked',))
1410
client.add_expected_call(
1411
b'Branch.last_revision_info', (b'quack/',),
1412
b'success', (b'ok', b'1', b'rev-tip'))
1413
client.add_expected_call(
1414
b'Branch.get_config_file', (b'quack/',),
1415
b'success', (b'ok',), b'')
1416
transport.mkdir('quack')
1417
transport = transport.clone('quack')
1418
branch = self.make_remote_branch(transport, client)
1419
result = branch.heads_to_fetch()
1420
self.assertFinished(client)
1421
self.assertEqual(({b'rev-tip'}, set()), result)
1423
def test_uses_last_revision_info_and_tags_when_set(self):
1424
transport = MemoryTransport()
1425
client = FakeClient(transport.base)
1426
client.add_expected_call(
1427
b'Branch.get_stacked_on_url', (b'quack/',),
1428
b'error', (b'NotStacked',))
1429
client.add_expected_call(
1430
b'Branch.last_revision_info', (b'quack/',),
1431
b'success', (b'ok', b'1', b'rev-tip'))
1432
client.add_expected_call(
1433
b'Branch.get_config_file', (b'quack/',),
1434
b'success', (b'ok',), b'branch.fetch_tags = True')
1435
# XXX: this will break if the default format's serialization of tags
1436
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1437
client.add_expected_call(
1438
b'Branch.get_tags_bytes', (b'quack/',),
1439
b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
1440
transport.mkdir('quack')
1441
transport = transport.clone('quack')
1442
branch = self.make_remote_branch(transport, client)
1443
result = branch.heads_to_fetch()
1444
self.assertFinished(client)
1446
({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
1448
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1449
transport = MemoryTransport()
1450
client = FakeClient(transport.base)
1451
client.add_expected_call(
1452
b'Branch.get_stacked_on_url', (b'quack/',),
1453
b'error', (b'NotStacked',))
1454
client.add_expected_call(
1455
b'Branch.heads_to_fetch', (b'quack/',),
1456
b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
1457
transport.mkdir('quack')
1458
transport = transport.clone('quack')
1459
branch = self.make_remote_branch(transport, client)
1460
branch._format._use_default_local_heads_to_fetch = lambda: False
1461
result = branch.heads_to_fetch()
1462
self.assertFinished(client)
1463
self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
1465
def make_branch_with_tags(self):
1466
self.setup_smart_server_with_call_log()
1467
# Make a branch with a single revision.
1468
builder = self.make_branch_builder('foo')
1469
builder.start_series()
1470
builder.build_snapshot(None, [
1471
('add', ('', b'root-id', 'directory', ''))],
1473
builder.finish_series()
1474
branch = builder.get_branch()
1475
# Add two tags to that branch
1476
branch.tags.set_tag('tag-1', b'rev-1')
1477
branch.tags.set_tag('tag-2', b'rev-2')
1480
def test_backwards_compatible(self):
1481
br = self.make_branch_with_tags()
1482
br.get_config_stack().set('branch.fetch_tags', True)
1483
self.addCleanup(br.lock_read().unlock)
1484
# Disable the heads_to_fetch verb
1485
verb = b'Branch.heads_to_fetch'
1486
self.disable_verb(verb)
1487
self.reset_smart_call_log()
1488
result = br.heads_to_fetch()
1489
self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
1491
[b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
1492
[call.call.method for call in self.hpss_calls])
1494
def test_backwards_compatible_no_tags(self):
1495
br = self.make_branch_with_tags()
1496
br.get_config_stack().set('branch.fetch_tags', False)
1497
self.addCleanup(br.lock_read().unlock)
1498
# Disable the heads_to_fetch verb
1499
verb = b'Branch.heads_to_fetch'
1500
self.disable_verb(verb)
1501
self.reset_smart_call_log()
1502
result = br.heads_to_fetch()
1503
self.assertEqual(({b'tip'}, set()), result)
1505
[b'Branch.last_revision_info'],
1506
[call.call.method for call in self.hpss_calls])
1146
1509
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1190
1553
# doesn't just open in - this test probably needs to be rewritten using
1191
1554
# a spawn()ed server.
1192
1555
stacked_branch = self.make_branch('stacked', format='1.9')
1193
memory_branch = self.make_branch('base', format='1.9')
1556
self.make_branch('base', format='1.9')
1194
1557
vfs_url = self.get_vfs_only_url('base')
1195
1558
stacked_branch.set_stacked_on_url(vfs_url)
1196
transport = stacked_branch.bzrdir.root_transport
1559
transport = stacked_branch.controldir.root_transport
1197
1560
client = FakeClient(transport.base)
1198
1561
client.add_expected_call(
1199
'Branch.get_stacked_on_url', ('stacked/',),
1200
'success', ('ok', vfs_url))
1562
b'Branch.get_stacked_on_url', (b'stacked/',),
1563
b'success', (b'ok', vfs_url.encode('utf-8')))
1201
1564
# XXX: Multiple calls are bad, this second call documents what is
1203
1566
client.add_expected_call(
1204
'Branch.get_stacked_on_url', ('stacked/',),
1205
'success', ('ok', vfs_url))
1206
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1567
b'Branch.get_stacked_on_url', (b'stacked/',),
1568
b'success', (b'ok', vfs_url.encode('utf-8')))
1569
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1208
1571
repo_fmt = remote.RemoteRepositoryFormat()
1209
1572
repo_fmt._custom_format = stacked_branch.repository._format
1210
1573
branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
1212
1575
result = branch.get_stacked_on_url()
1213
1576
self.assertEqual(vfs_url, result)
1215
1578
def test_backwards_compatible(self):
1216
1579
# like with bzr1.6 with no Branch.get_stacked_on_url rpc
1217
base_branch = self.make_branch('base', format='1.6')
1580
self.make_branch('base', format='1.6')
1218
1581
stacked_branch = self.make_branch('stacked', format='1.6')
1219
1582
stacked_branch.set_stacked_on_url('../base')
1220
1583
client = FakeClient(self.get_url())
1221
1584
branch_network_name = self.get_branch_format().network_name()
1222
1585
client.add_expected_call(
1223
'BzrDir.open_branchV3', ('stacked/',),
1224
'success', ('branch', branch_network_name))
1586
b'BzrDir.open_branchV3', (b'stacked/',),
1587
b'success', (b'branch', branch_network_name))
1225
1588
client.add_expected_call(
1226
'BzrDir.find_repositoryV3', ('stacked/',),
1227
'success', ('ok', '', 'no', 'no', 'yes',
1228
stacked_branch.repository._format.network_name()))
1589
b'BzrDir.find_repositoryV3', (b'stacked/',),
1590
b'success', (b'ok', b'', b'no', b'no', b'yes',
1591
stacked_branch.repository._format.network_name()))
1229
1592
# called twice, once from constructor and then again by us
1230
1593
client.add_expected_call(
1231
'Branch.get_stacked_on_url', ('stacked/',),
1232
'unknown', ('Branch.get_stacked_on_url',))
1594
b'Branch.get_stacked_on_url', (b'stacked/',),
1595
b'unknown', (b'Branch.get_stacked_on_url',))
1233
1596
client.add_expected_call(
1234
'Branch.get_stacked_on_url', ('stacked/',),
1235
'unknown', ('Branch.get_stacked_on_url',))
1597
b'Branch.get_stacked_on_url', (b'stacked/',),
1598
b'unknown', (b'Branch.get_stacked_on_url',))
1236
1599
# this will also do vfs access, but that goes direct to the transport
1237
1600
# and isn't seen by the FakeClient.
1238
1601
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
remote.RemoteBzrDirFormat(), _client=client)
1602
RemoteBzrDirFormat(), _client=client)
1240
1603
branch = bzrdir.open_branch()
1241
1604
result = branch.get_stacked_on_url()
1242
1605
self.assertEqual('../base', result)
1292
1655
client = FakeClient(transport.base)
1293
1656
client.add_expected_call(
1294
'Branch.get_stacked_on_url', ('branch/',),
1295
'error', ('NotStacked',))
1296
client.add_expected_call(
1297
'Branch.lock_write', ('branch/', '', ''),
1298
'success', ('ok', 'branch token', 'repo token'))
1299
client.add_expected_call(
1300
'Branch.last_revision_info',
1302
'success', ('ok', '0', 'null:'))
1303
client.add_expected_call(
1304
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
1306
client.add_expected_call(
1307
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1657
b'Branch.get_stacked_on_url', (b'branch/',),
1658
b'error', (b'NotStacked',))
1659
client.add_expected_call(
1660
b'Branch.lock_write', (b'branch/', b'', b''),
1661
b'success', (b'ok', b'branch token', b'repo token'))
1662
client.add_expected_call(
1663
b'Branch.last_revision_info',
1665
b'success', (b'ok', b'0', b'null:'))
1666
client.add_expected_call(
1667
b'Branch.set_last_revision', (b'branch/',
1668
b'branch token', b'repo token', b'null:',),
1669
b'success', (b'ok',))
1670
client.add_expected_call(
1671
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1672
b'success', (b'ok',))
1309
1673
branch = self.make_remote_branch(transport, client)
1310
# This is a hack to work around the problem that RemoteBranch currently
1311
# unnecessarily invokes _ensure_real upon a call to lock_write.
1312
branch._ensure_real = lambda: None
1313
1674
branch.lock_write()
1314
result = branch.set_revision_history([])
1675
result = branch._set_last_revision(NULL_REVISION)
1315
1676
branch.unlock()
1316
1677
self.assertEqual(None, result)
1317
1678
self.assertFinished(client)
1319
1680
def test_set_nonempty(self):
1320
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1681
# set_last_revision_info(N, rev-idN) is translated to calling
1321
1682
# Branch.set_last_revision(path, rev-idN) on the wire.
1322
1683
transport = MemoryTransport()
1323
1684
transport.mkdir('branch')
1326
1687
client = FakeClient(transport.base)
1327
1688
client.add_expected_call(
1328
'Branch.get_stacked_on_url', ('branch/',),
1329
'error', ('NotStacked',))
1330
client.add_expected_call(
1331
'Branch.lock_write', ('branch/', '', ''),
1332
'success', ('ok', 'branch token', 'repo token'))
1333
client.add_expected_call(
1334
'Branch.last_revision_info',
1336
'success', ('ok', '0', 'null:'))
1338
encoded_body = bz2.compress('\n'.join(lines))
1339
client.add_success_response_with_body(encoded_body, 'ok')
1340
client.add_expected_call(
1341
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
1343
client.add_expected_call(
1344
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1689
b'Branch.get_stacked_on_url', (b'branch/',),
1690
b'error', (b'NotStacked',))
1691
client.add_expected_call(
1692
b'Branch.lock_write', (b'branch/', b'', b''),
1693
b'success', (b'ok', b'branch token', b'repo token'))
1694
client.add_expected_call(
1695
b'Branch.last_revision_info',
1697
b'success', (b'ok', b'0', b'null:'))
1698
lines = [b'rev-id2']
1699
encoded_body = bz2.compress(b'\n'.join(lines))
1700
client.add_success_response_with_body(encoded_body, b'ok')
1701
client.add_expected_call(
1702
b'Branch.set_last_revision', (b'branch/',
1703
b'branch token', b'repo token', b'rev-id2',),
1704
b'success', (b'ok',))
1705
client.add_expected_call(
1706
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1707
b'success', (b'ok',))
1346
1708
branch = self.make_remote_branch(transport, client)
1347
# This is a hack to work around the problem that RemoteBranch currently
1348
# unnecessarily invokes _ensure_real upon a call to lock_write.
1349
branch._ensure_real = lambda: None
1350
1709
# Lock the branch, reset the record of remote calls.
1351
1710
branch.lock_write()
1352
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1711
result = branch._set_last_revision(b'rev-id2')
1353
1712
branch.unlock()
1354
1713
self.assertEqual(None, result)
1355
1714
self.assertFinished(client)
1361
1720
# A response of 'NoSuchRevision' is translated into an exception.
1362
1721
client = FakeClient(transport.base)
1363
1722
client.add_expected_call(
1364
'Branch.get_stacked_on_url', ('branch/',),
1365
'error', ('NotStacked',))
1366
client.add_expected_call(
1367
'Branch.lock_write', ('branch/', '', ''),
1368
'success', ('ok', 'branch token', 'repo token'))
1369
client.add_expected_call(
1370
'Branch.last_revision_info',
1372
'success', ('ok', '0', 'null:'))
1723
b'Branch.get_stacked_on_url', (b'branch/',),
1724
b'error', (b'NotStacked',))
1725
client.add_expected_call(
1726
b'Branch.lock_write', (b'branch/', b'', b''),
1727
b'success', (b'ok', b'branch token', b'repo token'))
1728
client.add_expected_call(
1729
b'Branch.last_revision_info',
1731
b'success', (b'ok', b'0', b'null:'))
1373
1732
# get_graph calls to construct the revision history, for the set_rh
1376
encoded_body = bz2.compress('\n'.join(lines))
1377
client.add_success_response_with_body(encoded_body, 'ok')
1378
client.add_expected_call(
1379
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1380
'error', ('NoSuchRevision', 'rev-id'))
1381
client.add_expected_call(
1382
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1735
encoded_body = bz2.compress(b'\n'.join(lines))
1736
client.add_success_response_with_body(encoded_body, b'ok')
1737
client.add_expected_call(
1738
b'Branch.set_last_revision', (b'branch/',
1739
b'branch token', b'repo token', b'rev-id',),
1740
b'error', (b'NoSuchRevision', b'rev-id'))
1741
client.add_expected_call(
1742
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1743
b'success', (b'ok',))
1385
1745
branch = self.make_remote_branch(transport, client)
1386
1746
branch.lock_write()
1387
1747
self.assertRaises(
1388
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1748
errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1749
branch.unlock()
1390
1750
self.assertFinished(client)
1400
1760
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1761
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1762
client.add_expected_call(
1403
'Branch.get_stacked_on_url', ('branch/',),
1404
'error', ('NotStacked',))
1405
client.add_expected_call(
1406
'Branch.lock_write', ('branch/', '', ''),
1407
'success', ('ok', 'branch token', 'repo token'))
1408
client.add_expected_call(
1409
'Branch.last_revision_info',
1411
'success', ('ok', '0', 'null:'))
1413
encoded_body = bz2.compress('\n'.join(lines))
1414
client.add_success_response_with_body(encoded_body, 'ok')
1415
client.add_expected_call(
1416
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1417
'error', ('TipChangeRejected', rejection_msg_utf8))
1418
client.add_expected_call(
1419
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1763
b'Branch.get_stacked_on_url', (b'branch/',),
1764
b'error', (b'NotStacked',))
1765
client.add_expected_call(
1766
b'Branch.lock_write', (b'branch/', b'', b''),
1767
b'success', (b'ok', b'branch token', b'repo token'))
1768
client.add_expected_call(
1769
b'Branch.last_revision_info',
1771
b'success', (b'ok', b'0', b'null:'))
1773
encoded_body = bz2.compress(b'\n'.join(lines))
1774
client.add_success_response_with_body(encoded_body, b'ok')
1775
client.add_expected_call(
1776
b'Branch.set_last_revision', (b'branch/',
1777
b'branch token', b'repo token', b'rev-id',),
1778
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1779
client.add_expected_call(
1780
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1781
b'success', (b'ok',))
1421
1782
branch = self.make_remote_branch(transport, client)
1422
branch._ensure_real = lambda: None
1423
1783
branch.lock_write()
1424
1784
# The 'TipChangeRejected' error response triggered by calling
1425
# set_revision_history causes a TipChangeRejected exception.
1785
# set_last_revision_info causes a TipChangeRejected exception.
1426
1786
err = self.assertRaises(
1427
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1787
errors.TipChangeRejected,
1788
branch._set_last_revision, b'rev-id')
1428
1789
# The UTF-8 message from the response has been decoded into a unicode
1430
self.assertIsInstance(err.msg, unicode)
1791
self.assertIsInstance(err.msg, text_type)
1431
1792
self.assertEqual(rejection_msg_unicode, err.msg)
1432
1793
branch.unlock()
1433
1794
self.assertFinished(client)
1652
2016
branch.unlock()
1653
2017
self.assertFinished(client)
2019
def test_set_option_with_dict(self):
2020
client = FakeClient()
2021
client.add_expected_call(
2022
b'Branch.get_stacked_on_url', (b'memory:///',),
2023
b'error', (b'NotStacked',),)
2024
client.add_expected_call(
2025
b'Branch.lock_write', (b'memory:///', b'', b''),
2026
b'success', (b'ok', b'branch token', b'repo token'))
2027
encoded_dict_value = b'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
2028
client.add_expected_call(
2029
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2030
b'repo token', encoded_dict_value, b'foo', b''),
2032
client.add_expected_call(
2033
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2034
b'success', (b'ok',))
2035
transport = MemoryTransport()
2036
branch = self.make_remote_branch(transport, client)
2038
config = branch._get_config()
2040
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
2043
self.assertFinished(client)
1655
2045
def test_backwards_compat_set_option(self):
1656
2046
self.setup_smart_server_with_call_log()
1657
2047
branch = self.make_branch('.')
1658
verb = 'Branch.set_config_option'
2048
verb = b'Branch.set_config_option'
1659
2049
self.disable_verb(verb)
1660
2050
branch.lock_write()
1661
2051
self.addCleanup(branch.unlock)
1662
2052
self.reset_smart_call_log()
1663
2053
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2054
self.assertLength(11, self.hpss_calls)
1665
2055
self.assertEqual('value', branch._get_config().get_option('name'))
2057
def test_backwards_compat_set_option_with_dict(self):
2058
self.setup_smart_server_with_call_log()
2059
branch = self.make_branch('.')
2060
verb = b'Branch.set_config_option_dict'
2061
self.disable_verb(verb)
2063
self.addCleanup(branch.unlock)
2064
self.reset_smart_call_log()
2065
config = branch._get_config()
2066
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2067
config.set_option(value_dict, 'name')
2068
self.assertLength(11, self.hpss_calls)
2069
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2072
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2074
def test_get_branch_conf(self):
2075
# in an empty branch we decode the response properly
2076
client = FakeClient()
2077
client.add_expected_call(
2078
b'Branch.get_stacked_on_url', (b'memory:///',),
2079
b'error', (b'NotStacked',),)
2080
client.add_success_response_with_body(b'# config file body', b'ok')
2081
transport = MemoryTransport()
2082
branch = self.make_remote_branch(transport, client)
2083
config = branch.get_config_stack()
2085
config.get("log_format")
2087
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2088
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
2091
def test_set_branch_conf(self):
2092
client = FakeClient()
2093
client.add_expected_call(
2094
b'Branch.get_stacked_on_url', (b'memory:///',),
2095
b'error', (b'NotStacked',),)
2096
client.add_expected_call(
2097
b'Branch.lock_write', (b'memory:///', b'', b''),
2098
b'success', (b'ok', b'branch token', b'repo token'))
2099
client.add_expected_call(
2100
b'Branch.get_config_file', (b'memory:///', ),
2101
b'success', (b'ok', ), b"# line 1\n")
2102
client.add_expected_call(
2103
b'Branch.get_config_file', (b'memory:///', ),
2104
b'success', (b'ok', ), b"# line 1\n")
2105
client.add_expected_call(
2106
b'Branch.put_config_file', (b'memory:///', b'branch token',
2108
b'success', (b'ok',))
2109
client.add_expected_call(
2110
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2111
b'success', (b'ok',))
2112
transport = MemoryTransport()
2113
branch = self.make_remote_branch(transport, client)
2115
config = branch.get_config_stack()
2116
config.set('email', 'The Dude <lebowski@example.com>')
2118
self.assertFinished(client)
2120
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2121
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2122
('call_expecting_body', b'Branch.get_config_file',
2124
('call_expecting_body', b'Branch.get_config_file',
2126
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2127
(b'memory:///', b'branch token', b'repo token'),
2128
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2129
('call', b'Branch.unlock',
2130
(b'memory:///', b'branch token', b'repo token'))],
1668
2134
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2149
self.assertFinished(client)
2152
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2154
def test_simple(self):
2155
transport = MemoryTransport()
2156
client = FakeClient(transport.base)
2157
client.add_expected_call(
2158
b'Branch.get_stacked_on_url', (b'quack/',),
2159
b'error', (b'NotStacked',),)
2160
client.add_expected_call(
2161
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2162
b'success', (b'ok', b'0',),)
2163
client.add_expected_call(
2164
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2165
b'error', (b'NoSuchRevision', b'unknown',),)
2166
transport.mkdir('quack')
2167
transport = transport.clone('quack')
2168
branch = self.make_remote_branch(transport, client)
2169
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2170
self.assertRaises(errors.NoSuchRevision,
2171
branch.revision_id_to_revno, b'unknown')
2172
self.assertFinished(client)
2174
def test_dotted(self):
2175
transport = MemoryTransport()
2176
client = FakeClient(transport.base)
2177
client.add_expected_call(
2178
b'Branch.get_stacked_on_url', (b'quack/',),
2179
b'error', (b'NotStacked',),)
2180
client.add_expected_call(
2181
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2182
b'success', (b'ok', b'0',),)
2183
client.add_expected_call(
2184
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2185
b'error', (b'NoSuchRevision', b'unknown',),)
2186
transport.mkdir('quack')
2187
transport = transport.clone('quack')
2188
branch = self.make_remote_branch(transport, client)
2189
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2190
self.assertRaises(errors.NoSuchRevision,
2191
branch.revision_id_to_dotted_revno, b'unknown')
2192
self.assertFinished(client)
2194
def test_dotted_no_smart_verb(self):
2195
self.setup_smart_server_with_call_log()
2196
branch = self.make_branch('.')
2197
self.disable_verb(b'Branch.revision_id_to_revno')
2198
self.reset_smart_call_log()
2199
self.assertEqual((0, ),
2200
branch.revision_id_to_dotted_revno(b'null:'))
2201
self.assertLength(8, self.hpss_calls)
1686
2204
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2206
def test__get_config(self):
1689
2207
client = FakeClient()
1690
client.add_success_response_with_body('default_stack_on = /\n', 'ok')
2208
client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2209
transport = MemoryTransport()
1692
2210
bzrdir = self.make_remote_bzrdir(transport, client)
1693
2211
config = bzrdir.get_config()
1694
2212
self.assertEqual('/', config.get_default_stack_on())
1695
2213
self.assertEqual(
1696
[('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
2214
[('call_expecting_body', b'BzrDir.get_config_file',
1699
2218
def test_set_option_uses_vfs(self):
1700
2219
self.setup_smart_server_with_call_log()
1701
bzrdir = self.make_bzrdir('.')
2220
bzrdir = self.make_controldir('.')
1702
2221
self.reset_smart_call_log()
1703
2222
config = bzrdir.get_config()
1704
2223
config.set_default_stack_on('/')
1705
self.assertLength(3, self.hpss_calls)
2224
self.assertLength(4, self.hpss_calls)
1707
2226
def test_backwards_compat_get_option(self):
1708
2227
self.setup_smart_server_with_call_log()
1709
bzrdir = self.make_bzrdir('.')
1710
verb = 'BzrDir.get_config_file'
2228
bzrdir = self.make_controldir('.')
2229
verb = b'BzrDir.get_config_file'
1711
2230
self.disable_verb(verb)
1712
2231
self.reset_smart_call_log()
1713
2232
self.assertEqual(None,
1714
bzrdir._get_config().get_option('default_stack_on'))
1715
self.assertLength(3, self.hpss_calls)
2233
bzrdir._get_config().get_option('default_stack_on'))
2234
self.assertLength(4, self.hpss_calls)
1718
2237
class TestTransportIsReadonly(tests.TestCase):
1720
2239
def test_true(self):
1721
2240
client = FakeClient()
1722
client.add_success_response('yes')
2241
client.add_success_response(b'yes')
1723
2242
transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2243
_client=client)
1725
2244
self.assertEqual(True, transport.is_readonly())
1726
2245
self.assertEqual(
1727
[('call', 'Transport.is_readonly', ())],
2246
[('call', b'Transport.is_readonly', ())],
1730
2249
def test_false(self):
1731
2250
client = FakeClient()
1732
client.add_success_response('no')
2251
client.add_success_response(b'no')
1733
2252
transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2253
_client=client)
1735
2254
self.assertEqual(False, transport.is_readonly())
1736
2255
self.assertEqual(
1737
[('call', 'Transport.is_readonly', ())],
2256
[('call', b'Transport.is_readonly', ())],
1740
2259
def test_error_from_old_server(self):
1852
2398
transport_path = 'quack'
1853
2399
repo, client = self.setup_fake_client_and_repository(transport_path)
1854
2400
client.add_success_response_with_body(
1855
'revisions: 2\nsize: 18\n', 'ok')
2401
b'revisions: 2\nsize: 18\n', b'ok')
1856
2402
result = repo.gather_stats(None)
1857
2403
self.assertEqual(
1858
[('call_expecting_body', 'Repository.gather_stats',
1859
('quack/','','no'))],
2404
[('call_expecting_body', b'Repository.gather_stats',
2405
(b'quack/', b'', b'no'))],
1861
2407
self.assertEqual({'revisions': 2, 'size': 18}, result)
1863
2409
def test_revid_no_committers(self):
1864
2410
# ('ok',), body without committers
1865
body = ('firstrev: 123456.300 3600\n'
1866
'latestrev: 654231.400 0\n'
2411
body = (b'firstrev: 123456.300 3600\n'
2412
b'latestrev: 654231.400 0\n'
1869
2415
transport_path = 'quick'
1870
2416
revid = u'\xc8'.encode('utf8')
1871
2417
repo, client = self.setup_fake_client_and_repository(transport_path)
1872
client.add_success_response_with_body(body, 'ok')
2418
client.add_success_response_with_body(body, b'ok')
1873
2419
result = repo.gather_stats(revid)
1874
2420
self.assertEqual(
1875
[('call_expecting_body', 'Repository.gather_stats',
1876
('quick/', revid, 'no'))],
2421
[('call_expecting_body', b'Repository.gather_stats',
2422
(b'quick/', revid, b'no'))],
1878
2424
self.assertEqual({'revisions': 2, 'size': 18,
1879
2425
'firstrev': (123456.300, 3600),
1880
'latestrev': (654231.400, 0),},
2426
'latestrev': (654231.400, 0), },
1883
2429
def test_revid_with_committers(self):
1884
2430
# ('ok',), body with committers
1885
body = ('committers: 128\n'
1886
'firstrev: 123456.300 3600\n'
1887
'latestrev: 654231.400 0\n'
2431
body = (b'committers: 128\n'
2432
b'firstrev: 123456.300 3600\n'
2433
b'latestrev: 654231.400 0\n'
1890
2436
transport_path = 'buick'
1891
2437
revid = u'\xc8'.encode('utf8')
1892
2438
repo, client = self.setup_fake_client_and_repository(transport_path)
1893
client.add_success_response_with_body(body, 'ok')
2439
client.add_success_response_with_body(body, b'ok')
1894
2440
result = repo.gather_stats(revid, True)
1895
2441
self.assertEqual(
1896
[('call_expecting_body', 'Repository.gather_stats',
1897
('buick/', revid, 'yes'))],
2442
[('call_expecting_body', b'Repository.gather_stats',
2443
(b'buick/', revid, b'yes'))],
1899
2445
self.assertEqual({'revisions': 2, 'size': 18,
1900
2446
'committers': 128,
1901
2447
'firstrev': (123456.300, 3600),
1902
'latestrev': (654231.400, 0),},
2448
'latestrev': (654231.400, 0), },
2452
class TestRepositoryBreakLock(TestRemoteRepository):
2454
def test_break_lock(self):
2455
transport_path = 'quack'
2456
repo, client = self.setup_fake_client_and_repository(transport_path)
2457
client.add_success_response(b'ok')
2460
[('call', b'Repository.break_lock', (b'quack/',))],
2464
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2466
def test_get_serializer_format(self):
2467
transport_path = 'hill'
2468
repo, client = self.setup_fake_client_and_repository(transport_path)
2469
client.add_success_response(b'ok', b'7')
2470
self.assertEqual(b'7', repo.get_serializer_format())
2472
[('call', b'VersionedFileRepository.get_serializer_format',
2477
class TestRepositoryReconcile(TestRemoteRepository):
2479
def test_reconcile(self):
2480
transport_path = 'hill'
2481
repo, client = self.setup_fake_client_and_repository(transport_path)
2482
body = (b"garbage_inventories: 2\n"
2483
b"inconsistent_parents: 3\n")
2484
client.add_expected_call(
2485
b'Repository.lock_write', (b'hill/', b''),
2486
b'success', (b'ok', b'a token'))
2487
client.add_success_response_with_body(body, b'ok')
2488
reconciler = repo.reconcile()
2490
[('call', b'Repository.lock_write', (b'hill/', b'')),
2491
('call_expecting_body', b'Repository.reconcile',
2492
(b'hill/', b'a token'))],
2494
self.assertEqual(2, reconciler.garbage_inventories)
2495
self.assertEqual(3, reconciler.inconsistent_parents)
2498
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2500
def test_text(self):
2501
# ('ok',), body with signature text
2502
transport_path = 'quack'
2503
repo, client = self.setup_fake_client_and_repository(transport_path)
2504
client.add_success_response_with_body(
2506
self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
2508
[('call_expecting_body', b'Repository.get_revision_signature_text',
2509
(b'quack/', b'revid'))],
2512
def test_no_signature(self):
2513
transport_path = 'quick'
2514
repo, client = self.setup_fake_client_and_repository(transport_path)
2515
client.add_error_response(b'nosuchrevision', b'unknown')
2516
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2519
[('call_expecting_body', b'Repository.get_revision_signature_text',
2520
(b'quick/', b'unknown'))],
1906
2524
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2526
def test_get_graph(self):
2257
2976
self.setup_smart_server_with_call_log()
2258
2977
tree = self.make_branch_and_memory_tree('.')
2259
2978
tree.lock_write()
2260
2980
rev1 = tree.commit('First')
2261
rev2 = tree.commit('Second')
2981
tree.commit('Second')
2263
2983
branch = tree.branch
2264
2984
self.assertFalse(branch.is_locked())
2265
2985
self.reset_smart_call_log()
2266
verb = 'Repository.get_rev_id_for_revno'
2986
verb = b'Repository.get_rev_id_for_revno'
2267
2987
self.disable_verb(verb)
2268
2988
self.assertEqual(rev1, branch.get_rev_id(1))
2269
2989
self.assertLength(1, [call for call in self.hpss_calls if
2270
2990
call.call.method == verb])
2993
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2995
def test_has_signature_for_revision_id(self):
2996
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2997
transport_path = 'quack'
2998
repo, client = self.setup_fake_client_and_repository(transport_path)
2999
client.add_success_response(b'yes')
3000
result = repo.has_signature_for_revision_id(b'A')
3002
[('call', b'Repository.has_signature_for_revision_id',
3003
(b'quack/', b'A'))],
3005
self.assertEqual(True, result)
3007
def test_is_not_shared(self):
3008
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
3009
transport_path = 'qwack'
3010
repo, client = self.setup_fake_client_and_repository(transport_path)
3011
client.add_success_response(b'no')
3012
result = repo.has_signature_for_revision_id(b'A')
3014
[('call', b'Repository.has_signature_for_revision_id',
3015
(b'qwack/', b'A'))],
3017
self.assertEqual(False, result)
3020
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
3022
def test_get_physical_lock_status_yes(self):
3023
transport_path = 'qwack'
3024
repo, client = self.setup_fake_client_and_repository(transport_path)
3025
client.add_success_response(b'yes')
3026
result = repo.get_physical_lock_status()
3028
[('call', b'Repository.get_physical_lock_status',
3031
self.assertEqual(True, result)
3033
def test_get_physical_lock_status_no(self):
3034
transport_path = 'qwack'
3035
repo, client = self.setup_fake_client_and_repository(transport_path)
3036
client.add_success_response(b'no')
3037
result = repo.get_physical_lock_status()
3039
[('call', b'Repository.get_physical_lock_status',
3042
self.assertEqual(False, result)
2273
3045
class TestRepositoryIsShared(TestRemoteRepository):
2275
3047
def test_is_shared(self):
2276
3048
# ('yes', ) for Repository.is_shared -> 'True'.
2277
3049
transport_path = 'quack'
2278
3050
repo, client = self.setup_fake_client_and_repository(transport_path)
2279
client.add_success_response('yes')
3051
client.add_success_response(b'yes')
2280
3052
result = repo.is_shared()
2281
3053
self.assertEqual(
2282
[('call', 'Repository.is_shared', ('quack/',))],
3054
[('call', b'Repository.is_shared', (b'quack/',))],
2284
3056
self.assertEqual(True, result)
2300
3097
def test_lock_write(self):
2301
3098
transport_path = 'quack'
2302
3099
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
3100
client.add_success_response(b'ok', b'a token')
3101
token = repo.lock_write().repository_token
2305
3102
self.assertEqual(
2306
[('call', 'Repository.lock_write', ('quack/', ''))],
3103
[('call', b'Repository.lock_write', (b'quack/', b''))],
2308
self.assertEqual('a token', result)
3105
self.assertEqual(b'a token', token)
2310
3107
def test_lock_write_already_locked(self):
2311
3108
transport_path = 'quack'
2312
3109
repo, client = self.setup_fake_client_and_repository(transport_path)
2313
client.add_error_response('LockContention')
3110
client.add_error_response(b'LockContention')
2314
3111
self.assertRaises(errors.LockContention, repo.lock_write)
2315
3112
self.assertEqual(
2316
[('call', 'Repository.lock_write', ('quack/', ''))],
3113
[('call', b'Repository.lock_write', (b'quack/', b''))],
2319
3116
def test_lock_write_unlockable(self):
2320
3117
transport_path = 'quack'
2321
3118
repo, client = self.setup_fake_client_and_repository(transport_path)
2322
client.add_error_response('UnlockableTransport')
3119
client.add_error_response(b'UnlockableTransport')
2323
3120
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3121
self.assertEqual(
2325
[('call', 'Repository.lock_write', ('quack/', ''))],
3122
[('call', b'Repository.lock_write', (b'quack/', b''))],
3126
class TestRepositoryWriteGroups(TestRemoteRepository):
3128
def test_start_write_group(self):
3129
transport_path = 'quack'
3130
repo, client = self.setup_fake_client_and_repository(transport_path)
3131
client.add_expected_call(
3132
b'Repository.lock_write', (b'quack/', b''),
3133
b'success', (b'ok', b'a token'))
3134
client.add_expected_call(
3135
b'Repository.start_write_group', (b'quack/', b'a token'),
3136
b'success', (b'ok', (b'token1', )))
3138
repo.start_write_group()
3140
def test_start_write_group_unsuspendable(self):
3141
# Some repositories do not support suspending write
3142
# groups. For those, fall back to the "real" repository.
3143
transport_path = 'quack'
3144
repo, client = self.setup_fake_client_and_repository(transport_path)
3146
def stub_ensure_real():
3147
client._calls.append(('_ensure_real',))
3148
repo._real_repository = _StubRealPackRepository(client._calls)
3149
repo._ensure_real = stub_ensure_real
3150
client.add_expected_call(
3151
b'Repository.lock_write', (b'quack/', b''),
3152
b'success', (b'ok', b'a token'))
3153
client.add_expected_call(
3154
b'Repository.start_write_group', (b'quack/', b'a token'),
3155
b'error', (b'UnsuspendableWriteGroup',))
3157
repo.start_write_group()
3158
self.assertEqual(client._calls[-2:], [
3160
('start_write_group',)])
3162
def test_commit_write_group(self):
3163
transport_path = 'quack'
3164
repo, client = self.setup_fake_client_and_repository(transport_path)
3165
client.add_expected_call(
3166
b'Repository.lock_write', (b'quack/', b''),
3167
b'success', (b'ok', b'a token'))
3168
client.add_expected_call(
3169
b'Repository.start_write_group', (b'quack/', b'a token'),
3170
b'success', (b'ok', [b'token1']))
3171
client.add_expected_call(
3172
b'Repository.commit_write_group', (b'quack/',
3173
b'a token', [b'token1']),
3174
b'success', (b'ok',))
3176
repo.start_write_group()
3177
repo.commit_write_group()
3179
def test_abort_write_group(self):
3180
transport_path = 'quack'
3181
repo, client = self.setup_fake_client_and_repository(transport_path)
3182
client.add_expected_call(
3183
b'Repository.lock_write', (b'quack/', b''),
3184
b'success', (b'ok', b'a token'))
3185
client.add_expected_call(
3186
b'Repository.start_write_group', (b'quack/', b'a token'),
3187
b'success', (b'ok', [b'token1']))
3188
client.add_expected_call(
3189
b'Repository.abort_write_group', (b'quack/',
3190
b'a token', [b'token1']),
3191
b'success', (b'ok',))
3193
repo.start_write_group()
3194
repo.abort_write_group(False)
3196
def test_suspend_write_group(self):
3197
transport_path = 'quack'
3198
repo, client = self.setup_fake_client_and_repository(transport_path)
3199
self.assertEqual([], repo.suspend_write_group())
3201
def test_resume_write_group(self):
3202
transport_path = 'quack'
3203
repo, client = self.setup_fake_client_and_repository(transport_path)
3204
client.add_expected_call(
3205
b'Repository.lock_write', (b'quack/', b''),
3206
b'success', (b'ok', b'a token'))
3207
client.add_expected_call(
3208
b'Repository.check_write_group', (b'quack/',
3209
b'a token', [b'token1']),
3210
b'success', (b'ok',))
3212
repo.resume_write_group(['token1'])
2329
3215
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3217
def test_backwards_compat(self):
2332
3218
self.setup_smart_server_with_call_log()
2333
3219
repo = self.make_repository('.')
2334
3220
self.reset_smart_call_log()
2335
verb = 'Repository.set_make_working_trees'
3221
verb = b'Repository.set_make_working_trees'
2336
3222
self.disable_verb(verb)
2337
3223
repo.set_make_working_trees(True)
2338
3224
call_count = len([call for call in self.hpss_calls if
2339
call.call.method == verb])
3225
call.call.method == verb])
2340
3226
self.assertEqual(1, call_count)
2342
3228
def test_current(self):
2343
3229
transport_path = 'quack'
2344
3230
repo, client = self.setup_fake_client_and_repository(transport_path)
2345
3231
client.add_expected_call(
2346
'Repository.set_make_working_trees', ('quack/', 'True'),
3232
b'Repository.set_make_working_trees', (b'quack/', b'True'),
3233
b'success', (b'ok',))
2348
3234
client.add_expected_call(
2349
'Repository.set_make_working_trees', ('quack/', 'False'),
3235
b'Repository.set_make_working_trees', (b'quack/', b'False'),
3236
b'success', (b'ok',))
2351
3237
repo.set_make_working_trees(True)
2352
3238
repo.set_make_working_trees(False)
2419
3332
def setUp(self):
2420
TestRemoteRepository.setUp(self)
2421
self.disable_verb('Repository.insert_stream_1.19')
3333
super(TestRepositoryInsertStream, self).setUp()
3334
self.disable_verb(b'Repository.insert_stream_1.19')
2423
3336
def test_unlocked_repo(self):
2424
3337
transport_path = 'quack'
2425
3338
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3339
client.add_expected_call(
2427
'Repository.insert_stream_1.19', ('quack/', ''),
2428
'unknown', ('Repository.insert_stream_1.19',))
2429
client.add_expected_call(
2430
'Repository.insert_stream', ('quack/', ''),
2432
client.add_expected_call(
2433
'Repository.insert_stream', ('quack/', ''),
3340
b'Repository.insert_stream_1.19', (b'quack/', b''),
3341
b'unknown', (b'Repository.insert_stream_1.19',))
3342
client.add_expected_call(
3343
b'Repository.insert_stream', (b'quack/', b''),
3344
b'success', (b'ok',))
3345
client.add_expected_call(
3346
b'Repository.insert_stream', (b'quack/', b''),
3347
b'success', (b'ok',))
2435
3348
self.checkInsertEmptyStream(repo, client)
2437
3350
def test_locked_repo_with_no_lock_token(self):
2438
3351
transport_path = 'quack'
2439
3352
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3353
client.add_expected_call(
2441
'Repository.lock_write', ('quack/', ''),
2442
'success', ('ok', ''))
2443
client.add_expected_call(
2444
'Repository.insert_stream_1.19', ('quack/', ''),
2445
'unknown', ('Repository.insert_stream_1.19',))
2446
client.add_expected_call(
2447
'Repository.insert_stream', ('quack/', ''),
2449
client.add_expected_call(
2450
'Repository.insert_stream', ('quack/', ''),
3354
b'Repository.lock_write', (b'quack/', b''),
3355
b'success', (b'ok', b''))
3356
client.add_expected_call(
3357
b'Repository.insert_stream_1.19', (b'quack/', b''),
3358
b'unknown', (b'Repository.insert_stream_1.19',))
3359
client.add_expected_call(
3360
b'Repository.insert_stream', (b'quack/', b''),
3361
b'success', (b'ok',))
3362
client.add_expected_call(
3363
b'Repository.insert_stream', (b'quack/', b''),
3364
b'success', (b'ok',))
2452
3365
repo.lock_write()
2453
3366
self.checkInsertEmptyStream(repo, client)
2479
3392
transport_path = 'quack'
2480
3393
repo, client = self.setup_fake_client_and_repository(transport_path)
2481
3394
client.add_expected_call(
2482
'Repository.insert_stream_1.19', ('quack/', ''),
2483
'unknown', ('Repository.insert_stream_1.19',))
2484
client.add_expected_call(
2485
'Repository.insert_stream', ('quack/', ''),
2487
client.add_expected_call(
2488
'Repository.insert_stream', ('quack/', ''),
3395
b'Repository.insert_stream_1.19', (b'quack/', b''),
3396
b'unknown', (b'Repository.insert_stream_1.19',))
3397
client.add_expected_call(
3398
b'Repository.insert_stream', (b'quack/', b''),
3399
b'success', (b'ok',))
3400
client.add_expected_call(
3401
b'Repository.insert_stream', (b'quack/', b''),
3402
b'success', (b'ok',))
2490
3403
# Create a fake real repository for insert_stream to fall back on, so
2491
3404
# that we can directly see the records the RemoteSink passes to the
2493
3407
class FakeRealSink:
2494
3408
def __init__(self):
2495
3409
self.records = []
2496
3411
def insert_stream(self, stream, src_format, resume_tokens):
2497
3412
for substream_kind, substream in stream:
2498
3413
self.records.append(
2499
3414
(substream_kind, [record.key for record in substream]))
2500
return ['fake tokens'], ['fake missing keys']
3415
return [b'fake tokens'], [b'fake missing keys']
2501
3416
fake_real_sink = FakeRealSink()
2502
3418
class FakeRealRepository:
2503
3419
def _get_sink(self):
2504
3420
return fake_real_sink
2505
3422
def is_in_write_group(self):
2507
3425
def refresh_data(self):
2509
3427
repo._real_repository = FakeRealRepository()
2510
3428
sink = repo._get_sink()
2511
fmt = repository.RepositoryFormat.get_default_format()
3429
fmt = repository.format_registry.get_default()
2512
3430
stream = self.make_stream_with_inv_deltas(fmt)
2513
3431
resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3432
# Every record from the first inventory delta should have been sent to
2515
3433
# the VFS sink.
2516
3434
expected_records = [
2517
('inventory-deltas', [('rev2',), ('rev3',)]),
2518
('texts', [('some-rev', 'some-file')])]
3435
('inventory-deltas', [(b'rev2',), (b'rev3',)]),
3436
('texts', [(b'some-rev', b'some-file')])]
2519
3437
self.assertEqual(expected_records, fake_real_sink.records)
2520
3438
# The return values from the real sink's insert_stream are propagated
2521
3439
# back to the original caller.
2522
self.assertEqual(['fake tokens'], resume_tokens)
2523
self.assertEqual(['fake missing keys'], missing_keys)
3440
self.assertEqual([b'fake tokens'], resume_tokens)
3441
self.assertEqual([b'fake missing keys'], missing_keys)
2524
3442
self.assertFinished(client)
2526
3444
def make_stream_with_inv_deltas(self, fmt):
2534
3452
* texts substream: (some-rev, some-file)
2536
3454
# Define a stream using generators so that it isn't rewindable.
2537
inv = inventory.Inventory(revision_id='rev1')
2538
inv.root.revision = 'rev1'
3455
inv = inventory.Inventory(revision_id=b'rev1')
3456
inv.root.revision = b'rev1'
2539
3458
def stream_with_inv_delta():
2540
3459
yield ('inventories', inventories_substream())
2541
3460
yield ('inventory-deltas', inventory_delta_substream())
2542
3461
yield ('texts', [
2543
3462
versionedfile.FulltextContentFactory(
2544
('some-rev', 'some-file'), (), None, 'content')])
3463
(b'some-rev', b'some-file'), (), None, b'content')])
2545
3465
def inventories_substream():
2546
3466
# An empty inventory fulltext. This will be streamed normally.
2547
3467
text = fmt._serializer.write_inventory_to_string(inv)
2548
3468
yield versionedfile.FulltextContentFactory(
2549
('rev1',), (), None, text)
3469
(b'rev1',), (), None, text)
2550
3471
def inventory_delta_substream():
2551
3472
# An inventory delta. This can't be streamed via this verb, so it
2552
3473
# will trigger a fallback to VFS insert_stream.
2553
3474
entry = inv.make_entry(
2554
'directory', 'newdir', inv.root.file_id, 'newdir-id')
2555
entry.revision = 'ghost'
2556
delta = [(None, 'newdir', 'newdir-id', entry)]
3475
'directory', 'newdir', inv.root.file_id, b'newdir-id')
3476
entry.revision = b'ghost'
3477
delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3478
serializer = inventory_delta.InventoryDeltaSerializer(
2558
3479
versioned_root=True, tree_references=False)
2559
lines = serializer.delta_to_lines('rev1', 'rev2', delta)
3480
lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3481
yield versionedfile.ChunkedContentFactory(
2561
('rev2',), (('rev1',)), None, lines)
3482
(b'rev2',), ((b'rev1',)), None, lines)
2562
3483
# Another delta.
2563
lines = serializer.delta_to_lines('rev1', 'rev3', delta)
3484
lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3485
yield versionedfile.ChunkedContentFactory(
2565
('rev3',), (('rev1',)), None, lines)
3486
(b'rev3',), ((b'rev1',)), None, lines)
2566
3487
return stream_with_inv_delta()
2784
3719
def test_NoSuchRevision(self):
2785
3720
branch = self.make_branch('')
2787
3722
translated_error = self.translateTuple(
2788
('NoSuchRevision', revid), branch=branch)
3723
(b'NoSuchRevision', revid), branch=branch)
2789
3724
expected_error = errors.NoSuchRevision(branch, revid)
2790
3725
self.assertEqual(expected_error, translated_error)
2792
3727
def test_nosuchrevision(self):
2793
3728
repository = self.make_repository('')
2795
3730
translated_error = self.translateTuple(
2796
('nosuchrevision', revid), repository=repository)
3731
(b'nosuchrevision', revid), repository=repository)
2797
3732
expected_error = errors.NoSuchRevision(repository, revid)
2798
3733
self.assertEqual(expected_error, translated_error)
2800
3735
def test_nobranch(self):
2801
bzrdir = self.make_bzrdir('')
2802
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3736
bzrdir = self.make_controldir('')
3737
translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3738
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3739
self.assertEqual(expected_error, translated_error)
2806
3741
def test_nobranch_one_arg(self):
2807
bzrdir = self.make_bzrdir('')
3742
bzrdir = self.make_controldir('')
2808
3743
translated_error = self.translateTuple(
2809
('nobranch', 'extra detail'), bzrdir=bzrdir)
3744
(b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3745
expected_error = errors.NotBranchError(
2811
3746
path=bzrdir.root_transport.base,
2812
3747
detail='extra detail')
2813
3748
self.assertEqual(expected_error, translated_error)
3750
def test_norepository(self):
3751
bzrdir = self.make_controldir('')
3752
translated_error = self.translateTuple((b'norepository',),
3754
expected_error = errors.NoRepositoryPresent(bzrdir)
3755
self.assertEqual(expected_error, translated_error)
2815
3757
def test_LockContention(self):
2816
translated_error = self.translateTuple(('LockContention',))
3758
translated_error = self.translateTuple((b'LockContention',))
2817
3759
expected_error = errors.LockContention('(remote lock)')
2818
3760
self.assertEqual(expected_error, translated_error)
2820
3762
def test_UnlockableTransport(self):
2821
bzrdir = self.make_bzrdir('')
3763
bzrdir = self.make_controldir('')
2822
3764
translated_error = self.translateTuple(
2823
('UnlockableTransport',), bzrdir=bzrdir)
3765
(b'UnlockableTransport',), bzrdir=bzrdir)
2824
3766
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3767
self.assertEqual(expected_error, translated_error)
2827
3769
def test_LockFailed(self):
2828
3770
lock = 'str() of a server lock'
2829
3771
why = 'str() of why'
2830
translated_error = self.translateTuple(('LockFailed', lock, why))
3772
translated_error = self.translateTuple(
3773
(b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3774
expected_error = errors.LockFailed(lock, why)
2832
3775
self.assertEqual(expected_error, translated_error)
2834
3777
def test_TokenMismatch(self):
2835
3778
token = 'a lock token'
2836
translated_error = self.translateTuple(('TokenMismatch',), token=token)
3779
translated_error = self.translateTuple(
3780
(b'TokenMismatch',), token=token)
2837
3781
expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3782
self.assertEqual(expected_error, translated_error)
2841
3785
branch = self.make_branch('a')
2842
3786
other_branch = self.make_branch('b')
2843
3787
translated_error = self.translateTuple(
2844
('Diverged',), branch=branch, other_branch=other_branch)
3788
(b'Diverged',), branch=branch, other_branch=other_branch)
2845
3789
expected_error = errors.DivergedBranches(branch, other_branch)
2846
3790
self.assertEqual(expected_error, translated_error)
3792
def test_NotStacked(self):
3793
branch = self.make_branch('')
3794
translated_error = self.translateTuple((b'NotStacked',), branch=branch)
3795
expected_error = errors.NotStacked(branch)
3796
self.assertEqual(expected_error, translated_error)
2848
3798
def test_ReadError_no_args(self):
2849
3799
path = 'a path'
2850
translated_error = self.translateTuple(('ReadError',), path=path)
3800
translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3801
expected_error = errors.ReadError(path)
2852
3802
self.assertEqual(expected_error, translated_error)
2854
3804
def test_ReadError(self):
2855
3805
path = 'a path'
2856
translated_error = self.translateTuple(('ReadError', path))
3806
translated_error = self.translateTuple(
3807
(b'ReadError', path.encode('utf-8')))
2857
3808
expected_error = errors.ReadError(path)
2858
3809
self.assertEqual(expected_error, translated_error)
2860
3811
def test_IncompatibleRepositories(self):
2861
translated_error = self.translateTuple(('IncompatibleRepositories',
2862
"repo1", "repo2", "details here"))
3812
translated_error = self.translateTuple((b'IncompatibleRepositories',
3813
b"repo1", b"repo2", b"details here"))
2863
3814
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
3816
self.assertEqual(expected_error, translated_error)
3818
def test_GhostRevisionsHaveNoRevno(self):
3819
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3820
b"revid1", b"revid2"))
3821
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
2865
3822
self.assertEqual(expected_error, translated_error)
2867
3824
def test_PermissionDenied_no_args(self):
2868
3825
path = 'a path'
2869
translated_error = self.translateTuple(('PermissionDenied',), path=path)
3826
translated_error = self.translateTuple((b'PermissionDenied',),
2870
3828
expected_error = errors.PermissionDenied(path)
2871
3829
self.assertEqual(expected_error, translated_error)
2873
3831
def test_PermissionDenied_one_arg(self):
2874
3832
path = 'a path'
2875
translated_error = self.translateTuple(('PermissionDenied', path))
3833
translated_error = self.translateTuple(
3834
(b'PermissionDenied', path.encode('utf-8')))
2876
3835
expected_error = errors.PermissionDenied(path)
2877
3836
self.assertEqual(expected_error, translated_error)
3143
4143
def test_copy_content_into_avoids_revision_history(self):
3144
4144
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4145
builder = self.make_branch_builder('remote')
4146
builder.build_commit(message="Commit.")
3147
4147
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4148
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4149
local.repository.fetch(remote_branch.repository)
3150
4150
self.hpss_calls = []
3151
4151
remote_branch.copy_content_into(local)
3152
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4152
self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
4154
def test_fetch_everything_needs_just_one_call(self):
4155
local = self.make_branch('local')
4156
builder = self.make_branch_builder('remote')
4157
builder.build_commit(message="Commit.")
4158
remote_branch_url = self.smart_server.get_url() + 'remote'
4159
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4160
self.hpss_calls = []
4161
local.repository.fetch(
4162
remote_branch.repository,
4163
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4164
self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
4166
def override_verb(self, verb_name, verb):
4167
request_handlers = request.request_handlers
4168
orig_verb = request_handlers.get(verb_name)
4169
orig_info = request_handlers.get_info(verb_name)
4170
request_handlers.register(verb_name, verb, override_existing=True)
4171
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4172
override_existing=True, info=orig_info)
4174
def test_fetch_everything_backwards_compat(self):
4175
"""Can fetch with EverythingResult even with pre 2.4 servers.
4177
Pre-2.4 do not support 'everything' searches with the
4178
Repository.get_stream_1.19 verb.
4182
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4183
"""A version of the Repository.get_stream_1.19 verb patched to
4184
reject 'everything' searches the way 2.3 and earlier do.
4187
def recreate_search(self, repository, search_bytes,
4188
discard_excess=False):
4189
verb_log.append(search_bytes.split(b'\n', 1)[0])
4190
if search_bytes == b'everything':
4192
request.FailedSmartServerResponse((b'BadSearch',)))
4193
return super(OldGetStreamVerb,
4194
self).recreate_search(repository, search_bytes,
4195
discard_excess=discard_excess)
4196
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4197
local = self.make_branch('local')
4198
builder = self.make_branch_builder('remote')
4199
builder.build_commit(message="Commit.")
4200
remote_branch_url = self.smart_server.get_url() + 'remote'
4201
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4202
self.hpss_calls = []
4203
local.repository.fetch(
4204
remote_branch.repository,
4205
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4206
# make sure the overridden verb was used
4207
self.assertLength(1, verb_log)
4208
# more than one HPSS call is needed, but because it's a VFS callback
4209
# its hard to predict exactly how many.
4210
self.assertTrue(len(self.hpss_calls) > 1)
4213
class TestUpdateBoundBranchWithModifiedBoundLocation(
4214
tests.TestCaseWithTransport):
4215
"""Ensure correct handling of bound_location modifications.
4217
This is tested against a smart server as http://pad.lv/786980 was about a
4218
ReadOnlyError (write attempt during a read-only transaction) which can only
4219
happen in this context.
4223
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4224
self.transport_server = test_server.SmartTCPServer_for_testing
4226
def make_master_and_checkout(self, master_name, checkout_name):
4227
# Create the master branch and its associated checkout
4228
self.master = self.make_branch_and_tree(master_name)
4229
self.checkout = self.master.branch.create_checkout(checkout_name)
4230
# Modify the master branch so there is something to update
4231
self.master.commit('add stuff')
4232
self.last_revid = self.master.commit('even more stuff')
4233
self.bound_location = self.checkout.branch.get_bound_location()
4235
def assertUpdateSucceeds(self, new_location):
4236
self.checkout.branch.set_bound_location(new_location)
4237
self.checkout.update()
4238
self.assertEqual(self.last_revid, self.checkout.last_revision())
4240
def test_without_final_slash(self):
4241
self.make_master_and_checkout('master', 'checkout')
4242
# For unclear reasons some users have a bound_location without a final
4243
# '/', simulate that by forcing such a value
4244
self.assertEndsWith(self.bound_location, '/')
4245
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4247
def test_plus_sign(self):
4248
self.make_master_and_checkout('+master', 'checkout')
4249
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4251
def test_tilda(self):
4252
# Embed ~ in the middle of the path just to avoid any $HOME
4254
self.make_master_and_checkout('mas~ter', 'checkout')
4255
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4258
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4260
def test_no_context(self):
4261
class OutOfCoffee(errors.BzrError):
4262
"""A dummy exception for testing."""
4264
def __init__(self, urgency):
4265
self.urgency = urgency
4266
remote.no_context_error_translators.register(b"OutOfCoffee",
4267
lambda err: OutOfCoffee(err.error_args[0]))
4268
transport = MemoryTransport()
4269
client = FakeClient(transport.base)
4270
client.add_expected_call(
4271
b'Branch.get_stacked_on_url', (b'quack/',),
4272
b'error', (b'NotStacked',))
4273
client.add_expected_call(
4274
b'Branch.last_revision_info',
4276
b'error', (b'OutOfCoffee', b'low'))
4277
transport.mkdir('quack')
4278
transport = transport.clone('quack')
4279
branch = self.make_remote_branch(transport, client)
4280
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4281
self.assertFinished(client)
4283
def test_with_context(self):
4284
class OutOfTea(errors.BzrError):
4285
def __init__(self, branch, urgency):
4286
self.branch = branch
4287
self.urgency = urgency
4288
remote.error_translators.register(b"OutOfTea",
4289
lambda err, find, path: OutOfTea(
4290
err.error_args[0].decode(
4293
transport = MemoryTransport()
4294
client = FakeClient(transport.base)
4295
client.add_expected_call(
4296
b'Branch.get_stacked_on_url', (b'quack/',),
4297
b'error', (b'NotStacked',))
4298
client.add_expected_call(
4299
b'Branch.last_revision_info',
4301
b'error', (b'OutOfTea', b'low'))
4302
transport.mkdir('quack')
4303
transport = transport.clone('quack')
4304
branch = self.make_remote_branch(transport, client)
4305
self.assertRaises(OutOfTea, branch.last_revision_info)
4306
self.assertFinished(client)
4309
class TestRepositoryPack(TestRemoteRepository):
4311
def test_pack(self):
4312
transport_path = 'quack'
4313
repo, client = self.setup_fake_client_and_repository(transport_path)
4314
client.add_expected_call(
4315
b'Repository.lock_write', (b'quack/', b''),
4316
b'success', (b'ok', b'token'))
4317
client.add_expected_call(
4318
b'Repository.pack', (b'quack/', b'token', b'False'),
4319
b'success', (b'ok',), )
4320
client.add_expected_call(
4321
b'Repository.unlock', (b'quack/', b'token'),
4322
b'success', (b'ok', ))
4325
def test_pack_with_hint(self):
4326
transport_path = 'quack'
4327
repo, client = self.setup_fake_client_and_repository(transport_path)
4328
client.add_expected_call(
4329
b'Repository.lock_write', (b'quack/', b''),
4330
b'success', (b'ok', b'token'))
4331
client.add_expected_call(
4332
b'Repository.pack', (b'quack/', b'token', b'False'),
4333
b'success', (b'ok',), )
4334
client.add_expected_call(
4335
b'Repository.unlock', (b'quack/', b'token', b'False'),
4336
b'success', (b'ok', ))
4337
repo.pack(['hinta', 'hintb'])
4340
class TestRepositoryIterInventories(TestRemoteRepository):
4341
"""Test Repository.iter_inventories."""
4343
def _serialize_inv_delta(self, old_name, new_name, delta):
4344
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4345
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4347
def test_single_empty(self):
4348
transport_path = 'quack'
4349
repo, client = self.setup_fake_client_and_repository(transport_path)
4350
fmt = controldir.format_registry.get('2a')().repository_format
4352
stream = [('inventory-deltas', [
4353
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4354
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4355
client.add_expected_call(
4356
b'VersionedFileRepository.get_inventories', (
4357
b'quack/', b'unordered'),
4358
b'success', (b'ok', ),
4359
_stream_to_byte_stream(stream, fmt))
4360
ret = list(repo.iter_inventories([b"somerevid"]))
4361
self.assertLength(1, ret)
4363
self.assertEqual(b"somerevid", inv.revision_id)
4365
def test_empty(self):
4366
transport_path = 'quack'
4367
repo, client = self.setup_fake_client_and_repository(transport_path)
4368
ret = list(repo.iter_inventories([]))
4369
self.assertEqual(ret, [])
4371
def test_missing(self):
4372
transport_path = 'quack'
4373
repo, client = self.setup_fake_client_and_repository(transport_path)
4374
client.add_expected_call(
4375
b'VersionedFileRepository.get_inventories', (
4376
b'quack/', b'unordered'),
4377
b'success', (b'ok', ), iter([]))
4378
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4382
class TestRepositoryRevisionTreeArchive(TestRemoteRepository):
4383
"""Test Repository.iter_inventories."""
4385
def _serialize_inv_delta(self, old_name, new_name, delta):
4386
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4387
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4389
def test_simple(self):
4390
transport_path = 'quack'
4391
repo, client = self.setup_fake_client_and_repository(transport_path)
4392
fmt = controldir.format_registry.get('2a')().repository_format
4394
stream = [('inventory-deltas', [
4395
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4396
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4397
client.add_expected_call(
4398
b'VersionedFileRepository.get_inventories', (
4399
b'quack/', b'unordered'),
4400
b'success', (b'ok', ),
4401
_stream_to_byte_stream(stream, fmt))
4403
with tarfile.open(mode='w', fileobj=f) as tf:
4404
info = tarfile.TarInfo('somefile')
4406
contents = b'some data'
4407
info.type = tarfile.REGTYPE
4409
info.size = len(contents)
4410
tf.addfile(info, BytesIO(contents))
4411
client.add_expected_call(
4412
b'Repository.revision_archive', (b'quack/',
4413
b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4414
b'success', (b'ok', ),
4416
tree = repo.revision_tree(b'somerevid')
4417
self.assertEqual(f.getvalue(), b''.join(
4418
tree.archive('tar', 'foo.tar')))
4421
class TestRepositoryAnnotate(TestRemoteRepository):
4422
"""Test RemoteRevisionTree.annotate.."""
4424
def _serialize_inv_delta(self, old_name, new_name, delta):
4425
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4426
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4428
def test_simple(self):
4429
transport_path = 'quack'
4430
repo, client = self.setup_fake_client_and_repository(transport_path)
4431
fmt = controldir.format_registry.get('2a')().repository_format
4434
('inventory-deltas', [
4435
versionedfile.FulltextContentFactory(
4436
b'somerevid', None, None,
4437
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4438
client.add_expected_call(
4439
b'VersionedFileRepository.get_inventories', (
4440
b'quack/', b'unordered'),
4441
b'success', (b'ok', ),
4442
_stream_to_byte_stream(stream, fmt))
4443
client.add_expected_call(
4444
b'Repository.annotate_file_revision',
4445
(b'quack/', b'somerevid', b'filename', b'', b'current:'),
4446
b'success', (b'ok', ),
4447
bencode.bencode([[b'baserevid', b'line 1\n'],
4448
[b'somerevid', b'line2\n']]))
4449
tree = repo.revision_tree(b'somerevid')
4451
(b'baserevid', b'line 1\n'),
4452
(b'somerevid', b'line2\n')],
4453
list(tree.annotate_iter('filename')))