53
64
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,
66
from ..bzr import groupcompress_repo, knitpack_repo
67
from ..revision import (
71
from ..sixish import (
75
from ..bzr.smart import medium, request
76
from ..bzr.smart.client import _SmartClient
77
from ..bzr.smart.repository import (
78
SmartServerRepositoryGetParentMap,
79
SmartServerRepositoryGetStream_1_19,
80
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
85
from .scenarios import load_tests_apply_scenarios
86
from ..transport.memory import MemoryTransport
87
from ..transport.remote import (
70
89
RemoteSSHTransport,
71
90
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 = [
94
load_tests = load_tests_apply_scenarios
97
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
101
{'transport_server': 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):
103
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
107
super(BasicRemoteObjectTests, self).setUp()
89
108
self.transport = self.get_transport()
90
109
# make a branch that can be opened over the smart transport
91
110
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
111
self.addCleanup(self.transport.disconnect)
97
113
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
114
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
115
self.assertIsInstance(b, BzrDir)
101
117
def test_open_remote_branch(self):
102
118
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
119
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
120
branch = b.open_branch()
105
121
self.assertIsInstance(branch, Branch)
480
489
self.assertEqual(None, result._branch_format)
481
490
self.assertFinished(client)
492
def test_unknown(self):
493
transport = self.get_transport('quack')
494
referenced = self.make_branch('referenced')
495
expected = referenced.controldir.cloning_metadir()
496
client = FakeClient(transport.base)
497
client.add_expected_call(
498
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
499
b'success', (b'unknown', b'unknown', (b'branch', b''))),
500
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
502
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
505
class TestBzrDirCheckoutMetaDir(TestRemote):
507
def test__get_checkout_format(self):
508
transport = MemoryTransport()
509
client = FakeClient(transport.base)
510
reference_bzrdir_format = controldir.format_registry.get('default')()
511
control_name = reference_bzrdir_format.network_name()
512
client.add_expected_call(
513
b'BzrDir.checkout_metadir', (b'quack/', ),
514
b'success', (control_name, b'', b''))
515
transport.mkdir('quack')
516
transport = transport.clone('quack')
517
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
519
result = a_controldir.checkout_metadir()
520
# We should have got a reference control dir with default branch and
521
# repository formats.
522
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
523
self.assertEqual(None, result._repository_format)
524
self.assertEqual(None, result._branch_format)
525
self.assertFinished(client)
527
def test_unknown_format(self):
528
transport = MemoryTransport()
529
client = FakeClient(transport.base)
530
client.add_expected_call(
531
b'BzrDir.checkout_metadir', (b'quack/',),
532
b'success', (b'dontknow', b'', b''))
533
transport.mkdir('quack')
534
transport = transport.clone('quack')
535
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
537
self.assertRaises(errors.UnknownFormatError,
538
a_controldir.checkout_metadir)
539
self.assertFinished(client)
542
class TestBzrDirGetBranches(TestRemote):
544
def test_get_branches(self):
545
transport = MemoryTransport()
546
client = FakeClient(transport.base)
547
reference_bzrdir_format = controldir.format_registry.get('default')()
548
branch_name = reference_bzrdir_format.get_branch_format().network_name()
549
client.add_success_response_with_body(
551
b"foo": (b"branch", branch_name),
552
b"": (b"branch", branch_name)}), b"success")
553
client.add_success_response(
554
b'ok', b'', b'no', b'no', b'no',
555
reference_bzrdir_format.repository_format.network_name())
556
client.add_error_response(b'NotStacked')
557
client.add_success_response(
558
b'ok', b'', b'no', b'no', b'no',
559
reference_bzrdir_format.repository_format.network_name())
560
client.add_error_response(b'NotStacked')
561
transport.mkdir('quack')
562
transport = transport.clone('quack')
563
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
565
result = a_controldir.get_branches()
566
self.assertEqual({b"", b"foo"}, set(result.keys()))
568
[('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
569
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
570
('call', b'Branch.get_stacked_on_url', (b'quack/', )),
571
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
572
('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
576
class TestBzrDirDestroyBranch(TestRemote):
578
def test_destroy_default(self):
579
transport = self.get_transport('quack')
580
referenced = self.make_branch('referenced')
581
client = FakeClient(transport.base)
582
client.add_expected_call(
583
b'BzrDir.destroy_branch', (b'quack/', ),
584
b'success', (b'ok',)),
585
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
587
a_controldir.destroy_branch()
588
self.assertFinished(client)
591
class TestBzrDirHasWorkingTree(TestRemote):
593
def test_has_workingtree(self):
594
transport = self.get_transport('quack')
595
client = FakeClient(transport.base)
596
client.add_expected_call(
597
b'BzrDir.has_workingtree', (b'quack/',),
598
b'success', (b'yes',)),
599
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
601
self.assertTrue(a_controldir.has_workingtree())
602
self.assertFinished(client)
604
def test_no_workingtree(self):
605
transport = self.get_transport('quack')
606
client = FakeClient(transport.base)
607
client.add_expected_call(
608
b'BzrDir.has_workingtree', (b'quack/',),
609
b'success', (b'no',)),
610
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
612
self.assertFalse(a_controldir.has_workingtree())
613
self.assertFinished(client)
616
class TestBzrDirDestroyRepository(TestRemote):
618
def test_destroy_repository(self):
619
transport = self.get_transport('quack')
620
client = FakeClient(transport.base)
621
client.add_expected_call(
622
b'BzrDir.destroy_repository', (b'quack/',),
623
b'success', (b'ok',)),
624
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
626
a_controldir.destroy_repository()
627
self.assertFinished(client)
484
630
class TestBzrDirOpen(TestRemote):
577
723
transport = transport.clone('quack')
578
724
client = FakeClient(transport.base)
579
725
client.add_expected_call(
580
'BzrDir.open_branchV3', ('quack/',),
581
'success', ('branch', branch_network_name))
582
client.add_expected_call(
583
'BzrDir.find_repositoryV3', ('quack/',),
584
'success', ('ok', '', 'no', 'no', 'no', network_name))
585
client.add_expected_call(
586
'Branch.get_stacked_on_url', ('quack/',),
587
'error', ('NotStacked',))
588
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
726
b'BzrDir.open_branchV3', (b'quack/',),
727
b'success', (b'branch', branch_network_name))
728
client.add_expected_call(
729
b'BzrDir.find_repositoryV3', (b'quack/',),
730
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
731
client.add_expected_call(
732
b'Branch.get_stacked_on_url', (b'quack/',),
733
b'error', (b'NotStacked',))
734
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
590
736
result = bzrdir.open_branch()
591
737
self.assertIsInstance(result, RemoteBranch)
592
self.assertEqual(bzrdir, result.bzrdir)
738
self.assertEqual(bzrdir, result.controldir)
593
739
self.assertFinished(client)
595
741
def test_branch_missing(self):
632
778
network_name = reference_format.network_name()
633
779
branch_network_name = self.get_branch_format().network_name()
634
780
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(),
781
b'BzrDir.open_branchV3', (b'~hello/',),
782
b'success', (b'branch', branch_network_name))
783
client.add_expected_call(
784
b'BzrDir.find_repositoryV3', (b'~hello/',),
785
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
786
client.add_expected_call(
787
b'Branch.get_stacked_on_url', (b'~hello/',),
788
b'error', (b'NotStacked',))
789
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
645
791
result = bzrdir.open_branch()
646
792
self.assertFinished(client)
648
def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
794
def check_open_repository(self, rich_root, subtrees, external_lookup=b'no'):
649
795
reference_format = self.get_repo_format()
650
796
network_name = reference_format.network_name()
651
797
transport = MemoryTransport()
652
798
transport.mkdir('quack')
653
799
transport = transport.clone('quack')
655
rich_response = 'yes'
801
rich_response = b'yes'
803
rich_response = b'no'
659
subtree_response = 'yes'
805
subtree_response = b'yes'
661
subtree_response = 'no'
807
subtree_response = b'no'
662
808
client = FakeClient(transport.base)
663
809
client.add_success_response(
664
'ok', '', rich_response, subtree_response, external_lookup,
810
b'ok', b'', rich_response, subtree_response, external_lookup,
666
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
812
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
814
result = bzrdir.open_repository()
669
815
self.assertEqual(
670
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
816
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
672
818
self.assertIsInstance(result, RemoteRepository)
673
self.assertEqual(bzrdir, result.bzrdir)
819
self.assertEqual(bzrdir, result.controldir)
674
820
self.assertEqual(rich_root, result._format.rich_root_data)
675
821
self.assertEqual(subtrees, result._format.supports_tree_reference)
706
852
transport = transport.clone('quack')
707
853
self.make_repository('quack')
708
854
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()
855
reference_bzrdir_format = controldir.format_registry.get('default')()
856
reference_format = reference_bzrdir_format.get_branch_format()
857
network_name = reference_format.network_name()
858
reference_repo_fmt = reference_bzrdir_format.repository_format
859
reference_repo_name = reference_repo_fmt.network_name()
860
client.add_expected_call(
861
b'BzrDir.create_branch', (b'quack/', network_name),
862
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
863
reference_repo_name))
864
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
866
branch = a_controldir.create_branch()
867
# We should have got a remote branch
868
self.assertIsInstance(branch, remote.RemoteBranch)
869
# its format should have the settings from the response
870
format = branch._format
871
self.assertEqual(network_name, format.network_name())
873
def test_already_open_repo_and_reused_medium(self):
874
"""Bug 726584: create_branch(..., repository=repo) should work
875
regardless of what the smart medium's base URL is.
877
self.transport_server = test_server.SmartTCPServer_for_testing
878
transport = self.get_transport('.')
879
repo = self.make_repository('quack')
880
# Client's medium rooted a transport root (not at the bzrdir)
881
client = FakeClient(transport.base)
882
transport = transport.clone('quack')
883
reference_bzrdir_format = controldir.format_registry.get('default')()
884
reference_format = reference_bzrdir_format.get_branch_format()
885
network_name = reference_format.network_name()
886
reference_repo_fmt = reference_bzrdir_format.repository_format
887
reference_repo_name = reference_repo_fmt.network_name()
888
client.add_expected_call(
889
b'BzrDir.create_branch', (b'extra/quack/', network_name),
890
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
891
reference_repo_name))
892
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
894
branch = a_controldir.create_branch(repository=repo)
721
895
# We should have got a remote branch
722
896
self.assertIsInstance(branch, remote.RemoteBranch)
723
897
# its format should have the settings from the response
730
904
def test_backwards_compat(self):
731
905
self.setup_smart_server_with_call_log()
732
bzrdir = self.make_bzrdir('.')
906
bzrdir = self.make_controldir('.')
733
907
self.reset_smart_call_log()
734
self.disable_verb('BzrDir.create_repository')
908
self.disable_verb(b'BzrDir.create_repository')
735
909
repo = bzrdir.create_repository()
736
910
create_repo_call_count = len([call for call in self.hpss_calls if
737
call.call.method == 'BzrDir.create_repository'])
911
call.call.method == b'BzrDir.create_repository'])
738
912
self.assertEqual(1, create_repo_call_count)
740
914
def test_current_server(self):
741
915
transport = self.get_transport('.')
742
916
transport = transport.clone('quack')
743
self.make_bzrdir('quack')
917
self.make_controldir('quack')
744
918
client = FakeClient(transport.base)
745
reference_bzrdir_format = bzrdir.format_registry.get('default')()
919
reference_bzrdir_format = controldir.format_registry.get('default')()
746
920
reference_format = reference_bzrdir_format.repository_format
747
921
network_name = reference_format.network_name()
748
922
client.add_expected_call(
749
'BzrDir.create_repository', ('quack/',
750
'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
752
'success', ('ok', 'yes', 'yes', 'yes', network_name))
753
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
923
b'BzrDir.create_repository', (b'quack/',
924
b'Bazaar repository format 2a (needs bzr 1.16 or later)\n',
926
b'success', (b'ok', b'yes', b'yes', b'yes', network_name))
927
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
755
repo = a_bzrdir.create_repository()
929
repo = a_controldir.create_repository()
756
930
# We should have got a remote repository
757
931
self.assertIsInstance(repo, remote.RemoteRepository)
758
932
# its format should have the settings from the response
772
946
server_url = 'bzr://example.com/'
773
947
self.permit_url(server_url)
774
948
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')
949
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
950
client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
951
client.add_success_response(b'ok', b'', b'no', b'no')
778
952
# A real repository instance will be created to determine the network
780
954
client.add_success_response_with_body(
781
"Bazaar-NG meta directory, format 1\n", 'ok')
955
b"Bazaar-NG meta directory, format 1\n", b'ok')
956
client.add_success_response(b'stat', b'0', b'65535')
782
957
client.add_success_response_with_body(
783
reference_format.get_format_string(), 'ok')
958
reference_format.get_format_string(), b'ok')
784
959
# PackRepository wants to do a stat
785
client.add_success_response('stat', '0', '65535')
960
client.add_success_response(b'stat', b'0', b'65535')
786
961
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
788
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
963
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
790
965
repo = bzrdir.open_repository()
791
966
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',)),
967
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
968
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
969
('call', b'BzrDir.find_repository', (b'quack/',)),
970
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
971
('call', b'stat', (b'/quack/.bzr',)),
972
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
973
('call', b'stat', (b'/quack/.bzr/repository',)),
800
976
self.assertEqual(network_name, repo._format.network_name())
806
982
server_url = 'bzr://example.com/'
807
983
self.permit_url(server_url)
808
984
client = FakeClient(server_url)
809
client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
client.add_success_response('ok', '', 'no', 'no', 'no')
985
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
986
client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
987
# A real repository instance will be created to determine the network
813
989
client.add_success_response_with_body(
814
"Bazaar-NG meta directory, format 1\n", 'ok')
990
b"Bazaar-NG meta directory, format 1\n", b'ok')
991
client.add_success_response(b'stat', b'0', b'65535')
815
992
client.add_success_response_with_body(
816
reference_format.get_format_string(), 'ok')
993
reference_format.get_format_string(), b'ok')
817
994
# PackRepository wants to do a stat
818
client.add_success_response('stat', '0', '65535')
995
client.add_success_response(b'stat', b'0', b'65535')
819
996
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
821
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
998
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
823
1000
repo = bzrdir.open_repository()
824
1001
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',)),
1002
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1003
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1004
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1005
('call', b'stat', (b'/quack/.bzr',)),
1006
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
1007
('call', b'stat', (b'/quack/.bzr/repository',)),
832
1010
self.assertEqual(network_name, repo._format.network_name())
967
1145
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1148
class TestBranchBreakLock(RemoteBranchTestCase):
1150
def test_break_lock(self):
1151
transport_path = 'quack'
1152
transport = MemoryTransport()
1153
client = FakeClient(transport.base)
1154
client.add_expected_call(
1155
b'Branch.get_stacked_on_url', (b'quack/',),
1156
b'error', (b'NotStacked',))
1157
client.add_expected_call(
1158
b'Branch.break_lock', (b'quack/',),
1159
b'success', (b'ok',))
1160
transport.mkdir('quack')
1161
transport = transport.clone('quack')
1162
branch = self.make_remote_branch(transport, client)
1164
self.assertFinished(client)
1167
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1169
def test_get_physical_lock_status_yes(self):
1170
transport = MemoryTransport()
1171
client = FakeClient(transport.base)
1172
client.add_expected_call(
1173
b'Branch.get_stacked_on_url', (b'quack/',),
1174
b'error', (b'NotStacked',))
1175
client.add_expected_call(
1176
b'Branch.get_physical_lock_status', (b'quack/',),
1177
b'success', (b'yes',))
1178
transport.mkdir('quack')
1179
transport = transport.clone('quack')
1180
branch = self.make_remote_branch(transport, client)
1181
result = branch.get_physical_lock_status()
1182
self.assertFinished(client)
1183
self.assertEqual(True, result)
1185
def test_get_physical_lock_status_no(self):
1186
transport = MemoryTransport()
1187
client = FakeClient(transport.base)
1188
client.add_expected_call(
1189
b'Branch.get_stacked_on_url', (b'quack/',),
1190
b'error', (b'NotStacked',))
1191
client.add_expected_call(
1192
b'Branch.get_physical_lock_status', (b'quack/',),
1193
b'success', (b'no',))
1194
transport.mkdir('quack')
1195
transport = transport.clone('quack')
1196
branch = self.make_remote_branch(transport, client)
1197
result = branch.get_physical_lock_status()
1198
self.assertFinished(client)
1199
self.assertEqual(False, result)
970
1202
class TestBranchGetParent(RemoteBranchTestCase):
972
1204
def test_no_parent(self):
1101
1333
transport = MemoryTransport()
1102
1334
client = FakeClient(transport.base)
1103
1335
client.add_expected_call(
1104
'Branch.get_stacked_on_url', ('quack/',),
1105
'error', ('NotStacked',))
1336
b'Branch.get_stacked_on_url', (b'quack/',),
1337
b'error', (b'NotStacked',))
1106
1338
client.add_expected_call(
1107
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1339
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1109
1341
transport.mkdir('quack')
1110
1342
transport = transport.clone('quack')
1111
1343
branch = self.make_remote_branch(transport, client)
1112
1344
self.lock_remote_branch(branch)
1113
branch._set_tags_bytes('tags bytes')
1345
branch._set_tags_bytes(b'tags bytes')
1114
1346
self.assertFinished(client)
1115
self.assertEqual('tags bytes', client._calls[-1][-1])
1347
self.assertEqual(b'tags bytes', client._calls[-1][-1])
1117
1349
def test_backwards_compatible(self):
1118
1350
transport = MemoryTransport()
1119
1351
client = FakeClient(transport.base)
1120
1352
client.add_expected_call(
1121
'Branch.get_stacked_on_url', ('quack/',),
1122
'error', ('NotStacked',))
1353
b'Branch.get_stacked_on_url', (b'quack/',),
1354
b'error', (b'NotStacked',))
1123
1355
client.add_expected_call(
1124
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1125
'unknown', ('Branch.set_tags_bytes',))
1356
b'Branch.set_tags_bytes', (b'quack/', b'branch token', b'repo token'),
1357
b'unknown', (b'Branch.set_tags_bytes',))
1126
1358
transport.mkdir('quack')
1127
1359
transport = transport.clone('quack')
1128
1360
branch = self.make_remote_branch(transport, client)
1134
1366
self.calls.append(('set_tags_bytes', bytes))
1135
1367
real_branch = StubRealBranch()
1136
1368
branch._real_branch = real_branch
1137
branch._set_tags_bytes('tags bytes')
1369
branch._set_tags_bytes(b'tags bytes')
1138
1370
# 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)
1372
branch._set_tags_bytes(b'tags bytes')
1373
self.assertFinished(client)
1375
[('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
1378
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1380
def test_uses_last_revision_info_and_tags_by_default(self):
1381
transport = MemoryTransport()
1382
client = FakeClient(transport.base)
1383
client.add_expected_call(
1384
b'Branch.get_stacked_on_url', (b'quack/',),
1385
b'error', (b'NotStacked',))
1386
client.add_expected_call(
1387
b'Branch.last_revision_info', (b'quack/',),
1388
b'success', (b'ok', b'1', b'rev-tip'))
1389
client.add_expected_call(
1390
b'Branch.get_config_file', (b'quack/',),
1391
b'success', (b'ok',), '')
1392
transport.mkdir('quack')
1393
transport = transport.clone('quack')
1394
branch = self.make_remote_branch(transport, client)
1395
result = branch.heads_to_fetch()
1396
self.assertFinished(client)
1397
self.assertEqual(({b'rev-tip'}, set()), result)
1399
def test_uses_last_revision_info_and_tags_when_set(self):
1400
transport = MemoryTransport()
1401
client = FakeClient(transport.base)
1402
client.add_expected_call(
1403
b'Branch.get_stacked_on_url', (b'quack/',),
1404
b'error', (b'NotStacked',))
1405
client.add_expected_call(
1406
b'Branch.last_revision_info', (b'quack/',),
1407
b'success', (b'ok', b'1', b'rev-tip'))
1408
client.add_expected_call(
1409
b'Branch.get_config_file', (b'quack/',),
1410
b'success', (b'ok',), b'branch.fetch_tags = True')
1411
# XXX: this will break if the default format's serialization of tags
1412
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1413
client.add_expected_call(
1414
b'Branch.get_tags_bytes', (b'quack/',),
1415
b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
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)
1422
({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
1424
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1425
transport = MemoryTransport()
1426
client = FakeClient(transport.base)
1427
client.add_expected_call(
1428
b'Branch.get_stacked_on_url', (b'quack/',),
1429
b'error', (b'NotStacked',))
1430
client.add_expected_call(
1431
b'Branch.heads_to_fetch', (b'quack/',),
1432
b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
1433
transport.mkdir('quack')
1434
transport = transport.clone('quack')
1435
branch = self.make_remote_branch(transport, client)
1436
branch._format._use_default_local_heads_to_fetch = lambda: False
1437
result = branch.heads_to_fetch()
1438
self.assertFinished(client)
1439
self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
1441
def make_branch_with_tags(self):
1442
self.setup_smart_server_with_call_log()
1443
# Make a branch with a single revision.
1444
builder = self.make_branch_builder('foo')
1445
builder.start_series()
1446
builder.build_snapshot(None, [
1447
('add', ('', b'root-id', 'directory', ''))],
1449
builder.finish_series()
1450
branch = builder.get_branch()
1451
# Add two tags to that branch
1452
branch.tags.set_tag('tag-1', b'rev-1')
1453
branch.tags.set_tag('tag-2', b'rev-2')
1456
def test_backwards_compatible(self):
1457
br = self.make_branch_with_tags()
1458
br.get_config_stack().set('branch.fetch_tags', True)
1459
self.addCleanup(br.lock_read().unlock)
1460
# Disable the heads_to_fetch verb
1461
verb = b'Branch.heads_to_fetch'
1462
self.disable_verb(verb)
1463
self.reset_smart_call_log()
1464
result = br.heads_to_fetch()
1465
self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
1467
[b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
1468
[call.call.method for call in self.hpss_calls])
1470
def test_backwards_compatible_no_tags(self):
1471
br = self.make_branch_with_tags()
1472
br.get_config_stack().set('branch.fetch_tags', False)
1473
self.addCleanup(br.lock_read().unlock)
1474
# Disable the heads_to_fetch verb
1475
verb = b'Branch.heads_to_fetch'
1476
self.disable_verb(verb)
1477
self.reset_smart_call_log()
1478
result = br.heads_to_fetch()
1479
self.assertEqual(({b'tip'}, set()), result)
1481
[b'Branch.last_revision_info'],
1482
[call.call.method for call in self.hpss_calls])
1146
1485
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1220
1559
client = FakeClient(self.get_url())
1221
1560
branch_network_name = self.get_branch_format().network_name()
1222
1561
client.add_expected_call(
1223
'BzrDir.open_branchV3', ('stacked/',),
1224
'success', ('branch', branch_network_name))
1562
b'BzrDir.open_branchV3', (b'stacked/',),
1563
b'success', (b'branch', branch_network_name))
1225
1564
client.add_expected_call(
1226
'BzrDir.find_repositoryV3', ('stacked/',),
1227
'success', ('ok', '', 'no', 'no', 'yes',
1565
b'BzrDir.find_repositoryV3', (b'stacked/',),
1566
b'success', (b'ok', b'', b'no', b'no', b'yes',
1228
1567
stacked_branch.repository._format.network_name()))
1229
1568
# called twice, once from constructor and then again by us
1230
1569
client.add_expected_call(
1231
'Branch.get_stacked_on_url', ('stacked/',),
1232
'unknown', ('Branch.get_stacked_on_url',))
1570
b'Branch.get_stacked_on_url', (b'stacked/',),
1571
b'unknown', (b'Branch.get_stacked_on_url',))
1233
1572
client.add_expected_call(
1234
'Branch.get_stacked_on_url', ('stacked/',),
1235
'unknown', ('Branch.get_stacked_on_url',))
1573
b'Branch.get_stacked_on_url', (b'stacked/',),
1574
b'unknown', (b'Branch.get_stacked_on_url',))
1236
1575
# this will also do vfs access, but that goes direct to the transport
1237
1576
# and isn't seen by the FakeClient.
1238
1577
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
remote.RemoteBzrDirFormat(), _client=client)
1578
RemoteBzrDirFormat(), _client=client)
1240
1579
branch = bzrdir.open_branch()
1241
1580
result = branch.get_stacked_on_url()
1242
1581
self.assertEqual('../base', result)
1256
1595
client = FakeClient(self.get_url())
1257
1596
branch_network_name = self.get_branch_format().network_name()
1258
1597
client.add_expected_call(
1259
'BzrDir.open_branchV3', ('stacked/',),
1260
'success', ('branch', branch_network_name))
1598
b'BzrDir.open_branchV3', ('stacked/',),
1599
b'success', ('branch', branch_network_name))
1261
1600
client.add_expected_call(
1262
'BzrDir.find_repositoryV3', ('stacked/',),
1263
'success', ('ok', '', 'yes', 'no', 'yes', network_name))
1601
b'BzrDir.find_repositoryV3', (b'stacked/',),
1602
b'success', (b'ok', b'', b'yes', b'no', b'yes', network_name))
1264
1603
# called twice, once from constructor and then again by us
1265
1604
client.add_expected_call(
1266
'Branch.get_stacked_on_url', ('stacked/',),
1267
'success', ('ok', '../base'))
1605
b'Branch.get_stacked_on_url', (b'stacked/',),
1606
b'success', (b'ok', b'../base'))
1268
1607
client.add_expected_call(
1269
'Branch.get_stacked_on_url', ('stacked/',),
1270
'success', ('ok', '../base'))
1608
b'Branch.get_stacked_on_url', (b'stacked/',),
1609
b'success', (b'ok', b'../base'))
1271
1610
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1272
remote.RemoteBzrDirFormat(), _client=client)
1611
RemoteBzrDirFormat(), _client=client)
1273
1612
branch = bzrdir.open_branch()
1274
1613
result = branch.get_stacked_on_url()
1275
1614
self.assertEqual('../base', result)
1292
1631
client = FakeClient(transport.base)
1293
1632
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'),
1633
b'Branch.get_stacked_on_url', (b'branch/',),
1634
b'error', (b'NotStacked',))
1635
client.add_expected_call(
1636
b'Branch.lock_write', (b'branch/', b'', b''),
1637
b'success', (b'ok', b'branch token', b'repo token'))
1638
client.add_expected_call(
1639
b'Branch.last_revision_info',
1641
b'success', (b'ok', b'0', b'null:'))
1642
client.add_expected_call(
1643
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
1644
b'success', (b'ok',))
1645
client.add_expected_call(
1646
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1647
b'success', (b'ok',))
1309
1648
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
1649
branch.lock_write()
1314
result = branch.set_revision_history([])
1650
result = branch._set_last_revision(NULL_REVISION)
1315
1651
branch.unlock()
1316
1652
self.assertEqual(None, result)
1317
1653
self.assertFinished(client)
1319
1655
def test_set_nonempty(self):
1320
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1656
# set_last_revision_info(N, rev-idN) is translated to calling
1321
1657
# Branch.set_last_revision(path, rev-idN) on the wire.
1322
1658
transport = MemoryTransport()
1323
1659
transport.mkdir('branch')
1326
1662
client = FakeClient(transport.base)
1327
1663
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'),
1664
b'Branch.get_stacked_on_url', (b'branch/',),
1665
b'error', (b'NotStacked',))
1666
client.add_expected_call(
1667
b'Branch.lock_write', (b'branch/', b'', b''),
1668
b'success', (b'ok', b'branch token', b'repo token'))
1669
client.add_expected_call(
1670
b'Branch.last_revision_info',
1672
b'success', (b'ok', b'0', b'null:'))
1673
lines = [b'rev-id2']
1674
encoded_body = bz2.compress(b'\n'.join(lines))
1675
client.add_success_response_with_body(encoded_body, b'ok')
1676
client.add_expected_call(
1677
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
1678
b'success', (b'ok',))
1679
client.add_expected_call(
1680
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1681
b'success', (b'ok',))
1346
1682
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
1683
# Lock the branch, reset the record of remote calls.
1351
1684
branch.lock_write()
1352
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1685
result = branch._set_last_revision(b'rev-id2')
1353
1686
branch.unlock()
1354
1687
self.assertEqual(None, result)
1355
1688
self.assertFinished(client)
1361
1694
# A response of 'NoSuchRevision' is translated into an exception.
1362
1695
client = FakeClient(transport.base)
1363
1696
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:'))
1697
b'Branch.get_stacked_on_url', (b'branch/',),
1698
b'error', (b'NotStacked',))
1699
client.add_expected_call(
1700
b'Branch.lock_write', (b'branch/', b'', b''),
1701
b'success', (b'ok', b'branch token', b'repo token'))
1702
client.add_expected_call(
1703
b'Branch.last_revision_info',
1705
b'success', (b'ok', b'0', b'null:'))
1373
1706
# 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'),
1709
encoded_body = bz2.compress(b'\n'.join(lines))
1710
client.add_success_response_with_body(encoded_body, b'ok')
1711
client.add_expected_call(
1712
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1713
b'error', (b'NoSuchRevision', b'rev-id'))
1714
client.add_expected_call(
1715
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1716
b'success', (b'ok',))
1385
1718
branch = self.make_remote_branch(transport, client)
1386
1719
branch.lock_write()
1387
1720
self.assertRaises(
1388
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1721
errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1722
branch.unlock()
1390
1723
self.assertFinished(client)
1400
1733
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1734
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1735
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'),
1736
b'Branch.get_stacked_on_url', (b'branch/',),
1737
b'error', (b'NotStacked',))
1738
client.add_expected_call(
1739
b'Branch.lock_write', (b'branch/', b'', b''),
1740
b'success', (b'ok', b'branch token', b'repo token'))
1741
client.add_expected_call(
1742
b'Branch.last_revision_info',
1744
b'success', (b'ok', b'0', b'null:'))
1746
encoded_body = bz2.compress(b'\n'.join(lines))
1747
client.add_success_response_with_body(encoded_body, b'ok')
1748
client.add_expected_call(
1749
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1750
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1751
client.add_expected_call(
1752
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1753
b'success', (b'ok',))
1421
1754
branch = self.make_remote_branch(transport, client)
1422
branch._ensure_real = lambda: None
1423
1755
branch.lock_write()
1424
1756
# The 'TipChangeRejected' error response triggered by calling
1425
# set_revision_history causes a TipChangeRejected exception.
1757
# set_last_revision_info causes a TipChangeRejected exception.
1426
1758
err = self.assertRaises(
1427
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1759
errors.TipChangeRejected,
1760
branch._set_last_revision, b'rev-id')
1428
1761
# The UTF-8 message from the response has been decoded into a unicode
1430
self.assertIsInstance(err.msg, unicode)
1763
self.assertIsInstance(err.msg, text_type)
1431
1764
self.assertEqual(rejection_msg_unicode, err.msg)
1432
1765
branch.unlock()
1433
1766
self.assertFinished(client)
1443
1776
transport = transport.clone('branch')
1444
1777
client = FakeClient(transport.base)
1445
1778
# get_stacked_on_url
1446
client.add_error_response('NotStacked')
1779
client.add_error_response(b'NotStacked')
1448
client.add_success_response('ok', 'branch token', 'repo token')
1781
client.add_success_response(b'ok', b'branch token', b'repo token')
1449
1782
# query the current revision
1450
client.add_success_response('ok', '0', 'null:')
1783
client.add_success_response(b'ok', b'0', b'null:')
1451
1784
# set_last_revision
1452
client.add_success_response('ok')
1785
client.add_success_response(b'ok')
1454
client.add_success_response('ok')
1787
client.add_success_response(b'ok')
1456
1789
branch = self.make_remote_branch(transport, client)
1457
1790
# Lock the branch, reset the record of remote calls.
1458
1791
branch.lock_write()
1459
1792
client._calls = []
1460
result = branch.set_last_revision_info(1234, 'a-revision-id')
1793
result = branch.set_last_revision_info(1234, b'a-revision-id')
1461
1794
self.assertEqual(
1462
[('call', 'Branch.last_revision_info', ('branch/',)),
1463
('call', 'Branch.set_last_revision_info',
1464
('branch/', 'branch token', 'repo token',
1465
'1234', 'a-revision-id'))],
1795
[('call', b'Branch.last_revision_info', (b'branch/',)),
1796
('call', b'Branch.set_last_revision_info',
1797
(b'branch/', b'branch token', b'repo token',
1798
b'1234', b'a-revision-id'))],
1467
1800
self.assertEqual(None, result)
1603
1936
# in an empty branch we decode the response properly
1604
1937
client = FakeClient()
1605
1938
client.add_expected_call(
1606
'Branch.get_stacked_on_url', ('memory:///',),
1607
'error', ('NotStacked',),)
1608
client.add_success_response_with_body('# config file body', 'ok')
1939
b'Branch.get_stacked_on_url', (b'memory:///',),
1940
b'error', (b'NotStacked',),)
1941
client.add_success_response_with_body(b'# config file body', b'ok')
1609
1942
transport = MemoryTransport()
1610
1943
branch = self.make_remote_branch(transport, client)
1611
1944
config = branch.get_config()
1612
1945
config.has_explicit_nickname()
1613
1946
self.assertEqual(
1614
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1615
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1947
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
1948
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
1618
1951
def test_get_multi_line_branch_conf(self):
1619
1952
# Make sure that multiple-line branch.conf files are supported
1621
# https://bugs.edge.launchpad.net/bzr/+bug/354075
1954
# https://bugs.launchpad.net/bzr/+bug/354075
1622
1955
client = FakeClient()
1623
1956
client.add_expected_call(
1624
'Branch.get_stacked_on_url', ('memory:///',),
1625
'error', ('NotStacked',),)
1626
client.add_success_response_with_body('a = 1\nb = 2\nc = 3\n', 'ok')
1957
b'Branch.get_stacked_on_url', (b'memory:///',),
1958
b'error', (b'NotStacked',),)
1959
client.add_success_response_with_body(b'a = 1\nb = 2\nc = 3\n', b'ok')
1627
1960
transport = MemoryTransport()
1628
1961
branch = self.make_remote_branch(transport, client)
1629
1962
config = branch.get_config()
1632
1965
def test_set_option(self):
1633
1966
client = FakeClient()
1634
1967
client.add_expected_call(
1635
'Branch.get_stacked_on_url', ('memory:///',),
1636
'error', ('NotStacked',),)
1637
client.add_expected_call(
1638
'Branch.lock_write', ('memory:///', '', ''),
1639
'success', ('ok', 'branch token', 'repo token'))
1640
client.add_expected_call(
1641
'Branch.set_config_option', ('memory:///', 'branch token',
1642
'repo token', 'foo', 'bar', ''),
1644
client.add_expected_call(
1645
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1968
b'Branch.get_stacked_on_url', (b'memory:///',),
1969
b'error', (b'NotStacked',),)
1970
client.add_expected_call(
1971
b'Branch.lock_write', (b'memory:///', b'', b''),
1972
b'success', (b'ok', b'branch token', b'repo token'))
1973
client.add_expected_call(
1974
b'Branch.set_config_option', (b'memory:///', b'branch token',
1975
b'repo token', b'foo', b'bar', b''),
1977
client.add_expected_call(
1978
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
1979
b'success', (b'ok',))
1647
1980
transport = MemoryTransport()
1648
1981
branch = self.make_remote_branch(transport, client)
1649
1982
branch.lock_write()
1652
1985
branch.unlock()
1653
1986
self.assertFinished(client)
1988
def test_set_option_with_dict(self):
1989
client = FakeClient()
1990
client.add_expected_call(
1991
b'Branch.get_stacked_on_url', (b'memory:///',),
1992
b'error', (b'NotStacked',),)
1993
client.add_expected_call(
1994
b'Branch.lock_write', (b'memory:///', b'', b''),
1995
b'success', (b'ok', b'branch token', b'repo token'))
1996
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1997
client.add_expected_call(
1998
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
1999
b'repo token', encoded_dict_value, b'foo', b''),
2001
client.add_expected_call(
2002
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2003
b'success', (b'ok',))
2004
transport = MemoryTransport()
2005
branch = self.make_remote_branch(transport, client)
2007
config = branch._get_config()
2009
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
2012
self.assertFinished(client)
1655
2014
def test_backwards_compat_set_option(self):
1656
2015
self.setup_smart_server_with_call_log()
1657
2016
branch = self.make_branch('.')
1658
verb = 'Branch.set_config_option'
2017
verb = b'Branch.set_config_option'
1659
2018
self.disable_verb(verb)
1660
2019
branch.lock_write()
1661
2020
self.addCleanup(branch.unlock)
1662
2021
self.reset_smart_call_log()
1663
2022
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2023
self.assertLength(11, self.hpss_calls)
1665
2024
self.assertEqual('value', branch._get_config().get_option('name'))
2026
def test_backwards_compat_set_option_with_dict(self):
2027
self.setup_smart_server_with_call_log()
2028
branch = self.make_branch('.')
2029
verb = b'Branch.set_config_option_dict'
2030
self.disable_verb(verb)
2032
self.addCleanup(branch.unlock)
2033
self.reset_smart_call_log()
2034
config = branch._get_config()
2035
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2036
config.set_option(value_dict, 'name')
2037
self.assertLength(11, self.hpss_calls)
2038
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2041
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2043
def test_get_branch_conf(self):
2044
# in an empty branch we decode the response properly
2045
client = FakeClient()
2046
client.add_expected_call(
2047
b'Branch.get_stacked_on_url', (b'memory:///',),
2048
b'error', (b'NotStacked',),)
2049
client.add_success_response_with_body(b'# config file body', b'ok')
2050
transport = MemoryTransport()
2051
branch = self.make_remote_branch(transport, client)
2052
config = branch.get_config_stack()
2054
config.get("log_format")
2056
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2057
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
2060
def test_set_branch_conf(self):
2061
client = FakeClient()
2062
client.add_expected_call(
2063
b'Branch.get_stacked_on_url', (b'memory:///',),
2064
b'error', (b'NotStacked',),)
2065
client.add_expected_call(
2066
b'Branch.lock_write', (b'memory:///', b'', b''),
2067
b'success', (b'ok', b'branch token', b'repo token'))
2068
client.add_expected_call(
2069
b'Branch.get_config_file', (b'memory:///', ),
2070
b'success', (b'ok', ), b"# line 1\n")
2071
client.add_expected_call(
2072
b'Branch.get_config_file', (b'memory:///', ),
2073
b'success', (b'ok', ), b"# line 1\n")
2074
client.add_expected_call(
2075
b'Branch.put_config_file', (b'memory:///', b'branch token',
2077
b'success', (b'ok',))
2078
client.add_expected_call(
2079
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2080
b'success', (b'ok',))
2081
transport = MemoryTransport()
2082
branch = self.make_remote_branch(transport, client)
2084
config = branch.get_config_stack()
2085
config.set('email', 'The Dude <lebowski@example.com>')
2087
self.assertFinished(client)
2089
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2090
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2091
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2092
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2093
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2094
(b'memory:///', b'branch token', b'repo token'),
2095
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2096
('call', b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'))],
1668
2100
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2115
self.assertFinished(client)
2118
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2120
def test_simple(self):
2121
transport = MemoryTransport()
2122
client = FakeClient(transport.base)
2123
client.add_expected_call(
2124
b'Branch.get_stacked_on_url', (b'quack/',),
2125
b'error', (b'NotStacked',),)
2126
client.add_expected_call(
2127
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2128
b'success', (b'ok', b'0',),)
2129
client.add_expected_call(
2130
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2131
b'error', (b'NoSuchRevision', b'unknown',),)
2132
transport.mkdir('quack')
2133
transport = transport.clone('quack')
2134
branch = self.make_remote_branch(transport, client)
2135
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2136
self.assertRaises(errors.NoSuchRevision,
2137
branch.revision_id_to_revno, b'unknown')
2138
self.assertFinished(client)
2140
def test_dotted(self):
2141
transport = MemoryTransport()
2142
client = FakeClient(transport.base)
2143
client.add_expected_call(
2144
b'Branch.get_stacked_on_url', (b'quack/',),
2145
b'error', (b'NotStacked',),)
2146
client.add_expected_call(
2147
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2148
b'success', (b'ok', b'0',),)
2149
client.add_expected_call(
2150
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2151
b'error', (b'NoSuchRevision', b'unknown',),)
2152
transport.mkdir('quack')
2153
transport = transport.clone('quack')
2154
branch = self.make_remote_branch(transport, client)
2155
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2156
self.assertRaises(errors.NoSuchRevision,
2157
branch.revision_id_to_dotted_revno, b'unknown')
2158
self.assertFinished(client)
2160
def test_dotted_no_smart_verb(self):
2161
self.setup_smart_server_with_call_log()
2162
branch = self.make_branch('.')
2163
self.disable_verb(b'Branch.revision_id_to_revno')
2164
self.reset_smart_call_log()
2165
self.assertEqual((0, ),
2166
branch.revision_id_to_dotted_revno(b'null:'))
2167
self.assertLength(8, self.hpss_calls)
1686
2170
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2172
def test__get_config(self):
1689
2173
client = FakeClient()
1690
client.add_success_response_with_body('default_stack_on = /\n', 'ok')
2174
client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2175
transport = MemoryTransport()
1692
2176
bzrdir = self.make_remote_bzrdir(transport, client)
1693
2177
config = bzrdir.get_config()
1694
2178
self.assertEqual('/', config.get_default_stack_on())
1695
2179
self.assertEqual(
1696
[('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
2180
[('call_expecting_body', b'BzrDir.get_config_file', (b'memory:///',))],
1699
2183
def test_set_option_uses_vfs(self):
1700
2184
self.setup_smart_server_with_call_log()
1701
bzrdir = self.make_bzrdir('.')
2185
bzrdir = self.make_controldir('.')
1702
2186
self.reset_smart_call_log()
1703
2187
config = bzrdir.get_config()
1704
2188
config.set_default_stack_on('/')
1705
self.assertLength(3, self.hpss_calls)
2189
self.assertLength(4, self.hpss_calls)
1707
2191
def test_backwards_compat_get_option(self):
1708
2192
self.setup_smart_server_with_call_log()
1709
bzrdir = self.make_bzrdir('.')
1710
verb = 'BzrDir.get_config_file'
2193
bzrdir = self.make_controldir('.')
2194
verb = b'BzrDir.get_config_file'
1711
2195
self.disable_verb(verb)
1712
2196
self.reset_smart_call_log()
1713
2197
self.assertEqual(None,
1714
2198
bzrdir._get_config().get_option('default_stack_on'))
1715
self.assertLength(3, self.hpss_calls)
2199
self.assertLength(4, self.hpss_calls)
1718
2202
class TestTransportIsReadonly(tests.TestCase):
1720
2204
def test_true(self):
1721
2205
client = FakeClient()
1722
client.add_success_response('yes')
2206
client.add_success_response(b'yes')
1723
2207
transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2208
_client=client)
1725
2209
self.assertEqual(True, transport.is_readonly())
1726
2210
self.assertEqual(
1727
[('call', 'Transport.is_readonly', ())],
2211
[('call', b'Transport.is_readonly', ())],
1730
2214
def test_false(self):
1731
2215
client = FakeClient()
1732
client.add_success_response('no')
2216
client.add_success_response(b'no')
1733
2217
transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2218
_client=client)
1735
2219
self.assertEqual(False, transport.is_readonly())
1736
2220
self.assertEqual(
1737
[('call', 'Transport.is_readonly', ())],
2221
[('call', b'Transport.is_readonly', ())],
1740
2224
def test_error_from_old_server(self):
2415
class TestRepositoryBreakLock(TestRemoteRepository):
2417
def test_break_lock(self):
2418
transport_path = 'quack'
2419
repo, client = self.setup_fake_client_and_repository(transport_path)
2420
client.add_success_response(b'ok')
2423
[('call', b'Repository.break_lock', (b'quack/',))],
2427
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2429
def test_get_serializer_format(self):
2430
transport_path = 'hill'
2431
repo, client = self.setup_fake_client_and_repository(transport_path)
2432
client.add_success_response(b'ok', b'7')
2433
self.assertEqual(b'7', repo.get_serializer_format())
2435
[('call', b'VersionedFileRepository.get_serializer_format',
2440
class TestRepositoryReconcile(TestRemoteRepository):
2442
def test_reconcile(self):
2443
transport_path = 'hill'
2444
repo, client = self.setup_fake_client_and_repository(transport_path)
2445
body = (b"garbage_inventories: 2\n"
2446
b"inconsistent_parents: 3\n")
2447
client.add_expected_call(
2448
b'Repository.lock_write', (b'hill/', b''),
2449
b'success', (b'ok', b'a token'))
2450
client.add_success_response_with_body(body, b'ok')
2451
reconciler = repo.reconcile()
2453
[('call', b'Repository.lock_write', (b'hill/', b'')),
2454
('call_expecting_body', b'Repository.reconcile',
2455
(b'hill/', b'a token'))],
2457
self.assertEqual(2, reconciler.garbage_inventories)
2458
self.assertEqual(3, reconciler.inconsistent_parents)
2461
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2463
def test_text(self):
2464
# ('ok',), body with signature text
2465
transport_path = 'quack'
2466
repo, client = self.setup_fake_client_and_repository(transport_path)
2467
client.add_success_response_with_body(
2469
self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
2471
[('call_expecting_body', b'Repository.get_revision_signature_text',
2472
(b'quack/', b'revid'))],
2475
def test_no_signature(self):
2476
transport_path = 'quick'
2477
repo, client = self.setup_fake_client_and_repository(transport_path)
2478
client.add_error_response(b'nosuchrevision', b'unknown')
2479
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2482
[('call_expecting_body', b'Repository.get_revision_signature_text',
2483
(b'quick/', b'unknown'))],
1906
2487
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2489
def test_get_graph(self):
1949
2557
self.assertEqual({r1: (NULL_REVISION,)}, parents)
1950
2558
self.assertEqual(
1951
2559
[('call_with_body_bytes_expecting_body',
1952
'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
2560
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r2),
1954
2562
('call_with_body_bytes_expecting_body',
1955
'Repository.get_parent_map', ('quack/', 'include-missing:', r1),
2563
b'Repository.get_parent_map', (b'quack/', b'include-missing:', r1),
1961
2569
def test_get_parent_map_reconnects_if_unknown_method(self):
1962
2570
transport_path = 'quack'
1963
rev_id = 'revision-id'
2571
rev_id = b'revision-id'
1964
2572
repo, client = self.setup_fake_client_and_repository(transport_path)
1965
client.add_unknown_method_response('Repository.get_parent_map')
1966
client.add_success_response_with_body(rev_id, 'ok')
2573
client.add_unknown_method_response(b'Repository.get_parent_map')
2574
client.add_success_response_with_body(rev_id, b'ok')
1967
2575
self.assertFalse(client._medium._is_remote_before((1, 2)))
1968
2576
parents = repo.get_parent_map([rev_id])
1969
2577
self.assertEqual(
1970
2578
[('call_with_body_bytes_expecting_body',
1971
'Repository.get_parent_map', ('quack/', 'include-missing:',
2579
b'Repository.get_parent_map',
2580
(b'quack/', b'include-missing:', rev_id), b'\n\n0'),
1973
2581
('disconnect medium',),
1974
('call_expecting_body', 'Repository.get_revision_graph',
2582
('call_expecting_body', b'Repository.get_revision_graph',
1977
2585
# The medium is now marked as being connected to an older server
1978
2586
self.assertTrue(client._medium._is_remote_before((1, 2)))
1979
self.assertEqual({rev_id: ('null:',)}, parents)
2587
self.assertEqual({rev_id: (b'null:',)}, parents)
1981
2589
def test_get_parent_map_fallback_parentless_node(self):
1982
2590
"""get_parent_map falls back to get_revision_graph on old servers. The
2109
2741
self.addCleanup(tree.unlock)
2110
2742
graph = tree.branch.repository.get_graph()
2111
2743
# This provides an opportunity for the missing rev-id to be cached.
2112
self.assertEqual({}, graph.get_parent_map(['rev1']))
2113
tree.commit('message', rev_id='rev1')
2744
self.assertEqual({}, graph.get_parent_map([b'rev1']))
2745
tree.commit('message', rev_id=b'rev1')
2114
2746
graph = tree.branch.repository.get_graph()
2115
self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2747
self.assertEqual({b'rev1': (b'null:',)}, graph.get_parent_map([b'rev1']))
2750
class TestRepositoryGetRevisions(TestRemoteRepository):
2752
def test_hpss_missing_revision(self):
2753
transport_path = 'quack'
2754
repo, client = self.setup_fake_client_and_repository(transport_path)
2755
client.add_success_response_with_body(
2757
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2758
[b'somerev1', b'anotherrev2'])
2760
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2761
(b'quack/', ), b"somerev1\nanotherrev2")],
2764
def test_hpss_get_single_revision(self):
2765
transport_path = 'quack'
2766
repo, client = self.setup_fake_client_and_repository(transport_path)
2767
somerev1 = Revision(b"somerev1")
2768
somerev1.committer = "Joe Committer <joe@example.com>"
2769
somerev1.timestamp = 1321828927
2770
somerev1.timezone = -60
2771
somerev1.inventory_sha1 = b"691b39be74c67b1212a75fcb19c433aaed903c2b"
2772
somerev1.message = "Message"
2773
body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
2775
# Split up body into two bits to make sure the zlib compression object
2776
# gets data fed twice.
2777
client.add_success_response_with_body(
2778
[body[:10], body[10:]], b'ok', b'10')
2779
revs = repo.get_revisions([b'somerev1'])
2780
self.assertEqual(revs, [somerev1])
2782
[('call_with_body_bytes_expecting_body', b'Repository.iter_revisions',
2783
(b'quack/', ), b"somerev1")],
2118
2787
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2154
2823
r11 = u'\u0e33'.encode('utf8')
2155
2824
r12 = u'\xc9'.encode('utf8')
2156
2825
r2 = u'\u0dab'.encode('utf8')
2157
lines = [' '.join([r2, r11, r12]), r11, r12]
2158
encoded_body = '\n'.join(lines)
2826
lines = [b' '.join([r2, r11, r12]), r11, r12]
2827
encoded_body = b'\n'.join(lines)
2160
2829
transport_path = 'sinhala'
2161
2830
repo, client = self.setup_fake_client_and_repository(transport_path)
2162
client.add_success_response_with_body(encoded_body, 'ok')
2831
client.add_success_response_with_body(encoded_body, b'ok')
2163
2832
result = repo._get_revision_graph(r2)
2164
2833
self.assertEqual(
2165
[('call_expecting_body', 'Repository.get_revision_graph',
2834
[('call_expecting_body', b'Repository.get_revision_graph',
2835
(b'sinhala/', r2))],
2168
2837
self.assertEqual({r11: (), r12: (), r2: (r11, r12), }, result)
2170
2839
def test_no_such_revision(self):
2172
2841
transport_path = 'sinhala'
2173
2842
repo, client = self.setup_fake_client_and_repository(transport_path)
2174
client.add_error_response('nosuchrevision', revid)
2843
client.add_error_response(b'nosuchrevision', revid)
2175
2844
# also check that the right revision is reported in the error
2176
2845
self.assertRaises(errors.NoSuchRevision,
2177
2846
repo._get_revision_graph, revid)
2178
2847
self.assertEqual(
2179
[('call_expecting_body', 'Repository.get_revision_graph',
2180
('sinhala/', revid))],
2848
[('call_expecting_body', b'Repository.get_revision_graph',
2849
(b'sinhala/', revid))],
2183
2852
def test_unexpected_error(self):
2185
2854
transport_path = 'sinhala'
2186
2855
repo, client = self.setup_fake_client_and_repository(transport_path)
2187
client.add_error_response('AnUnexpectedError')
2856
client.add_error_response(b'AnUnexpectedError')
2188
2857
e = self.assertRaises(errors.UnknownErrorFromSmartServer,
2189
2858
repo._get_revision_graph, revid)
2190
self.assertEqual(('AnUnexpectedError',), e.error_tuple)
2859
self.assertEqual((b'AnUnexpectedError',), e.error_tuple)
2193
2862
class TestRepositoryGetRevIdForRevno(TestRemoteRepository):
2195
2864
def test_ok(self):
2196
2865
repo, client = self.setup_fake_client_and_repository('quack')
2197
2866
client.add_expected_call(
2198
'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2199
'success', ('ok', 'rev-five'))
2200
result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2201
self.assertEqual((True, 'rev-five'), result)
2867
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2868
b'success', (b'ok', b'rev-five'))
2869
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2870
self.assertEqual((True, b'rev-five'), result)
2202
2871
self.assertFinished(client)
2204
2873
def test_history_incomplete(self):
2205
2874
repo, client = self.setup_fake_client_and_repository('quack')
2206
2875
client.add_expected_call(
2207
'Repository.get_rev_id_for_revno', ('quack/', 5, (42, 'rev-foo')),
2208
'success', ('history-incomplete', 10, 'rev-ten'))
2209
result = repo.get_rev_id_for_revno(5, (42, 'rev-foo'))
2210
self.assertEqual((False, (10, 'rev-ten')), result)
2876
b'Repository.get_rev_id_for_revno', (b'quack/', 5, (42, b'rev-foo')),
2877
b'success', (b'history-incomplete', 10, b'rev-ten'))
2878
result = repo.get_rev_id_for_revno(5, (42, b'rev-foo'))
2879
self.assertEqual((False, (10, b'rev-ten')), result)
2211
2880
self.assertFinished(client)
2213
2882
def test_history_incomplete_with_fallback(self):
2257
2926
self.setup_smart_server_with_call_log()
2258
2927
tree = self.make_branch_and_memory_tree('.')
2259
2928
tree.lock_write()
2260
2930
rev1 = tree.commit('First')
2261
2931
rev2 = tree.commit('Second')
2263
2933
branch = tree.branch
2264
2934
self.assertFalse(branch.is_locked())
2265
2935
self.reset_smart_call_log()
2266
verb = 'Repository.get_rev_id_for_revno'
2936
verb = b'Repository.get_rev_id_for_revno'
2267
2937
self.disable_verb(verb)
2268
2938
self.assertEqual(rev1, branch.get_rev_id(1))
2269
2939
self.assertLength(1, [call for call in self.hpss_calls if
2270
2940
call.call.method == verb])
2943
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2945
def test_has_signature_for_revision_id(self):
2946
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2947
transport_path = 'quack'
2948
repo, client = self.setup_fake_client_and_repository(transport_path)
2949
client.add_success_response(b'yes')
2950
result = repo.has_signature_for_revision_id(b'A')
2952
[('call', b'Repository.has_signature_for_revision_id',
2953
(b'quack/', b'A'))],
2955
self.assertEqual(True, result)
2957
def test_is_not_shared(self):
2958
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2959
transport_path = 'qwack'
2960
repo, client = self.setup_fake_client_and_repository(transport_path)
2961
client.add_success_response(b'no')
2962
result = repo.has_signature_for_revision_id(b'A')
2964
[('call', b'Repository.has_signature_for_revision_id',
2965
(b'qwack/', b'A'))],
2967
self.assertEqual(False, result)
2970
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2972
def test_get_physical_lock_status_yes(self):
2973
transport_path = 'qwack'
2974
repo, client = self.setup_fake_client_and_repository(transport_path)
2975
client.add_success_response(b'yes')
2976
result = repo.get_physical_lock_status()
2978
[('call', b'Repository.get_physical_lock_status',
2981
self.assertEqual(True, result)
2983
def test_get_physical_lock_status_no(self):
2984
transport_path = 'qwack'
2985
repo, client = self.setup_fake_client_and_repository(transport_path)
2986
client.add_success_response(b'no')
2987
result = repo.get_physical_lock_status()
2989
[('call', b'Repository.get_physical_lock_status',
2992
self.assertEqual(False, result)
2273
2995
class TestRepositoryIsShared(TestRemoteRepository):
2275
2997
def test_is_shared(self):
2276
2998
# ('yes', ) for Repository.is_shared -> 'True'.
2277
2999
transport_path = 'quack'
2278
3000
repo, client = self.setup_fake_client_and_repository(transport_path)
2279
client.add_success_response('yes')
3001
client.add_success_response(b'yes')
2280
3002
result = repo.is_shared()
2281
3003
self.assertEqual(
2282
[('call', 'Repository.is_shared', ('quack/',))],
3004
[('call', b'Repository.is_shared', (b'quack/',))],
2284
3006
self.assertEqual(True, result)
2300
3047
def test_lock_write(self):
2301
3048
transport_path = 'quack'
2302
3049
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
client.add_success_response('ok', 'a token')
3050
client.add_success_response(b'ok', b'a token')
2304
3051
token = repo.lock_write().repository_token
2305
3052
self.assertEqual(
2306
[('call', 'Repository.lock_write', ('quack/', ''))],
3053
[('call', b'Repository.lock_write', (b'quack/', b''))],
2308
self.assertEqual('a token', token)
3055
self.assertEqual(b'a token', token)
2310
3057
def test_lock_write_already_locked(self):
2311
3058
transport_path = 'quack'
2312
3059
repo, client = self.setup_fake_client_and_repository(transport_path)
2313
client.add_error_response('LockContention')
3060
client.add_error_response(b'LockContention')
2314
3061
self.assertRaises(errors.LockContention, repo.lock_write)
2315
3062
self.assertEqual(
2316
[('call', 'Repository.lock_write', ('quack/', ''))],
3063
[('call', b'Repository.lock_write', (b'quack/', b''))],
2319
3066
def test_lock_write_unlockable(self):
2320
3067
transport_path = 'quack'
2321
3068
repo, client = self.setup_fake_client_and_repository(transport_path)
2322
client.add_error_response('UnlockableTransport')
3069
client.add_error_response(b'UnlockableTransport')
2323
3070
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3071
self.assertEqual(
2325
[('call', 'Repository.lock_write', ('quack/', ''))],
3072
[('call', b'Repository.lock_write', (b'quack/', b''))],
3076
class TestRepositoryWriteGroups(TestRemoteRepository):
3078
def test_start_write_group(self):
3079
transport_path = 'quack'
3080
repo, client = self.setup_fake_client_and_repository(transport_path)
3081
client.add_expected_call(
3082
b'Repository.lock_write', (b'quack/', b''),
3083
b'success', (b'ok', b'a token'))
3084
client.add_expected_call(
3085
b'Repository.start_write_group', (b'quack/', b'a token'),
3086
b'success', (b'ok', (b'token1', )))
3088
repo.start_write_group()
3090
def test_start_write_group_unsuspendable(self):
3091
# Some repositories do not support suspending write
3092
# groups. For those, fall back to the "real" repository.
3093
transport_path = 'quack'
3094
repo, client = self.setup_fake_client_and_repository(transport_path)
3095
def stub_ensure_real():
3096
client._calls.append(('_ensure_real',))
3097
repo._real_repository = _StubRealPackRepository(client._calls)
3098
repo._ensure_real = stub_ensure_real
3099
client.add_expected_call(
3100
b'Repository.lock_write', (b'quack/', b''),
3101
b'success', (b'ok', b'a token'))
3102
client.add_expected_call(
3103
b'Repository.start_write_group', (b'quack/', b'a token'),
3104
b'error', (b'UnsuspendableWriteGroup',))
3106
repo.start_write_group()
3107
self.assertEqual(client._calls[-2:], [
3109
('start_write_group',)])
3111
def test_commit_write_group(self):
3112
transport_path = 'quack'
3113
repo, client = self.setup_fake_client_and_repository(transport_path)
3114
client.add_expected_call(
3115
b'Repository.lock_write', (b'quack/', b''),
3116
b'success', (b'ok', b'a token'))
3117
client.add_expected_call(
3118
b'Repository.start_write_group', (b'quack/', b'a token'),
3119
b'success', (b'ok', [b'token1']))
3120
client.add_expected_call(
3121
b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
3122
b'success', (b'ok',))
3124
repo.start_write_group()
3125
repo.commit_write_group()
3127
def test_abort_write_group(self):
3128
transport_path = 'quack'
3129
repo, client = self.setup_fake_client_and_repository(transport_path)
3130
client.add_expected_call(
3131
b'Repository.lock_write', (b'quack/', b''),
3132
b'success', (b'ok', b'a token'))
3133
client.add_expected_call(
3134
b'Repository.start_write_group', (b'quack/', b'a token'),
3135
b'success', (b'ok', [b'token1']))
3136
client.add_expected_call(
3137
b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
3138
b'success', (b'ok',))
3140
repo.start_write_group()
3141
repo.abort_write_group(False)
3143
def test_suspend_write_group(self):
3144
transport_path = 'quack'
3145
repo, client = self.setup_fake_client_and_repository(transport_path)
3146
self.assertEqual([], repo.suspend_write_group())
3148
def test_resume_write_group(self):
3149
transport_path = 'quack'
3150
repo, client = self.setup_fake_client_and_repository(transport_path)
3151
client.add_expected_call(
3152
b'Repository.lock_write', (b'quack/', b''),
3153
b'success', (b'ok', b'a token'))
3154
client.add_expected_call(
3155
b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
3156
b'success', (b'ok',))
3158
repo.resume_write_group([b'token1'])
2329
3161
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3163
def test_backwards_compat(self):
2332
3164
self.setup_smart_server_with_call_log()
2333
3165
repo = self.make_repository('.')
2334
3166
self.reset_smart_call_log()
2335
verb = 'Repository.set_make_working_trees'
3167
verb = b'Repository.set_make_working_trees'
2336
3168
self.disable_verb(verb)
2337
3169
repo.set_make_working_trees(True)
2338
3170
call_count = len([call for call in self.hpss_calls if
2419
3278
def setUp(self):
2420
TestRemoteRepository.setUp(self)
2421
self.disable_verb('Repository.insert_stream_1.19')
3279
super(TestRepositoryInsertStream, self).setUp()
3280
self.disable_verb(b'Repository.insert_stream_1.19')
2423
3282
def test_unlocked_repo(self):
2424
3283
transport_path = 'quack'
2425
3284
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3285
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/', ''),
3286
b'Repository.insert_stream_1.19', (b'quack/', b''),
3287
b'unknown', (b'Repository.insert_stream_1.19',))
3288
client.add_expected_call(
3289
b'Repository.insert_stream', (b'quack/', b''),
3290
b'success', (b'ok',))
3291
client.add_expected_call(
3292
b'Repository.insert_stream', (b'quack/', b''),
3293
b'success', (b'ok',))
2435
3294
self.checkInsertEmptyStream(repo, client)
2437
3296
def test_locked_repo_with_no_lock_token(self):
2438
3297
transport_path = 'quack'
2439
3298
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3299
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/', ''),
3300
b'Repository.lock_write', (b'quack/', b''),
3301
b'success', (b'ok', b''))
3302
client.add_expected_call(
3303
b'Repository.insert_stream_1.19', (b'quack/', b''),
3304
b'unknown', (b'Repository.insert_stream_1.19',))
3305
client.add_expected_call(
3306
b'Repository.insert_stream', (b'quack/', b''),
3307
b'success', (b'ok',))
3308
client.add_expected_call(
3309
b'Repository.insert_stream', (b'quack/', b''),
3310
b'success', (b'ok',))
2452
3311
repo.lock_write()
2453
3312
self.checkInsertEmptyStream(repo, client)
2534
3393
* texts substream: (some-rev, some-file)
2536
3395
# Define a stream using generators so that it isn't rewindable.
2537
inv = inventory.Inventory(revision_id='rev1')
2538
inv.root.revision = 'rev1'
3396
inv = inventory.Inventory(revision_id=b'rev1')
3397
inv.root.revision = b'rev1'
2539
3398
def stream_with_inv_delta():
2540
3399
yield ('inventories', inventories_substream())
2541
3400
yield ('inventory-deltas', inventory_delta_substream())
2542
3401
yield ('texts', [
2543
3402
versionedfile.FulltextContentFactory(
2544
('some-rev', 'some-file'), (), None, 'content')])
3403
(b'some-rev', 'some-file'), (), None, 'content')])
2545
3404
def inventories_substream():
2546
3405
# An empty inventory fulltext. This will be streamed normally.
2547
3406
text = fmt._serializer.write_inventory_to_string(inv)
2548
3407
yield versionedfile.FulltextContentFactory(
2549
('rev1',), (), None, text)
3408
(b'rev1',), (), None, text)
2550
3409
def inventory_delta_substream():
2551
3410
# An inventory delta. This can't be streamed via this verb, so it
2552
3411
# will trigger a fallback to VFS insert_stream.
2553
3412
entry = inv.make_entry(
2554
'directory', 'newdir', inv.root.file_id, 'newdir-id')
3413
'directory', 'newdir', inv.root.file_id, b'newdir-id')
2555
3414
entry.revision = 'ghost'
2556
delta = [(None, 'newdir', 'newdir-id', entry)]
3415
delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3416
serializer = inventory_delta.InventoryDeltaSerializer(
2558
3417
versioned_root=True, tree_references=False)
2559
lines = serializer.delta_to_lines('rev1', 'rev2', delta)
3418
lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3419
yield versionedfile.ChunkedContentFactory(
2561
('rev2',), (('rev1',)), None, lines)
3420
(b'rev2',), ((b'rev1',)), None, lines)
2562
3421
# Another delta.
2563
lines = serializer.delta_to_lines('rev1', 'rev3', delta)
3422
lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3423
yield versionedfile.ChunkedContentFactory(
2565
('rev3',), (('rev1',)), None, lines)
3424
(b'rev3',), ((b'rev1',)), None, lines)
2566
3425
return stream_with_inv_delta()
2784
3656
def test_NoSuchRevision(self):
2785
3657
branch = self.make_branch('')
2787
3659
translated_error = self.translateTuple(
2788
('NoSuchRevision', revid), branch=branch)
3660
(b'NoSuchRevision', revid), branch=branch)
2789
3661
expected_error = errors.NoSuchRevision(branch, revid)
2790
3662
self.assertEqual(expected_error, translated_error)
2792
3664
def test_nosuchrevision(self):
2793
3665
repository = self.make_repository('')
2795
3667
translated_error = self.translateTuple(
2796
('nosuchrevision', revid), repository=repository)
3668
(b'nosuchrevision', revid), repository=repository)
2797
3669
expected_error = errors.NoSuchRevision(repository, revid)
2798
3670
self.assertEqual(expected_error, translated_error)
2800
3672
def test_nobranch(self):
2801
bzrdir = self.make_bzrdir('')
2802
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3673
bzrdir = self.make_controldir('')
3674
translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3675
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3676
self.assertEqual(expected_error, translated_error)
2806
3678
def test_nobranch_one_arg(self):
2807
bzrdir = self.make_bzrdir('')
3679
bzrdir = self.make_controldir('')
2808
3680
translated_error = self.translateTuple(
2809
('nobranch', 'extra detail'), bzrdir=bzrdir)
3681
(b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3682
expected_error = errors.NotBranchError(
2811
3683
path=bzrdir.root_transport.base,
2812
3684
detail='extra detail')
2813
3685
self.assertEqual(expected_error, translated_error)
3687
def test_norepository(self):
3688
bzrdir = self.make_controldir('')
3689
translated_error = self.translateTuple((b'norepository',),
3691
expected_error = errors.NoRepositoryPresent(bzrdir)
3692
self.assertEqual(expected_error, translated_error)
2815
3694
def test_LockContention(self):
2816
translated_error = self.translateTuple(('LockContention',))
3695
translated_error = self.translateTuple((b'LockContention',))
2817
3696
expected_error = errors.LockContention('(remote lock)')
2818
3697
self.assertEqual(expected_error, translated_error)
2820
3699
def test_UnlockableTransport(self):
2821
bzrdir = self.make_bzrdir('')
3700
bzrdir = self.make_controldir('')
2822
3701
translated_error = self.translateTuple(
2823
('UnlockableTransport',), bzrdir=bzrdir)
3702
(b'UnlockableTransport',), bzrdir=bzrdir)
2824
3703
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3704
self.assertEqual(expected_error, translated_error)
2827
3706
def test_LockFailed(self):
2828
3707
lock = 'str() of a server lock'
2829
3708
why = 'str() of why'
2830
translated_error = self.translateTuple(('LockFailed', lock, why))
3709
translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3710
expected_error = errors.LockFailed(lock, why)
2832
3711
self.assertEqual(expected_error, translated_error)
2834
3713
def test_TokenMismatch(self):
2835
3714
token = 'a lock token'
2836
translated_error = self.translateTuple(('TokenMismatch',), token=token)
3715
translated_error = self.translateTuple((b'TokenMismatch',), token=token)
2837
3716
expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3717
self.assertEqual(expected_error, translated_error)
2841
3720
branch = self.make_branch('a')
2842
3721
other_branch = self.make_branch('b')
2843
3722
translated_error = self.translateTuple(
2844
('Diverged',), branch=branch, other_branch=other_branch)
3723
(b'Diverged',), branch=branch, other_branch=other_branch)
2845
3724
expected_error = errors.DivergedBranches(branch, other_branch)
2846
3725
self.assertEqual(expected_error, translated_error)
3727
def test_NotStacked(self):
3728
branch = self.make_branch('')
3729
translated_error = self.translateTuple((b'NotStacked',), branch=branch)
3730
expected_error = errors.NotStacked(branch)
3731
self.assertEqual(expected_error, translated_error)
2848
3733
def test_ReadError_no_args(self):
2849
3734
path = 'a path'
2850
translated_error = self.translateTuple(('ReadError',), path=path)
3735
translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3736
expected_error = errors.ReadError(path)
2852
3737
self.assertEqual(expected_error, translated_error)
2854
3739
def test_ReadError(self):
2855
3740
path = 'a path'
2856
translated_error = self.translateTuple(('ReadError', path))
3741
translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
2857
3742
expected_error = errors.ReadError(path)
2858
3743
self.assertEqual(expected_error, translated_error)
2860
3745
def test_IncompatibleRepositories(self):
2861
translated_error = self.translateTuple(('IncompatibleRepositories',
2862
"repo1", "repo2", "details here"))
3746
translated_error = self.translateTuple((b'IncompatibleRepositories',
3747
b"repo1", b"repo2", b"details here"))
2863
3748
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2864
3749
"details here")
2865
3750
self.assertEqual(expected_error, translated_error)
2867
3752
def test_PermissionDenied_no_args(self):
2868
3753
path = 'a path'
2869
translated_error = self.translateTuple(('PermissionDenied',), path=path)
3754
translated_error = self.translateTuple((b'PermissionDenied',),
2870
3756
expected_error = errors.PermissionDenied(path)
2871
3757
self.assertEqual(expected_error, translated_error)
2873
3759
def test_PermissionDenied_one_arg(self):
2874
3760
path = 'a path'
2875
translated_error = self.translateTuple(('PermissionDenied', path))
3761
translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
2876
3762
expected_error = errors.PermissionDenied(path)
2877
3763
self.assertEqual(expected_error, translated_error)
2891
3777
path = 'a path'
2892
3778
extra = 'a string with extra info'
2893
3779
translated_error = self.translateTuple(
2894
('PermissionDenied', path, extra))
3780
(b'PermissionDenied', path.encode('utf-8'), extra.encode('utf-8')))
2895
3781
expected_error = errors.PermissionDenied(path, extra)
2896
3782
self.assertEqual(expected_error, translated_error)
3784
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3786
def test_NoSuchFile_context_path(self):
3787
local_path = "local path"
3788
translated_error = self.translateTuple((b'ReadError', b"remote path"),
3790
expected_error = errors.ReadError(local_path)
3791
self.assertEqual(expected_error, translated_error)
3793
def test_NoSuchFile_without_context(self):
3794
remote_path = "remote path"
3795
translated_error = self.translateTuple((b'ReadError', remote_path.encode('utf-8')))
3796
expected_error = errors.ReadError(remote_path)
3797
self.assertEqual(expected_error, translated_error)
3799
def test_ReadOnlyError(self):
3800
translated_error = self.translateTuple((b'ReadOnlyError',))
3801
expected_error = errors.TransportNotPossible("readonly transport")
3802
self.assertEqual(expected_error, translated_error)
3804
def test_MemoryError(self):
3805
translated_error = self.translateTuple((b'MemoryError',))
3806
self.assertStartsWith(str(translated_error),
3807
"remote server out of memory")
3809
def test_generic_IndexError_no_classname(self):
3810
err = errors.ErrorFromSmartServer((b'error', b"list index out of range"))
3811
translated_error = self.translateErrorFromSmartServer(err)
3812
expected_error = errors.UnknownErrorFromSmartServer(err)
3813
self.assertEqual(expected_error, translated_error)
3815
# GZ 2011-03-02: TODO test generic non-ascii error string
3817
def test_generic_KeyError(self):
3818
err = errors.ErrorFromSmartServer((b'error', b'KeyError', b"1"))
3819
translated_error = self.translateErrorFromSmartServer(err)
3820
expected_error = errors.UnknownErrorFromSmartServer(err)
3821
self.assertEqual(expected_error, translated_error)
2899
3824
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3825
"""Unit tests for breezy.bzr.remote._translate_error's robustness.
2902
3827
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3828
translate successfully. This class about how _translate_err behaves when
3143
4070
def test_copy_content_into_avoids_revision_history(self):
3144
4071
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4072
builder = self.make_branch_builder('remote')
4073
builder.build_commit(message="Commit.")
3147
4074
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4075
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4076
local.repository.fetch(remote_branch.repository)
3150
4077
self.hpss_calls = []
3151
4078
remote_branch.copy_content_into(local)
3152
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4079
self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
4081
def test_fetch_everything_needs_just_one_call(self):
4082
local = self.make_branch('local')
4083
builder = self.make_branch_builder('remote')
4084
builder.build_commit(message="Commit.")
4085
remote_branch_url = self.smart_server.get_url() + 'remote'
4086
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4087
self.hpss_calls = []
4088
local.repository.fetch(
4089
remote_branch.repository,
4090
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4091
self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
4093
def override_verb(self, verb_name, verb):
4094
request_handlers = request.request_handlers
4095
orig_verb = request_handlers.get(verb_name)
4096
orig_info = request_handlers.get_info(verb_name)
4097
request_handlers.register(verb_name, verb, override_existing=True)
4098
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4099
override_existing=True, info=orig_info)
4101
def test_fetch_everything_backwards_compat(self):
4102
"""Can fetch with EverythingResult even with pre 2.4 servers.
4104
Pre-2.4 do not support 'everything' searches with the
4105
Repository.get_stream_1.19 verb.
4108
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4109
"""A version of the Repository.get_stream_1.19 verb patched to
4110
reject 'everything' searches the way 2.3 and earlier do.
4112
def recreate_search(self, repository, search_bytes,
4113
discard_excess=False):
4114
verb_log.append(search_bytes.split(b'\n', 1)[0])
4115
if search_bytes == b'everything':
4117
request.FailedSmartServerResponse((b'BadSearch',)))
4118
return super(OldGetStreamVerb,
4119
self).recreate_search(repository, search_bytes,
4120
discard_excess=discard_excess)
4121
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4122
local = self.make_branch('local')
4123
builder = self.make_branch_builder('remote')
4124
builder.build_commit(message="Commit.")
4125
remote_branch_url = self.smart_server.get_url() + 'remote'
4126
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4127
self.hpss_calls = []
4128
local.repository.fetch(
4129
remote_branch.repository,
4130
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4131
# make sure the overridden verb was used
4132
self.assertLength(1, verb_log)
4133
# more than one HPSS call is needed, but because it's a VFS callback
4134
# its hard to predict exactly how many.
4135
self.assertTrue(len(self.hpss_calls) > 1)
4138
class TestUpdateBoundBranchWithModifiedBoundLocation(
4139
tests.TestCaseWithTransport):
4140
"""Ensure correct handling of bound_location modifications.
4142
This is tested against a smart server as http://pad.lv/786980 was about a
4143
ReadOnlyError (write attempt during a read-only transaction) which can only
4144
happen in this context.
4148
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4149
self.transport_server = test_server.SmartTCPServer_for_testing
4151
def make_master_and_checkout(self, master_name, checkout_name):
4152
# Create the master branch and its associated checkout
4153
self.master = self.make_branch_and_tree(master_name)
4154
self.checkout = self.master.branch.create_checkout(checkout_name)
4155
# Modify the master branch so there is something to update
4156
self.master.commit('add stuff')
4157
self.last_revid = self.master.commit('even more stuff')
4158
self.bound_location = self.checkout.branch.get_bound_location()
4160
def assertUpdateSucceeds(self, new_location):
4161
self.checkout.branch.set_bound_location(new_location)
4162
self.checkout.update()
4163
self.assertEqual(self.last_revid, self.checkout.last_revision())
4165
def test_without_final_slash(self):
4166
self.make_master_and_checkout('master', 'checkout')
4167
# For unclear reasons some users have a bound_location without a final
4168
# '/', simulate that by forcing such a value
4169
self.assertEndsWith(self.bound_location, '/')
4170
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4172
def test_plus_sign(self):
4173
self.make_master_and_checkout('+master', 'checkout')
4174
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4176
def test_tilda(self):
4177
# Embed ~ in the middle of the path just to avoid any $HOME
4179
self.make_master_and_checkout('mas~ter', 'checkout')
4180
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4183
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4185
def test_no_context(self):
4186
class OutOfCoffee(errors.BzrError):
4187
"""A dummy exception for testing."""
4189
def __init__(self, urgency):
4190
self.urgency = urgency
4191
remote.no_context_error_translators.register(b"OutOfCoffee",
4192
lambda err: OutOfCoffee(err.error_args[0]))
4193
transport = MemoryTransport()
4194
client = FakeClient(transport.base)
4195
client.add_expected_call(
4196
b'Branch.get_stacked_on_url', (b'quack/',),
4197
b'error', (b'NotStacked',))
4198
client.add_expected_call(
4199
b'Branch.last_revision_info',
4201
b'error', (b'OutOfCoffee', b'low'))
4202
transport.mkdir('quack')
4203
transport = transport.clone('quack')
4204
branch = self.make_remote_branch(transport, client)
4205
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4206
self.assertFinished(client)
4208
def test_with_context(self):
4209
class OutOfTea(errors.BzrError):
4210
def __init__(self, branch, urgency):
4211
self.branch = branch
4212
self.urgency = urgency
4213
remote.error_translators.register(b"OutOfTea",
4214
lambda err, find, path: OutOfTea(
4215
err.error_args[0].decode('utf-8'),
4217
transport = MemoryTransport()
4218
client = FakeClient(transport.base)
4219
client.add_expected_call(
4220
b'Branch.get_stacked_on_url', (b'quack/',),
4221
b'error', (b'NotStacked',))
4222
client.add_expected_call(
4223
b'Branch.last_revision_info',
4225
b'error', (b'OutOfTea', b'low'))
4226
transport.mkdir('quack')
4227
transport = transport.clone('quack')
4228
branch = self.make_remote_branch(transport, client)
4229
self.assertRaises(OutOfTea, branch.last_revision_info)
4230
self.assertFinished(client)
4233
class TestRepositoryPack(TestRemoteRepository):
4235
def test_pack(self):
4236
transport_path = 'quack'
4237
repo, client = self.setup_fake_client_and_repository(transport_path)
4238
client.add_expected_call(
4239
b'Repository.lock_write', (b'quack/', b''),
4240
b'success', (b'ok', b'token'))
4241
client.add_expected_call(
4242
b'Repository.pack', (b'quack/', b'token', b'False'),
4243
b'success', (b'ok',), )
4244
client.add_expected_call(
4245
b'Repository.unlock', (b'quack/', b'token'),
4246
b'success', (b'ok', ))
4249
def test_pack_with_hint(self):
4250
transport_path = 'quack'
4251
repo, client = self.setup_fake_client_and_repository(transport_path)
4252
client.add_expected_call(
4253
b'Repository.lock_write', (b'quack/', b''),
4254
b'success', (b'ok', b'token'))
4255
client.add_expected_call(
4256
b'Repository.pack', (b'quack/', b'token', b'False'),
4257
b'success', (b'ok',), )
4258
client.add_expected_call(
4259
b'Repository.unlock', (b'quack/', b'token', b'False'),
4260
b'success', (b'ok', ))
4261
repo.pack([b'hinta', b'hintb'])
4264
class TestRepositoryIterInventories(TestRemoteRepository):
4265
"""Test Repository.iter_inventories."""
4267
def _serialize_inv_delta(self, old_name, new_name, delta):
4268
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4269
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4271
def test_single_empty(self):
4272
transport_path = 'quack'
4273
repo, client = self.setup_fake_client_and_repository(transport_path)
4274
fmt = controldir.format_registry.get('2a')().repository_format
4276
stream = [('inventory-deltas', [
4277
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4278
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4279
client.add_expected_call(
4280
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4281
b'success', (b'ok', ),
4282
_stream_to_byte_stream(stream, fmt))
4283
ret = list(repo.iter_inventories([b"somerevid"]))
4284
self.assertLength(1, ret)
4286
self.assertEqual(b"somerevid", inv.revision_id)
4288
def test_empty(self):
4289
transport_path = 'quack'
4290
repo, client = self.setup_fake_client_and_repository(transport_path)
4291
ret = list(repo.iter_inventories([]))
4292
self.assertEqual(ret, [])
4294
def test_missing(self):
4295
transport_path = 'quack'
4296
repo, client = self.setup_fake_client_and_repository(transport_path)
4297
client.add_expected_call(
4298
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4299
b'success', (b'ok', ), iter([]))
4300
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(