53
65
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
58
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
60
from bzrlib.tests import (
62
split_suite_by_condition,
67
from ..bzr import groupcompress_repo, knitpack_repo
68
from ..revision import (
72
from ..sixish import (
77
from ..bzr.smart import medium, request
78
from ..bzr.smart.client import _SmartClient
79
from ..bzr.smart.repository import (
80
SmartServerRepositoryGetParentMap,
81
SmartServerRepositoryGetStream_1_19,
82
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
87
from .scenarios import load_tests_apply_scenarios
88
from ..transport.memory import MemoryTransport
89
from ..transport.remote import (
70
91
RemoteSSHTransport,
71
92
RemoteTCPTransport,
74
def load_tests(standard_tests, module, loader):
75
to_adapt, result = split_suite_by_condition(
76
standard_tests, condition_isinstance(BasicRemoteObjectTests))
77
smart_server_version_scenarios = [
96
load_tests = load_tests_apply_scenarios
99
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
104
test_server.SmartTCPServer_for_testing_v2_only}),
81
{'transport_server': test_server.SmartTCPServer_for_testing})]
82
return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
106
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
109
super(BasicRemoteObjectTests, self).setUp()
89
110
self.transport = self.get_transport()
90
111
# make a branch that can be opened over the smart transport
91
112
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
113
self.addCleanup(self.transport.disconnect)
97
115
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
116
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
117
self.assertIsInstance(b, BzrDir)
101
119
def test_open_remote_branch(self):
102
120
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
121
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
122
branch = b.open_branch()
105
123
self.assertIsInstance(branch, Branch)
431
446
def test_backwards_compat(self):
432
447
self.setup_smart_server_with_call_log()
433
a_dir = self.make_bzrdir('.')
448
a_dir = self.make_controldir('.')
434
449
self.reset_smart_call_log()
435
verb = 'BzrDir.cloning_metadir'
450
verb = b'BzrDir.cloning_metadir'
436
451
self.disable_verb(verb)
437
format = a_dir.cloning_metadir()
452
a_dir.cloning_metadir()
438
453
call_count = len([call for call in self.hpss_calls if
439
call.call.method == verb])
454
call.call.method == verb])
440
455
self.assertEqual(1, call_count)
442
457
def test_branch_reference(self):
443
458
transport = self.get_transport('quack')
444
459
referenced = self.make_branch('referenced')
445
expected = referenced.bzrdir.cloning_metadir()
460
expected = referenced.controldir.cloning_metadir()
446
461
client = FakeClient(transport.base)
447
462
client.add_expected_call(
448
'BzrDir.cloning_metadir', ('quack/', 'False'),
449
'error', ('BranchReference',)),
463
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
464
b'error', (b'BranchReference',)),
450
465
client.add_expected_call(
451
'BzrDir.open_branchV3', ('quack/',),
452
'success', ('ref', self.get_url('referenced'))),
453
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
455
result = a_bzrdir.cloning_metadir()
466
b'BzrDir.open_branchV3', (b'quack/',),
467
b'success', (b'ref', self.get_url('referenced').encode('utf-8'))),
468
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
470
result = a_controldir.cloning_metadir()
456
471
# We should have got a control dir matching the referenced branch.
457
472
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
458
self.assertEqual(expected._repository_format, result._repository_format)
473
self.assertEqual(expected._repository_format,
474
result._repository_format)
459
475
self.assertEqual(expected._branch_format, result._branch_format)
460
476
self.assertFinished(client)
462
478
def test_current_server(self):
463
479
transport = self.get_transport('.')
464
480
transport = transport.clone('quack')
465
self.make_bzrdir('quack')
481
self.make_controldir('quack')
466
482
client = FakeClient(transport.base)
467
reference_bzrdir_format = bzrdir.format_registry.get('default')()
483
reference_bzrdir_format = controldir.format_registry.get('default')()
468
484
control_name = reference_bzrdir_format.network_name()
469
485
client.add_expected_call(
470
'BzrDir.cloning_metadir', ('quack/', 'False'),
471
'success', (control_name, '', ('branch', ''))),
472
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
474
result = a_bzrdir.cloning_metadir()
486
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
487
b'success', (control_name, b'', (b'branch', b''))),
488
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
490
result = a_controldir.cloning_metadir()
475
491
# We should have got a reference control dir with default branch and
476
492
# repository formats.
477
493
# This pokes a little, just to be sure.
480
496
self.assertEqual(None, result._branch_format)
481
497
self.assertFinished(client)
499
def test_unknown(self):
500
transport = self.get_transport('quack')
501
referenced = self.make_branch('referenced')
502
referenced.controldir.cloning_metadir()
503
client = FakeClient(transport.base)
504
client.add_expected_call(
505
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
506
b'success', (b'unknown', b'unknown', (b'branch', b''))),
507
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
509
self.assertRaises(errors.UnknownFormatError,
510
a_controldir.cloning_metadir)
513
class TestBzrDirCheckoutMetaDir(TestRemote):
515
def test__get_checkout_format(self):
516
transport = MemoryTransport()
517
client = FakeClient(transport.base)
518
reference_bzrdir_format = controldir.format_registry.get('default')()
519
control_name = reference_bzrdir_format.network_name()
520
client.add_expected_call(
521
b'BzrDir.checkout_metadir', (b'quack/', ),
522
b'success', (control_name, b'', b''))
523
transport.mkdir('quack')
524
transport = transport.clone('quack')
525
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
527
result = a_controldir.checkout_metadir()
528
# We should have got a reference control dir with default branch and
529
# repository formats.
530
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
531
self.assertEqual(None, result._repository_format)
532
self.assertEqual(None, result._branch_format)
533
self.assertFinished(client)
535
def test_unknown_format(self):
536
transport = MemoryTransport()
537
client = FakeClient(transport.base)
538
client.add_expected_call(
539
b'BzrDir.checkout_metadir', (b'quack/',),
540
b'success', (b'dontknow', b'', b''))
541
transport.mkdir('quack')
542
transport = transport.clone('quack')
543
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
545
self.assertRaises(errors.UnknownFormatError,
546
a_controldir.checkout_metadir)
547
self.assertFinished(client)
550
class TestBzrDirGetBranches(TestRemote):
552
def test_get_branches(self):
553
transport = MemoryTransport()
554
client = FakeClient(transport.base)
555
reference_bzrdir_format = controldir.format_registry.get('default')()
556
branch_name = reference_bzrdir_format.get_branch_format().network_name()
557
client.add_success_response_with_body(
559
b"foo": (b"branch", branch_name),
560
b"": (b"branch", branch_name)}), b"success")
561
client.add_success_response(
562
b'ok', b'', b'no', b'no', b'no',
563
reference_bzrdir_format.repository_format.network_name())
564
client.add_error_response(b'NotStacked')
565
client.add_success_response(
566
b'ok', b'', b'no', b'no', b'no',
567
reference_bzrdir_format.repository_format.network_name())
568
client.add_error_response(b'NotStacked')
569
transport.mkdir('quack')
570
transport = transport.clone('quack')
571
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
573
result = a_controldir.get_branches()
574
self.assertEqual({"", "foo"}, set(result.keys()))
576
[('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
577
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
578
('call', b'Branch.get_stacked_on_url', (b'quack/', )),
579
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
580
('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
584
class TestBzrDirDestroyBranch(TestRemote):
586
def test_destroy_default(self):
587
transport = self.get_transport('quack')
588
self.make_branch('referenced')
589
client = FakeClient(transport.base)
590
client.add_expected_call(
591
b'BzrDir.destroy_branch', (b'quack/', ),
592
b'success', (b'ok',)),
593
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
595
a_controldir.destroy_branch()
596
self.assertFinished(client)
599
class TestBzrDirHasWorkingTree(TestRemote):
601
def test_has_workingtree(self):
602
transport = self.get_transport('quack')
603
client = FakeClient(transport.base)
604
client.add_expected_call(
605
b'BzrDir.has_workingtree', (b'quack/',),
606
b'success', (b'yes',)),
607
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
609
self.assertTrue(a_controldir.has_workingtree())
610
self.assertFinished(client)
612
def test_no_workingtree(self):
613
transport = self.get_transport('quack')
614
client = FakeClient(transport.base)
615
client.add_expected_call(
616
b'BzrDir.has_workingtree', (b'quack/',),
617
b'success', (b'no',)),
618
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
620
self.assertFalse(a_controldir.has_workingtree())
621
self.assertFinished(client)
624
class TestBzrDirDestroyRepository(TestRemote):
626
def test_destroy_repository(self):
627
transport = self.get_transport('quack')
628
client = FakeClient(transport.base)
629
client.add_expected_call(
630
b'BzrDir.destroy_repository', (b'quack/',),
631
b'success', (b'ok',)),
632
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
634
a_controldir.destroy_repository()
635
self.assertFinished(client)
484
638
class TestBzrDirOpen(TestRemote):
632
791
network_name = reference_format.network_name()
633
792
branch_network_name = self.get_branch_format().network_name()
634
793
client.add_expected_call(
635
'BzrDir.open_branchV3', ('~hello/',),
636
'success', ('branch', branch_network_name))
637
client.add_expected_call(
638
'BzrDir.find_repositoryV3', ('~hello/',),
639
'success', ('ok', '', 'no', 'no', 'no', network_name))
640
client.add_expected_call(
641
'Branch.get_stacked_on_url', ('~hello/',),
642
'error', ('NotStacked',))
643
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
645
result = bzrdir.open_branch()
794
b'BzrDir.open_branchV3', (b'~hello/',),
795
b'success', (b'branch', branch_network_name))
796
client.add_expected_call(
797
b'BzrDir.find_repositoryV3', (b'~hello/',),
798
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
799
client.add_expected_call(
800
b'Branch.get_stacked_on_url', (b'~hello/',),
801
b'error', (b'NotStacked',))
802
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
646
805
self.assertFinished(client)
648
def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
807
def check_open_repository(self, rich_root, subtrees,
808
external_lookup=b'no'):
649
809
reference_format = self.get_repo_format()
650
810
network_name = reference_format.network_name()
651
811
transport = MemoryTransport()
652
812
transport.mkdir('quack')
653
813
transport = transport.clone('quack')
655
rich_response = 'yes'
815
rich_response = b'yes'
817
rich_response = b'no'
659
subtree_response = 'yes'
819
subtree_response = b'yes'
661
subtree_response = 'no'
821
subtree_response = b'no'
662
822
client = FakeClient(transport.base)
663
823
client.add_success_response(
664
'ok', '', rich_response, subtree_response, external_lookup,
824
b'ok', b'', rich_response, subtree_response, external_lookup,
666
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
826
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
828
result = bzrdir.open_repository()
669
829
self.assertEqual(
670
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
830
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
672
832
self.assertIsInstance(result, RemoteRepository)
673
self.assertEqual(bzrdir, result.bzrdir)
833
self.assertEqual(bzrdir, result.controldir)
674
834
self.assertEqual(rich_root, result._format.rich_root_data)
675
835
self.assertEqual(subtrees, result._format.supports_tree_reference)
706
868
transport = transport.clone('quack')
707
869
self.make_repository('quack')
708
870
client = FakeClient(transport.base)
709
reference_bzrdir_format = bzrdir.format_registry.get('default')()
710
reference_format = reference_bzrdir_format.get_branch_format()
711
network_name = reference_format.network_name()
712
reference_repo_fmt = reference_bzrdir_format.repository_format
713
reference_repo_name = reference_repo_fmt.network_name()
714
client.add_expected_call(
715
'BzrDir.create_branch', ('quack/', network_name),
716
'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
reference_repo_name))
718
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
branch = a_bzrdir.create_branch()
871
reference_bzrdir_format = controldir.format_registry.get('default')()
872
reference_format = reference_bzrdir_format.get_branch_format()
873
network_name = reference_format.network_name()
874
reference_repo_fmt = reference_bzrdir_format.repository_format
875
reference_repo_name = reference_repo_fmt.network_name()
876
client.add_expected_call(
877
b'BzrDir.create_branch', (b'quack/', network_name),
878
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
879
reference_repo_name))
880
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
882
branch = a_controldir.create_branch()
883
# We should have got a remote branch
884
self.assertIsInstance(branch, remote.RemoteBranch)
885
# its format should have the settings from the response
886
format = branch._format
887
self.assertEqual(network_name, format.network_name())
889
def test_already_open_repo_and_reused_medium(self):
890
"""Bug 726584: create_branch(..., repository=repo) should work
891
regardless of what the smart medium's base URL is.
893
self.transport_server = test_server.SmartTCPServer_for_testing
894
transport = self.get_transport('.')
895
repo = self.make_repository('quack')
896
# Client's medium rooted a transport root (not at the bzrdir)
897
client = FakeClient(transport.base)
898
transport = transport.clone('quack')
899
reference_bzrdir_format = controldir.format_registry.get('default')()
900
reference_format = reference_bzrdir_format.get_branch_format()
901
network_name = reference_format.network_name()
902
reference_repo_fmt = reference_bzrdir_format.repository_format
903
reference_repo_name = reference_repo_fmt.network_name()
904
client.add_expected_call(
905
b'BzrDir.create_branch', (b'extra/quack/', network_name),
906
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
907
reference_repo_name))
908
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
910
branch = a_controldir.create_branch(repository=repo)
721
911
# We should have got a remote branch
722
912
self.assertIsInstance(branch, remote.RemoteBranch)
723
913
# its format should have the settings from the response
772
962
server_url = 'bzr://example.com/'
773
963
self.permit_url(server_url)
774
964
client = FakeClient(server_url)
775
client.add_unknown_method_response('BzrDir.find_repositoryV3')
776
client.add_unknown_method_response('BzrDir.find_repositoryV2')
777
client.add_success_response('ok', '', 'no', 'no')
965
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
966
client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
967
client.add_success_response(b'ok', b'', b'no', b'no')
778
968
# A real repository instance will be created to determine the network
780
970
client.add_success_response_with_body(
781
"Bazaar-NG meta directory, format 1\n", 'ok')
971
b"Bazaar-NG meta directory, format 1\n", b'ok')
972
client.add_success_response(b'stat', b'0', b'65535')
782
973
client.add_success_response_with_body(
783
reference_format.get_format_string(), 'ok')
974
reference_format.get_format_string(), b'ok')
784
975
# PackRepository wants to do a stat
785
client.add_success_response('stat', '0', '65535')
976
client.add_success_response(b'stat', b'0', b'65535')
786
977
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
788
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
979
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
790
981
repo = bzrdir.open_repository()
791
982
self.assertEqual(
792
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
793
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
794
('call', 'BzrDir.find_repository', ('quack/',)),
795
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
796
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
797
('call', 'stat', ('/quack/.bzr/repository',)),
983
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
984
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
985
('call', b'BzrDir.find_repository', (b'quack/',)),
986
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
987
('call', b'stat', (b'/quack/.bzr',)),
988
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
989
('call', b'stat', (b'/quack/.bzr/repository',)),
800
992
self.assertEqual(network_name, repo._format.network_name())
806
998
server_url = 'bzr://example.com/'
807
999
self.permit_url(server_url)
808
1000
client = FakeClient(server_url)
809
client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
client.add_success_response('ok', '', 'no', 'no', 'no')
1001
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
1002
client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
1003
# A real repository instance will be created to determine the network
813
1005
client.add_success_response_with_body(
814
"Bazaar-NG meta directory, format 1\n", 'ok')
1006
b"Bazaar-NG meta directory, format 1\n", b'ok')
1007
client.add_success_response(b'stat', b'0', b'65535')
815
1008
client.add_success_response_with_body(
816
reference_format.get_format_string(), 'ok')
1009
reference_format.get_format_string(), b'ok')
817
1010
# PackRepository wants to do a stat
818
client.add_success_response('stat', '0', '65535')
1011
client.add_success_response(b'stat', b'0', b'65535')
819
1012
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
821
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
1014
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
823
1016
repo = bzrdir.open_repository()
824
1017
self.assertEqual(
825
[('call', 'BzrDir.find_repositoryV3', ('quack/',)),
826
('call', 'BzrDir.find_repositoryV2', ('quack/',)),
827
('call_expecting_body', 'get', ('/quack/.bzr/branch-format',)),
828
('call_expecting_body', 'get', ('/quack/.bzr/repository/format',)),
829
('call', 'stat', ('/quack/.bzr/repository',)),
1018
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1019
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1020
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1021
('call', b'stat', (b'/quack/.bzr',)),
1022
('call_expecting_body', b'get',
1023
(b'/quack/.bzr/repository/format',)),
1024
('call', b'stat', (b'/quack/.bzr/repository',)),
832
1027
self.assertEqual(network_name, repo._format.network_name())
853
1049
def test_success(self):
854
1050
"""Simple test for typical successful call."""
855
fmt = bzrdir.RemoteBzrDirFormat()
1051
fmt = RemoteBzrDirFormat()
856
1052
default_format_name = BzrDirFormat.get_default_format().network_name()
857
1053
transport = self.get_transport()
858
1054
client = FakeClient(transport.base)
859
1055
client.add_expected_call(
860
'BzrDirFormat.initialize_ex_1.16',
861
(default_format_name, 'path', 'False', 'False', 'False', '',
862
'', '', '', 'False'),
864
('.', 'no', 'no', 'yes', 'repo fmt', 'repo bzrdir fmt',
865
'bzrdir fmt', 'False', '', '', 'repo lock token'))
1056
b'BzrDirFormat.initialize_ex_1.16',
1057
(default_format_name, b'path', b'False', b'False', b'False', b'',
1058
b'', b'', b'', b'False'),
1060
(b'.', b'no', b'no', b'yes', b'repo fmt', b'repo bzrdir fmt',
1061
b'bzrdir fmt', b'False', b'', b'', b'repo lock token'))
866
1062
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
867
1063
# it's currently hard to test that without supplying a real remote
868
1064
# transport connected to a real server.
869
result = fmt._initialize_on_transport_ex_rpc(client, 'path',
870
transport, False, False, False, None, None, None, None, False)
1065
fmt._initialize_on_transport_ex_rpc(
1066
client, b'path', transport, False, False, False, None, None, None,
871
1068
self.assertFinished(client)
873
1070
def test_error(self):
874
1071
"""Error responses are translated, e.g. 'PermissionDenied' raises the
875
1072
corresponding error from the client.
877
fmt = bzrdir.RemoteBzrDirFormat()
1074
fmt = RemoteBzrDirFormat()
878
1075
default_format_name = BzrDirFormat.get_default_format().network_name()
879
1076
transport = self.get_transport()
880
1077
client = FakeClient(transport.base)
881
1078
client.add_expected_call(
882
'BzrDirFormat.initialize_ex_1.16',
883
(default_format_name, 'path', 'False', 'False', 'False', '',
884
'', '', '', 'False'),
886
('PermissionDenied', 'path', 'extra info'))
1079
b'BzrDirFormat.initialize_ex_1.16',
1080
(default_format_name, b'path', b'False', b'False', b'False', b'',
1081
b'', b'', b'', b'False'),
1083
(b'PermissionDenied', b'path', b'extra info'))
887
1084
# XXX: It would be better to call fmt.initialize_on_transport_ex, but
888
1085
# it's currently hard to test that without supplying a real remote
889
1086
# transport connected to a real server.
890
err = self.assertRaises(errors.PermissionDenied,
891
fmt._initialize_on_transport_ex_rpc, client, 'path', transport,
1087
err = self.assertRaises(
1088
errors.PermissionDenied,
1089
fmt._initialize_on_transport_ex_rpc, client, b'path', transport,
892
1090
False, False, False, None, None, None, None, False)
893
1091
self.assertEqual('path', err.path)
894
1092
self.assertEqual(': extra info', err.extra)
1101
1353
transport = MemoryTransport()
1102
1354
client = FakeClient(transport.base)
1103
1355
client.add_expected_call(
1104
'Branch.get_stacked_on_url', ('quack/',),
1105
'error', ('NotStacked',))
1356
b'Branch.get_stacked_on_url', (b'quack/',),
1357
b'error', (b'NotStacked',))
1106
1358
client.add_expected_call(
1107
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1359
b'Branch.set_tags_bytes', (b'quack/',
1360
b'branch token', b'repo token'),
1109
1362
transport.mkdir('quack')
1110
1363
transport = transport.clone('quack')
1111
1364
branch = self.make_remote_branch(transport, client)
1112
1365
self.lock_remote_branch(branch)
1113
branch._set_tags_bytes('tags bytes')
1366
branch._set_tags_bytes(b'tags bytes')
1114
1367
self.assertFinished(client)
1115
self.assertEqual('tags bytes', client._calls[-1][-1])
1368
self.assertEqual(b'tags bytes', client._calls[-1][-1])
1117
1370
def test_backwards_compatible(self):
1118
1371
transport = MemoryTransport()
1119
1372
client = FakeClient(transport.base)
1120
1373
client.add_expected_call(
1121
'Branch.get_stacked_on_url', ('quack/',),
1122
'error', ('NotStacked',))
1374
b'Branch.get_stacked_on_url', (b'quack/',),
1375
b'error', (b'NotStacked',))
1123
1376
client.add_expected_call(
1124
'Branch.set_tags_bytes', ('quack/', 'branch token', 'repo token'),
1125
'unknown', ('Branch.set_tags_bytes',))
1377
b'Branch.set_tags_bytes', (b'quack/',
1378
b'branch token', b'repo token'),
1379
b'unknown', (b'Branch.set_tags_bytes',))
1126
1380
transport.mkdir('quack')
1127
1381
transport = transport.clone('quack')
1128
1382
branch = self.make_remote_branch(transport, client)
1129
1383
self.lock_remote_branch(branch)
1130
1385
class StubRealBranch(object):
1131
1386
def __init__(self):
1132
1387
self.calls = []
1133
1389
def _set_tags_bytes(self, bytes):
1134
1390
self.calls.append(('set_tags_bytes', bytes))
1135
1391
real_branch = StubRealBranch()
1136
1392
branch._real_branch = real_branch
1137
branch._set_tags_bytes('tags bytes')
1393
branch._set_tags_bytes(b'tags bytes')
1138
1394
# Call a second time, to exercise the 'remote version already inferred'
1140
branch._set_tags_bytes('tags bytes')
1141
self.assertFinished(client)
1143
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1396
branch._set_tags_bytes(b'tags bytes')
1397
self.assertFinished(client)
1399
[('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
1402
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1404
def test_uses_last_revision_info_and_tags_by_default(self):
1405
transport = MemoryTransport()
1406
client = FakeClient(transport.base)
1407
client.add_expected_call(
1408
b'Branch.get_stacked_on_url', (b'quack/',),
1409
b'error', (b'NotStacked',))
1410
client.add_expected_call(
1411
b'Branch.last_revision_info', (b'quack/',),
1412
b'success', (b'ok', b'1', b'rev-tip'))
1413
client.add_expected_call(
1414
b'Branch.get_config_file', (b'quack/',),
1415
b'success', (b'ok',), b'')
1416
transport.mkdir('quack')
1417
transport = transport.clone('quack')
1418
branch = self.make_remote_branch(transport, client)
1419
result = branch.heads_to_fetch()
1420
self.assertFinished(client)
1421
self.assertEqual(({b'rev-tip'}, set()), result)
1423
def test_uses_last_revision_info_and_tags_when_set(self):
1424
transport = MemoryTransport()
1425
client = FakeClient(transport.base)
1426
client.add_expected_call(
1427
b'Branch.get_stacked_on_url', (b'quack/',),
1428
b'error', (b'NotStacked',))
1429
client.add_expected_call(
1430
b'Branch.last_revision_info', (b'quack/',),
1431
b'success', (b'ok', b'1', b'rev-tip'))
1432
client.add_expected_call(
1433
b'Branch.get_config_file', (b'quack/',),
1434
b'success', (b'ok',), b'branch.fetch_tags = True')
1435
# XXX: this will break if the default format's serialization of tags
1436
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1437
client.add_expected_call(
1438
b'Branch.get_tags_bytes', (b'quack/',),
1439
b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
1440
transport.mkdir('quack')
1441
transport = transport.clone('quack')
1442
branch = self.make_remote_branch(transport, client)
1443
result = branch.heads_to_fetch()
1444
self.assertFinished(client)
1446
({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
1448
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1449
transport = MemoryTransport()
1450
client = FakeClient(transport.base)
1451
client.add_expected_call(
1452
b'Branch.get_stacked_on_url', (b'quack/',),
1453
b'error', (b'NotStacked',))
1454
client.add_expected_call(
1455
b'Branch.heads_to_fetch', (b'quack/',),
1456
b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
1457
transport.mkdir('quack')
1458
transport = transport.clone('quack')
1459
branch = self.make_remote_branch(transport, client)
1460
branch._format._use_default_local_heads_to_fetch = lambda: False
1461
result = branch.heads_to_fetch()
1462
self.assertFinished(client)
1463
self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
1465
def make_branch_with_tags(self):
1466
self.setup_smart_server_with_call_log()
1467
# Make a branch with a single revision.
1468
builder = self.make_branch_builder('foo')
1469
builder.start_series()
1470
builder.build_snapshot(None, [
1471
('add', ('', b'root-id', 'directory', ''))],
1473
builder.finish_series()
1474
branch = builder.get_branch()
1475
# Add two tags to that branch
1476
branch.tags.set_tag('tag-1', b'rev-1')
1477
branch.tags.set_tag('tag-2', b'rev-2')
1480
def test_backwards_compatible(self):
1481
br = self.make_branch_with_tags()
1482
br.get_config_stack().set('branch.fetch_tags', True)
1483
self.addCleanup(br.lock_read().unlock)
1484
# Disable the heads_to_fetch verb
1485
verb = b'Branch.heads_to_fetch'
1486
self.disable_verb(verb)
1487
self.reset_smart_call_log()
1488
result = br.heads_to_fetch()
1489
self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
1491
[b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
1492
[call.call.method for call in self.hpss_calls])
1494
def test_backwards_compatible_no_tags(self):
1495
br = self.make_branch_with_tags()
1496
br.get_config_stack().set('branch.fetch_tags', False)
1497
self.addCleanup(br.lock_read().unlock)
1498
# Disable the heads_to_fetch verb
1499
verb = b'Branch.heads_to_fetch'
1500
self.disable_verb(verb)
1501
self.reset_smart_call_log()
1502
result = br.heads_to_fetch()
1503
self.assertEqual(({b'tip'}, set()), result)
1505
[b'Branch.last_revision_info'],
1506
[call.call.method for call in self.hpss_calls])
1146
1509
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1190
1553
# doesn't just open in - this test probably needs to be rewritten using
1191
1554
# a spawn()ed server.
1192
1555
stacked_branch = self.make_branch('stacked', format='1.9')
1193
memory_branch = self.make_branch('base', format='1.9')
1556
self.make_branch('base', format='1.9')
1194
1557
vfs_url = self.get_vfs_only_url('base')
1195
1558
stacked_branch.set_stacked_on_url(vfs_url)
1196
transport = stacked_branch.bzrdir.root_transport
1559
transport = stacked_branch.controldir.root_transport
1197
1560
client = FakeClient(transport.base)
1198
1561
client.add_expected_call(
1199
'Branch.get_stacked_on_url', ('stacked/',),
1200
'success', ('ok', vfs_url))
1562
b'Branch.get_stacked_on_url', (b'stacked/',),
1563
b'success', (b'ok', vfs_url.encode('utf-8')))
1201
1564
# XXX: Multiple calls are bad, this second call documents what is
1203
1566
client.add_expected_call(
1204
'Branch.get_stacked_on_url', ('stacked/',),
1205
'success', ('ok', vfs_url))
1206
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
1567
b'Branch.get_stacked_on_url', (b'stacked/',),
1568
b'success', (b'ok', vfs_url.encode('utf-8')))
1569
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
1208
1571
repo_fmt = remote.RemoteRepositoryFormat()
1209
1572
repo_fmt._custom_format = stacked_branch.repository._format
1210
1573
branch = RemoteBranch(bzrdir, RemoteRepository(bzrdir, repo_fmt),
1212
1575
result = branch.get_stacked_on_url()
1213
1576
self.assertEqual(vfs_url, result)
1215
1578
def test_backwards_compatible(self):
1216
1579
# like with bzr1.6 with no Branch.get_stacked_on_url rpc
1217
base_branch = self.make_branch('base', format='1.6')
1580
self.make_branch('base', format='1.6')
1218
1581
stacked_branch = self.make_branch('stacked', format='1.6')
1219
1582
stacked_branch.set_stacked_on_url('../base')
1220
1583
client = FakeClient(self.get_url())
1221
1584
branch_network_name = self.get_branch_format().network_name()
1222
1585
client.add_expected_call(
1223
'BzrDir.open_branchV3', ('stacked/',),
1224
'success', ('branch', branch_network_name))
1586
b'BzrDir.open_branchV3', (b'stacked/',),
1587
b'success', (b'branch', branch_network_name))
1225
1588
client.add_expected_call(
1226
'BzrDir.find_repositoryV3', ('stacked/',),
1227
'success', ('ok', '', 'no', 'no', 'yes',
1228
stacked_branch.repository._format.network_name()))
1589
b'BzrDir.find_repositoryV3', (b'stacked/',),
1590
b'success', (b'ok', b'', b'no', b'no', b'yes',
1591
stacked_branch.repository._format.network_name()))
1229
1592
# called twice, once from constructor and then again by us
1230
1593
client.add_expected_call(
1231
'Branch.get_stacked_on_url', ('stacked/',),
1232
'unknown', ('Branch.get_stacked_on_url',))
1594
b'Branch.get_stacked_on_url', (b'stacked/',),
1595
b'unknown', (b'Branch.get_stacked_on_url',))
1233
1596
client.add_expected_call(
1234
'Branch.get_stacked_on_url', ('stacked/',),
1235
'unknown', ('Branch.get_stacked_on_url',))
1597
b'Branch.get_stacked_on_url', (b'stacked/',),
1598
b'unknown', (b'Branch.get_stacked_on_url',))
1236
1599
# this will also do vfs access, but that goes direct to the transport
1237
1600
# and isn't seen by the FakeClient.
1238
1601
bzrdir = RemoteBzrDir(self.get_transport('stacked'),
1239
remote.RemoteBzrDirFormat(), _client=client)
1602
RemoteBzrDirFormat(), _client=client)
1240
1603
branch = bzrdir.open_branch()
1241
1604
result = branch.get_stacked_on_url()
1242
1605
self.assertEqual('../base', result)
1292
1655
client = FakeClient(transport.base)
1293
1656
client.add_expected_call(
1294
'Branch.get_stacked_on_url', ('branch/',),
1295
'error', ('NotStacked',))
1296
client.add_expected_call(
1297
'Branch.lock_write', ('branch/', '', ''),
1298
'success', ('ok', 'branch token', 'repo token'))
1299
client.add_expected_call(
1300
'Branch.last_revision_info',
1302
'success', ('ok', '0', 'null:'))
1303
client.add_expected_call(
1304
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'null:',),
1306
client.add_expected_call(
1307
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1657
b'Branch.get_stacked_on_url', (b'branch/',),
1658
b'error', (b'NotStacked',))
1659
client.add_expected_call(
1660
b'Branch.lock_write', (b'branch/', b'', b''),
1661
b'success', (b'ok', b'branch token', b'repo token'))
1662
client.add_expected_call(
1663
b'Branch.last_revision_info',
1665
b'success', (b'ok', b'0', b'null:'))
1666
client.add_expected_call(
1667
b'Branch.set_last_revision', (b'branch/',
1668
b'branch token', b'repo token', b'null:',),
1669
b'success', (b'ok',))
1670
client.add_expected_call(
1671
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1672
b'success', (b'ok',))
1309
1673
branch = self.make_remote_branch(transport, client)
1310
# This is a hack to work around the problem that RemoteBranch currently
1311
# unnecessarily invokes _ensure_real upon a call to lock_write.
1312
branch._ensure_real = lambda: None
1313
1674
branch.lock_write()
1314
result = branch.set_revision_history([])
1675
result = branch._set_last_revision(NULL_REVISION)
1315
1676
branch.unlock()
1316
1677
self.assertEqual(None, result)
1317
1678
self.assertFinished(client)
1319
1680
def test_set_nonempty(self):
1320
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1681
# set_last_revision_info(N, rev-idN) is translated to calling
1321
1682
# Branch.set_last_revision(path, rev-idN) on the wire.
1322
1683
transport = MemoryTransport()
1323
1684
transport.mkdir('branch')
1326
1687
client = FakeClient(transport.base)
1327
1688
client.add_expected_call(
1328
'Branch.get_stacked_on_url', ('branch/',),
1329
'error', ('NotStacked',))
1330
client.add_expected_call(
1331
'Branch.lock_write', ('branch/', '', ''),
1332
'success', ('ok', 'branch token', 'repo token'))
1333
client.add_expected_call(
1334
'Branch.last_revision_info',
1336
'success', ('ok', '0', 'null:'))
1338
encoded_body = bz2.compress('\n'.join(lines))
1339
client.add_success_response_with_body(encoded_body, 'ok')
1340
client.add_expected_call(
1341
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id2',),
1343
client.add_expected_call(
1344
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1689
b'Branch.get_stacked_on_url', (b'branch/',),
1690
b'error', (b'NotStacked',))
1691
client.add_expected_call(
1692
b'Branch.lock_write', (b'branch/', b'', b''),
1693
b'success', (b'ok', b'branch token', b'repo token'))
1694
client.add_expected_call(
1695
b'Branch.last_revision_info',
1697
b'success', (b'ok', b'0', b'null:'))
1698
lines = [b'rev-id2']
1699
encoded_body = bz2.compress(b'\n'.join(lines))
1700
client.add_success_response_with_body(encoded_body, b'ok')
1701
client.add_expected_call(
1702
b'Branch.set_last_revision', (b'branch/',
1703
b'branch token', b'repo token', b'rev-id2',),
1704
b'success', (b'ok',))
1705
client.add_expected_call(
1706
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1707
b'success', (b'ok',))
1346
1708
branch = self.make_remote_branch(transport, client)
1347
# This is a hack to work around the problem that RemoteBranch currently
1348
# unnecessarily invokes _ensure_real upon a call to lock_write.
1349
branch._ensure_real = lambda: None
1350
1709
# Lock the branch, reset the record of remote calls.
1351
1710
branch.lock_write()
1352
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1711
result = branch._set_last_revision(b'rev-id2')
1353
1712
branch.unlock()
1354
1713
self.assertEqual(None, result)
1355
1714
self.assertFinished(client)
1361
1720
# A response of 'NoSuchRevision' is translated into an exception.
1362
1721
client = FakeClient(transport.base)
1363
1722
client.add_expected_call(
1364
'Branch.get_stacked_on_url', ('branch/',),
1365
'error', ('NotStacked',))
1366
client.add_expected_call(
1367
'Branch.lock_write', ('branch/', '', ''),
1368
'success', ('ok', 'branch token', 'repo token'))
1369
client.add_expected_call(
1370
'Branch.last_revision_info',
1372
'success', ('ok', '0', 'null:'))
1723
b'Branch.get_stacked_on_url', (b'branch/',),
1724
b'error', (b'NotStacked',))
1725
client.add_expected_call(
1726
b'Branch.lock_write', (b'branch/', b'', b''),
1727
b'success', (b'ok', b'branch token', b'repo token'))
1728
client.add_expected_call(
1729
b'Branch.last_revision_info',
1731
b'success', (b'ok', b'0', b'null:'))
1373
1732
# get_graph calls to construct the revision history, for the set_rh
1376
encoded_body = bz2.compress('\n'.join(lines))
1377
client.add_success_response_with_body(encoded_body, 'ok')
1378
client.add_expected_call(
1379
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1380
'error', ('NoSuchRevision', 'rev-id'))
1381
client.add_expected_call(
1382
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1735
encoded_body = bz2.compress(b'\n'.join(lines))
1736
client.add_success_response_with_body(encoded_body, b'ok')
1737
client.add_expected_call(
1738
b'Branch.set_last_revision', (b'branch/',
1739
b'branch token', b'repo token', b'rev-id',),
1740
b'error', (b'NoSuchRevision', b'rev-id'))
1741
client.add_expected_call(
1742
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1743
b'success', (b'ok',))
1385
1745
branch = self.make_remote_branch(transport, client)
1386
1746
branch.lock_write()
1387
1747
self.assertRaises(
1388
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1748
errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1749
branch.unlock()
1390
1750
self.assertFinished(client)
1400
1760
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1761
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1762
client.add_expected_call(
1403
'Branch.get_stacked_on_url', ('branch/',),
1404
'error', ('NotStacked',))
1405
client.add_expected_call(
1406
'Branch.lock_write', ('branch/', '', ''),
1407
'success', ('ok', 'branch token', 'repo token'))
1408
client.add_expected_call(
1409
'Branch.last_revision_info',
1411
'success', ('ok', '0', 'null:'))
1413
encoded_body = bz2.compress('\n'.join(lines))
1414
client.add_success_response_with_body(encoded_body, 'ok')
1415
client.add_expected_call(
1416
'Branch.set_last_revision', ('branch/', 'branch token', 'repo token', 'rev-id',),
1417
'error', ('TipChangeRejected', rejection_msg_utf8))
1418
client.add_expected_call(
1419
'Branch.unlock', ('branch/', 'branch token', 'repo token'),
1763
b'Branch.get_stacked_on_url', (b'branch/',),
1764
b'error', (b'NotStacked',))
1765
client.add_expected_call(
1766
b'Branch.lock_write', (b'branch/', b'', b''),
1767
b'success', (b'ok', b'branch token', b'repo token'))
1768
client.add_expected_call(
1769
b'Branch.last_revision_info',
1771
b'success', (b'ok', b'0', b'null:'))
1773
encoded_body = bz2.compress(b'\n'.join(lines))
1774
client.add_success_response_with_body(encoded_body, b'ok')
1775
client.add_expected_call(
1776
b'Branch.set_last_revision', (b'branch/',
1777
b'branch token', b'repo token', b'rev-id',),
1778
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1779
client.add_expected_call(
1780
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1781
b'success', (b'ok',))
1421
1782
branch = self.make_remote_branch(transport, client)
1422
branch._ensure_real = lambda: None
1423
1783
branch.lock_write()
1424
1784
# The 'TipChangeRejected' error response triggered by calling
1425
# set_revision_history causes a TipChangeRejected exception.
1785
# set_last_revision_info causes a TipChangeRejected exception.
1426
1786
err = self.assertRaises(
1427
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1787
errors.TipChangeRejected,
1788
branch._set_last_revision, b'rev-id')
1428
1789
# The UTF-8 message from the response has been decoded into a unicode
1430
self.assertIsInstance(err.msg, unicode)
1791
self.assertIsInstance(err.msg, text_type)
1431
1792
self.assertEqual(rejection_msg_unicode, err.msg)
1432
1793
branch.unlock()
1433
1794
self.assertFinished(client)
1652
2016
branch.unlock()
1653
2017
self.assertFinished(client)
2019
def test_set_option_with_dict(self):
2020
client = FakeClient()
2021
client.add_expected_call(
2022
b'Branch.get_stacked_on_url', (b'memory:///',),
2023
b'error', (b'NotStacked',),)
2024
client.add_expected_call(
2025
b'Branch.lock_write', (b'memory:///', b'', b''),
2026
b'success', (b'ok', b'branch token', b'repo token'))
2027
encoded_dict_value = b'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
2028
client.add_expected_call(
2029
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2030
b'repo token', encoded_dict_value, b'foo', b''),
2032
client.add_expected_call(
2033
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2034
b'success', (b'ok',))
2035
transport = MemoryTransport()
2036
branch = self.make_remote_branch(transport, client)
2038
config = branch._get_config()
2040
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
2043
self.assertFinished(client)
2045
def test_set_option_with_bool(self):
2046
client = FakeClient()
2047
client.add_expected_call(
2048
b'Branch.get_stacked_on_url', (b'memory:///',),
2049
b'error', (b'NotStacked',),)
2050
client.add_expected_call(
2051
b'Branch.lock_write', (b'memory:///', b'', b''),
2052
b'success', (b'ok', b'branch token', b'repo token'))
2053
client.add_expected_call(
2054
b'Branch.set_config_option', (b'memory:///', b'branch token',
2055
b'repo token', b'True', b'foo', b''),
2057
client.add_expected_call(
2058
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2059
b'success', (b'ok',))
2060
transport = MemoryTransport()
2061
branch = self.make_remote_branch(transport, client)
2063
config = branch._get_config()
2064
config.set_option(True, 'foo')
2066
self.assertFinished(client)
1655
2068
def test_backwards_compat_set_option(self):
1656
2069
self.setup_smart_server_with_call_log()
1657
2070
branch = self.make_branch('.')
1658
verb = 'Branch.set_config_option'
2071
verb = b'Branch.set_config_option'
1659
2072
self.disable_verb(verb)
1660
2073
branch.lock_write()
1661
2074
self.addCleanup(branch.unlock)
1662
2075
self.reset_smart_call_log()
1663
2076
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2077
self.assertLength(11, self.hpss_calls)
1665
2078
self.assertEqual('value', branch._get_config().get_option('name'))
2080
def test_backwards_compat_set_option_with_dict(self):
2081
self.setup_smart_server_with_call_log()
2082
branch = self.make_branch('.')
2083
verb = b'Branch.set_config_option_dict'
2084
self.disable_verb(verb)
2086
self.addCleanup(branch.unlock)
2087
self.reset_smart_call_log()
2088
config = branch._get_config()
2089
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2090
config.set_option(value_dict, 'name')
2091
self.assertLength(11, self.hpss_calls)
2092
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2095
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2097
def test_get_branch_conf(self):
2098
# in an empty branch we decode the response properly
2099
client = FakeClient()
2100
client.add_expected_call(
2101
b'Branch.get_stacked_on_url', (b'memory:///',),
2102
b'error', (b'NotStacked',),)
2103
client.add_success_response_with_body(b'# config file body', b'ok')
2104
transport = MemoryTransport()
2105
branch = self.make_remote_branch(transport, client)
2106
config = branch.get_config_stack()
2108
config.get("log_format")
2110
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2111
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
2114
def test_set_branch_conf(self):
2115
client = FakeClient()
2116
client.add_expected_call(
2117
b'Branch.get_stacked_on_url', (b'memory:///',),
2118
b'error', (b'NotStacked',),)
2119
client.add_expected_call(
2120
b'Branch.lock_write', (b'memory:///', b'', b''),
2121
b'success', (b'ok', b'branch token', b'repo token'))
2122
client.add_expected_call(
2123
b'Branch.get_config_file', (b'memory:///', ),
2124
b'success', (b'ok', ), b"# line 1\n")
2125
client.add_expected_call(
2126
b'Branch.get_config_file', (b'memory:///', ),
2127
b'success', (b'ok', ), b"# line 1\n")
2128
client.add_expected_call(
2129
b'Branch.put_config_file', (b'memory:///', b'branch token',
2131
b'success', (b'ok',))
2132
client.add_expected_call(
2133
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2134
b'success', (b'ok',))
2135
transport = MemoryTransport()
2136
branch = self.make_remote_branch(transport, client)
2138
config = branch.get_config_stack()
2139
config.set('email', 'The Dude <lebowski@example.com>')
2141
self.assertFinished(client)
2143
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2144
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2145
('call_expecting_body', b'Branch.get_config_file',
2147
('call_expecting_body', b'Branch.get_config_file',
2149
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2150
(b'memory:///', b'branch token', b'repo token'),
2151
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2152
('call', b'Branch.unlock',
2153
(b'memory:///', b'branch token', b'repo token'))],
1668
2157
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2172
self.assertFinished(client)
2175
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2177
def test_simple(self):
2178
transport = MemoryTransport()
2179
client = FakeClient(transport.base)
2180
client.add_expected_call(
2181
b'Branch.get_stacked_on_url', (b'quack/',),
2182
b'error', (b'NotStacked',),)
2183
client.add_expected_call(
2184
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2185
b'success', (b'ok', b'0',),)
2186
client.add_expected_call(
2187
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2188
b'error', (b'NoSuchRevision', b'unknown',),)
2189
transport.mkdir('quack')
2190
transport = transport.clone('quack')
2191
branch = self.make_remote_branch(transport, client)
2192
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2193
self.assertRaises(errors.NoSuchRevision,
2194
branch.revision_id_to_revno, b'unknown')
2195
self.assertFinished(client)
2197
def test_dotted(self):
2198
transport = MemoryTransport()
2199
client = FakeClient(transport.base)
2200
client.add_expected_call(
2201
b'Branch.get_stacked_on_url', (b'quack/',),
2202
b'error', (b'NotStacked',),)
2203
client.add_expected_call(
2204
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2205
b'success', (b'ok', b'0',),)
2206
client.add_expected_call(
2207
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2208
b'error', (b'NoSuchRevision', b'unknown',),)
2209
transport.mkdir('quack')
2210
transport = transport.clone('quack')
2211
branch = self.make_remote_branch(transport, client)
2212
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2213
self.assertRaises(errors.NoSuchRevision,
2214
branch.revision_id_to_dotted_revno, b'unknown')
2215
self.assertFinished(client)
2217
def test_ghost_revid(self):
2218
transport = MemoryTransport()
2219
client = FakeClient(transport.base)
2220
client.add_expected_call(
2221
b'Branch.get_stacked_on_url', (b'quack/',),
2222
b'error', (b'NotStacked',),)
2223
# Some older versions of bzr/brz didn't explicitly return
2224
# GhostRevisionsHaveNoRevno
2225
client.add_expected_call(
2226
b'Branch.revision_id_to_revno', (b'quack/', b'revid'),
2227
b'error', (b'error', b'GhostRevisionsHaveNoRevno',
2228
b'The reivison {revid} was not found because there was '
2229
b'a ghost at {ghost-revid}'))
2230
client.add_expected_call(
2231
b'Branch.revision_id_to_revno', (b'quack/', b'revid'),
2232
b'error', (b'GhostRevisionsHaveNoRevno', b'revid', b'ghost-revid',))
2233
transport.mkdir('quack')
2234
transport = transport.clone('quack')
2235
branch = self.make_remote_branch(transport, client)
2236
self.assertRaises(errors.GhostRevisionsHaveNoRevno,
2237
branch.revision_id_to_dotted_revno, b'revid')
2238
self.assertRaises(errors.GhostRevisionsHaveNoRevno,
2239
branch.revision_id_to_dotted_revno, b'revid')
2240
self.assertFinished(client)
2242
def test_dotted_no_smart_verb(self):
2243
self.setup_smart_server_with_call_log()
2244
branch = self.make_branch('.')
2245
self.disable_verb(b'Branch.revision_id_to_revno')
2246
self.reset_smart_call_log()
2247
self.assertEqual((0, ),
2248
branch.revision_id_to_dotted_revno(b'null:'))
2249
self.assertLength(8, self.hpss_calls)
1686
2252
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2254
def test__get_config(self):
1689
2255
client = FakeClient()
1690
client.add_success_response_with_body('default_stack_on = /\n', 'ok')
2256
client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2257
transport = MemoryTransport()
1692
2258
bzrdir = self.make_remote_bzrdir(transport, client)
1693
2259
config = bzrdir.get_config()
1694
2260
self.assertEqual('/', config.get_default_stack_on())
1695
2261
self.assertEqual(
1696
[('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
2262
[('call_expecting_body', b'BzrDir.get_config_file',
1699
2266
def test_set_option_uses_vfs(self):
1700
2267
self.setup_smart_server_with_call_log()
1701
bzrdir = self.make_bzrdir('.')
2268
bzrdir = self.make_controldir('.')
1702
2269
self.reset_smart_call_log()
1703
2270
config = bzrdir.get_config()
1704
2271
config.set_default_stack_on('/')
1705
self.assertLength(3, self.hpss_calls)
2272
self.assertLength(4, self.hpss_calls)
1707
2274
def test_backwards_compat_get_option(self):
1708
2275
self.setup_smart_server_with_call_log()
1709
bzrdir = self.make_bzrdir('.')
1710
verb = 'BzrDir.get_config_file'
2276
bzrdir = self.make_controldir('.')
2277
verb = b'BzrDir.get_config_file'
1711
2278
self.disable_verb(verb)
1712
2279
self.reset_smart_call_log()
1713
2280
self.assertEqual(None,
1714
bzrdir._get_config().get_option('default_stack_on'))
1715
self.assertLength(3, self.hpss_calls)
2281
bzrdir._get_config().get_option('default_stack_on'))
2282
self.assertLength(4, self.hpss_calls)
1718
2285
class TestTransportIsReadonly(tests.TestCase):
1720
2287
def test_true(self):
1721
2288
client = FakeClient()
1722
client.add_success_response('yes')
2289
client.add_success_response(b'yes')
1723
2290
transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2291
_client=client)
1725
2292
self.assertEqual(True, transport.is_readonly())
1726
2293
self.assertEqual(
1727
[('call', 'Transport.is_readonly', ())],
2294
[('call', b'Transport.is_readonly', ())],
1730
2297
def test_false(self):
1731
2298
client = FakeClient()
1732
client.add_success_response('no')
2299
client.add_success_response(b'no')
1733
2300
transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2301
_client=client)
1735
2302
self.assertEqual(False, transport.is_readonly())
1736
2303
self.assertEqual(
1737
[('call', 'Transport.is_readonly', ())],
2304
[('call', b'Transport.is_readonly', ())],
1740
2307
def test_error_from_old_server(self):
1852
2446
transport_path = 'quack'
1853
2447
repo, client = self.setup_fake_client_and_repository(transport_path)
1854
2448
client.add_success_response_with_body(
1855
'revisions: 2\nsize: 18\n', 'ok')
2449
b'revisions: 2\nsize: 18\n', b'ok')
1856
2450
result = repo.gather_stats(None)
1857
2451
self.assertEqual(
1858
[('call_expecting_body', 'Repository.gather_stats',
1859
('quack/','','no'))],
2452
[('call_expecting_body', b'Repository.gather_stats',
2453
(b'quack/', b'', b'no'))],
1861
2455
self.assertEqual({'revisions': 2, 'size': 18}, result)
1863
2457
def test_revid_no_committers(self):
1864
2458
# ('ok',), body without committers
1865
body = ('firstrev: 123456.300 3600\n'
1866
'latestrev: 654231.400 0\n'
2459
body = (b'firstrev: 123456.300 3600\n'
2460
b'latestrev: 654231.400 0\n'
1869
2463
transport_path = 'quick'
1870
2464
revid = u'\xc8'.encode('utf8')
1871
2465
repo, client = self.setup_fake_client_and_repository(transport_path)
1872
client.add_success_response_with_body(body, 'ok')
2466
client.add_success_response_with_body(body, b'ok')
1873
2467
result = repo.gather_stats(revid)
1874
2468
self.assertEqual(
1875
[('call_expecting_body', 'Repository.gather_stats',
1876
('quick/', revid, 'no'))],
2469
[('call_expecting_body', b'Repository.gather_stats',
2470
(b'quick/', revid, b'no'))],
1878
2472
self.assertEqual({'revisions': 2, 'size': 18,
1879
2473
'firstrev': (123456.300, 3600),
1880
'latestrev': (654231.400, 0),},
2474
'latestrev': (654231.400, 0), },
1883
2477
def test_revid_with_committers(self):
1884
2478
# ('ok',), body with committers
1885
body = ('committers: 128\n'
1886
'firstrev: 123456.300 3600\n'
1887
'latestrev: 654231.400 0\n'
2479
body = (b'committers: 128\n'
2480
b'firstrev: 123456.300 3600\n'
2481
b'latestrev: 654231.400 0\n'
1890
2484
transport_path = 'buick'
1891
2485
revid = u'\xc8'.encode('utf8')
1892
2486
repo, client = self.setup_fake_client_and_repository(transport_path)
1893
client.add_success_response_with_body(body, 'ok')
2487
client.add_success_response_with_body(body, b'ok')
1894
2488
result = repo.gather_stats(revid, True)
1895
2489
self.assertEqual(
1896
[('call_expecting_body', 'Repository.gather_stats',
1897
('buick/', revid, 'yes'))],
2490
[('call_expecting_body', b'Repository.gather_stats',
2491
(b'buick/', revid, b'yes'))],
1899
2493
self.assertEqual({'revisions': 2, 'size': 18,
1900
2494
'committers': 128,
1901
2495
'firstrev': (123456.300, 3600),
1902
'latestrev': (654231.400, 0),},
2496
'latestrev': (654231.400, 0), },
2500
class TestRepositoryBreakLock(TestRemoteRepository):
2502
def test_break_lock(self):
2503
transport_path = 'quack'
2504
repo, client = self.setup_fake_client_and_repository(transport_path)
2505
client.add_success_response(b'ok')
2508
[('call', b'Repository.break_lock', (b'quack/',))],
2512
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2514
def test_get_serializer_format(self):
2515
transport_path = 'hill'
2516
repo, client = self.setup_fake_client_and_repository(transport_path)
2517
client.add_success_response(b'ok', b'7')
2518
self.assertEqual(b'7', repo.get_serializer_format())
2520
[('call', b'VersionedFileRepository.get_serializer_format',
2525
class TestRepositoryReconcile(TestRemoteRepository):
2527
def test_reconcile(self):
2528
transport_path = 'hill'
2529
repo, client = self.setup_fake_client_and_repository(transport_path)
2530
body = (b"garbage_inventories: 2\n"
2531
b"inconsistent_parents: 3\n")
2532
client.add_expected_call(
2533
b'Repository.lock_write', (b'hill/', b''),
2534
b'success', (b'ok', b'a token'))
2535
client.add_success_response_with_body(body, b'ok')
2536
reconciler = repo.reconcile()
2538
[('call', b'Repository.lock_write', (b'hill/', b'')),
2539
('call_expecting_body', b'Repository.reconcile',
2540
(b'hill/', b'a token'))],
2542
self.assertEqual(2, reconciler.garbage_inventories)
2543
self.assertEqual(3, reconciler.inconsistent_parents)
2546
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2548
def test_text(self):
2549
# ('ok',), body with signature text
2550
transport_path = 'quack'
2551
repo, client = self.setup_fake_client_and_repository(transport_path)
2552
client.add_success_response_with_body(
2554
self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
2556
[('call_expecting_body', b'Repository.get_revision_signature_text',
2557
(b'quack/', b'revid'))],
2560
def test_no_signature(self):
2561
transport_path = 'quick'
2562
repo, client = self.setup_fake_client_and_repository(transport_path)
2563
client.add_error_response(b'nosuchrevision', b'unknown')
2564
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2567
[('call_expecting_body', b'Repository.get_revision_signature_text',
2568
(b'quick/', b'unknown'))],
1906
2572
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2574
def test_get_graph(self):
2257
3049
self.setup_smart_server_with_call_log()
2258
3050
tree = self.make_branch_and_memory_tree('.')
2259
3051
tree.lock_write()
2260
3053
rev1 = tree.commit('First')
2261
rev2 = tree.commit('Second')
3054
tree.commit('Second')
2263
3056
branch = tree.branch
2264
3057
self.assertFalse(branch.is_locked())
2265
3058
self.reset_smart_call_log()
2266
verb = 'Repository.get_rev_id_for_revno'
3059
verb = b'Repository.get_rev_id_for_revno'
2267
3060
self.disable_verb(verb)
2268
3061
self.assertEqual(rev1, branch.get_rev_id(1))
2269
3062
self.assertLength(1, [call for call in self.hpss_calls if
2270
3063
call.call.method == verb])
3066
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
3068
def test_has_signature_for_revision_id(self):
3069
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
3070
transport_path = 'quack'
3071
repo, client = self.setup_fake_client_and_repository(transport_path)
3072
client.add_success_response(b'yes')
3073
result = repo.has_signature_for_revision_id(b'A')
3075
[('call', b'Repository.has_signature_for_revision_id',
3076
(b'quack/', b'A'))],
3078
self.assertEqual(True, result)
3080
def test_is_not_shared(self):
3081
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
3082
transport_path = 'qwack'
3083
repo, client = self.setup_fake_client_and_repository(transport_path)
3084
client.add_success_response(b'no')
3085
result = repo.has_signature_for_revision_id(b'A')
3087
[('call', b'Repository.has_signature_for_revision_id',
3088
(b'qwack/', b'A'))],
3090
self.assertEqual(False, result)
3093
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
3095
def test_get_physical_lock_status_yes(self):
3096
transport_path = 'qwack'
3097
repo, client = self.setup_fake_client_and_repository(transport_path)
3098
client.add_success_response(b'yes')
3099
result = repo.get_physical_lock_status()
3101
[('call', b'Repository.get_physical_lock_status',
3104
self.assertEqual(True, result)
3106
def test_get_physical_lock_status_no(self):
3107
transport_path = 'qwack'
3108
repo, client = self.setup_fake_client_and_repository(transport_path)
3109
client.add_success_response(b'no')
3110
result = repo.get_physical_lock_status()
3112
[('call', b'Repository.get_physical_lock_status',
3115
self.assertEqual(False, result)
2273
3118
class TestRepositoryIsShared(TestRemoteRepository):
2275
3120
def test_is_shared(self):
2276
3121
# ('yes', ) for Repository.is_shared -> 'True'.
2277
3122
transport_path = 'quack'
2278
3123
repo, client = self.setup_fake_client_and_repository(transport_path)
2279
client.add_success_response('yes')
3124
client.add_success_response(b'yes')
2280
3125
result = repo.is_shared()
2281
3126
self.assertEqual(
2282
[('call', 'Repository.is_shared', ('quack/',))],
3127
[('call', b'Repository.is_shared', (b'quack/',))],
2284
3129
self.assertEqual(True, result)
2300
3170
def test_lock_write(self):
2301
3171
transport_path = 'quack'
2302
3172
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
client.add_success_response('ok', 'a token')
3173
client.add_success_response(b'ok', b'a token')
2304
3174
token = repo.lock_write().repository_token
2305
3175
self.assertEqual(
2306
[('call', 'Repository.lock_write', ('quack/', ''))],
3176
[('call', b'Repository.lock_write', (b'quack/', b''))],
2308
self.assertEqual('a token', token)
3178
self.assertEqual(b'a token', token)
2310
3180
def test_lock_write_already_locked(self):
2311
3181
transport_path = 'quack'
2312
3182
repo, client = self.setup_fake_client_and_repository(transport_path)
2313
client.add_error_response('LockContention')
3183
client.add_error_response(b'LockContention')
2314
3184
self.assertRaises(errors.LockContention, repo.lock_write)
2315
3185
self.assertEqual(
2316
[('call', 'Repository.lock_write', ('quack/', ''))],
3186
[('call', b'Repository.lock_write', (b'quack/', b''))],
2319
3189
def test_lock_write_unlockable(self):
2320
3190
transport_path = 'quack'
2321
3191
repo, client = self.setup_fake_client_and_repository(transport_path)
2322
client.add_error_response('UnlockableTransport')
3192
client.add_error_response(b'UnlockableTransport')
2323
3193
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3194
self.assertEqual(
2325
[('call', 'Repository.lock_write', ('quack/', ''))],
3195
[('call', b'Repository.lock_write', (b'quack/', b''))],
3199
class TestRepositoryWriteGroups(TestRemoteRepository):
3201
def test_start_write_group(self):
3202
transport_path = 'quack'
3203
repo, client = self.setup_fake_client_and_repository(transport_path)
3204
client.add_expected_call(
3205
b'Repository.lock_write', (b'quack/', b''),
3206
b'success', (b'ok', b'a token'))
3207
client.add_expected_call(
3208
b'Repository.start_write_group', (b'quack/', b'a token'),
3209
b'success', (b'ok', (b'token1', )))
3211
repo.start_write_group()
3213
def test_start_write_group_unsuspendable(self):
3214
# Some repositories do not support suspending write
3215
# groups. For those, fall back to the "real" repository.
3216
transport_path = 'quack'
3217
repo, client = self.setup_fake_client_and_repository(transport_path)
3219
def stub_ensure_real():
3220
client._calls.append(('_ensure_real',))
3221
repo._real_repository = _StubRealPackRepository(client._calls)
3222
repo._ensure_real = stub_ensure_real
3223
client.add_expected_call(
3224
b'Repository.lock_write', (b'quack/', b''),
3225
b'success', (b'ok', b'a token'))
3226
client.add_expected_call(
3227
b'Repository.start_write_group', (b'quack/', b'a token'),
3228
b'error', (b'UnsuspendableWriteGroup',))
3230
repo.start_write_group()
3231
self.assertEqual(client._calls[-2:], [
3233
('start_write_group',)])
3235
def test_commit_write_group(self):
3236
transport_path = 'quack'
3237
repo, client = self.setup_fake_client_and_repository(transport_path)
3238
client.add_expected_call(
3239
b'Repository.lock_write', (b'quack/', b''),
3240
b'success', (b'ok', b'a token'))
3241
client.add_expected_call(
3242
b'Repository.start_write_group', (b'quack/', b'a token'),
3243
b'success', (b'ok', [b'token1']))
3244
client.add_expected_call(
3245
b'Repository.commit_write_group', (b'quack/',
3246
b'a token', [b'token1']),
3247
b'success', (b'ok',))
3249
repo.start_write_group()
3250
repo.commit_write_group()
3252
def test_abort_write_group(self):
3253
transport_path = 'quack'
3254
repo, client = self.setup_fake_client_and_repository(transport_path)
3255
client.add_expected_call(
3256
b'Repository.lock_write', (b'quack/', b''),
3257
b'success', (b'ok', b'a token'))
3258
client.add_expected_call(
3259
b'Repository.start_write_group', (b'quack/', b'a token'),
3260
b'success', (b'ok', [b'token1']))
3261
client.add_expected_call(
3262
b'Repository.abort_write_group', (b'quack/',
3263
b'a token', [b'token1']),
3264
b'success', (b'ok',))
3266
repo.start_write_group()
3267
repo.abort_write_group(False)
3269
def test_suspend_write_group(self):
3270
transport_path = 'quack'
3271
repo, client = self.setup_fake_client_and_repository(transport_path)
3272
self.assertEqual([], repo.suspend_write_group())
3274
def test_resume_write_group(self):
3275
transport_path = 'quack'
3276
repo, client = self.setup_fake_client_and_repository(transport_path)
3277
client.add_expected_call(
3278
b'Repository.lock_write', (b'quack/', b''),
3279
b'success', (b'ok', b'a token'))
3280
client.add_expected_call(
3281
b'Repository.check_write_group', (b'quack/',
3282
b'a token', [b'token1']),
3283
b'success', (b'ok',))
3285
repo.resume_write_group(['token1'])
2329
3288
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3290
def test_backwards_compat(self):
2332
3291
self.setup_smart_server_with_call_log()
2333
3292
repo = self.make_repository('.')
2334
3293
self.reset_smart_call_log()
2335
verb = 'Repository.set_make_working_trees'
3294
verb = b'Repository.set_make_working_trees'
2336
3295
self.disable_verb(verb)
2337
3296
repo.set_make_working_trees(True)
2338
3297
call_count = len([call for call in self.hpss_calls if
2339
call.call.method == verb])
3298
call.call.method == verb])
2340
3299
self.assertEqual(1, call_count)
2342
3301
def test_current(self):
2343
3302
transport_path = 'quack'
2344
3303
repo, client = self.setup_fake_client_and_repository(transport_path)
2345
3304
client.add_expected_call(
2346
'Repository.set_make_working_trees', ('quack/', 'True'),
3305
b'Repository.set_make_working_trees', (b'quack/', b'True'),
3306
b'success', (b'ok',))
2348
3307
client.add_expected_call(
2349
'Repository.set_make_working_trees', ('quack/', 'False'),
3308
b'Repository.set_make_working_trees', (b'quack/', b'False'),
3309
b'success', (b'ok',))
2351
3310
repo.set_make_working_trees(True)
2352
3311
repo.set_make_working_trees(False)
2419
3405
def setUp(self):
2420
TestRemoteRepository.setUp(self)
2421
self.disable_verb('Repository.insert_stream_1.19')
3406
super(TestRepositoryInsertStream, self).setUp()
3407
self.disable_verb(b'Repository.insert_stream_1.19')
2423
3409
def test_unlocked_repo(self):
2424
3410
transport_path = 'quack'
2425
3411
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3412
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/', ''),
3413
b'Repository.insert_stream_1.19', (b'quack/', b''),
3414
b'unknown', (b'Repository.insert_stream_1.19',))
3415
client.add_expected_call(
3416
b'Repository.insert_stream', (b'quack/', b''),
3417
b'success', (b'ok',))
3418
client.add_expected_call(
3419
b'Repository.insert_stream', (b'quack/', b''),
3420
b'success', (b'ok',))
2435
3421
self.checkInsertEmptyStream(repo, client)
2437
3423
def test_locked_repo_with_no_lock_token(self):
2438
3424
transport_path = 'quack'
2439
3425
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3426
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/', ''),
3427
b'Repository.lock_write', (b'quack/', b''),
3428
b'success', (b'ok', b''))
3429
client.add_expected_call(
3430
b'Repository.insert_stream_1.19', (b'quack/', b''),
3431
b'unknown', (b'Repository.insert_stream_1.19',))
3432
client.add_expected_call(
3433
b'Repository.insert_stream', (b'quack/', b''),
3434
b'success', (b'ok',))
3435
client.add_expected_call(
3436
b'Repository.insert_stream', (b'quack/', b''),
3437
b'success', (b'ok',))
2452
3438
repo.lock_write()
2453
3439
self.checkInsertEmptyStream(repo, client)
2479
3465
transport_path = 'quack'
2480
3466
repo, client = self.setup_fake_client_and_repository(transport_path)
2481
3467
client.add_expected_call(
2482
'Repository.insert_stream_1.19', ('quack/', ''),
2483
'unknown', ('Repository.insert_stream_1.19',))
2484
client.add_expected_call(
2485
'Repository.insert_stream', ('quack/', ''),
2487
client.add_expected_call(
2488
'Repository.insert_stream', ('quack/', ''),
3468
b'Repository.insert_stream_1.19', (b'quack/', b''),
3469
b'unknown', (b'Repository.insert_stream_1.19',))
3470
client.add_expected_call(
3471
b'Repository.insert_stream', (b'quack/', b''),
3472
b'success', (b'ok',))
3473
client.add_expected_call(
3474
b'Repository.insert_stream', (b'quack/', b''),
3475
b'success', (b'ok',))
2490
3476
# Create a fake real repository for insert_stream to fall back on, so
2491
3477
# that we can directly see the records the RemoteSink passes to the
2493
3480
class FakeRealSink:
2494
3481
def __init__(self):
2495
3482
self.records = []
2496
3484
def insert_stream(self, stream, src_format, resume_tokens):
2497
3485
for substream_kind, substream in stream:
2498
3486
self.records.append(
2499
3487
(substream_kind, [record.key for record in substream]))
2500
return ['fake tokens'], ['fake missing keys']
3488
return [b'fake tokens'], [b'fake missing keys']
2501
3489
fake_real_sink = FakeRealSink()
2502
3491
class FakeRealRepository:
2503
3492
def _get_sink(self):
2504
3493
return fake_real_sink
2505
3495
def is_in_write_group(self):
2507
3498
def refresh_data(self):
2509
3500
repo._real_repository = FakeRealRepository()
2510
3501
sink = repo._get_sink()
2511
fmt = repository.RepositoryFormat.get_default_format()
3502
fmt = repository.format_registry.get_default()
2512
3503
stream = self.make_stream_with_inv_deltas(fmt)
2513
3504
resume_tokens, missing_keys = sink.insert_stream(stream, fmt, [])
2514
3505
# Every record from the first inventory delta should have been sent to
2515
3506
# the VFS sink.
2516
3507
expected_records = [
2517
('inventory-deltas', [('rev2',), ('rev3',)]),
2518
('texts', [('some-rev', 'some-file')])]
3508
('inventory-deltas', [(b'rev2',), (b'rev3',)]),
3509
('texts', [(b'some-rev', b'some-file')])]
2519
3510
self.assertEqual(expected_records, fake_real_sink.records)
2520
3511
# The return values from the real sink's insert_stream are propagated
2521
3512
# back to the original caller.
2522
self.assertEqual(['fake tokens'], resume_tokens)
2523
self.assertEqual(['fake missing keys'], missing_keys)
3513
self.assertEqual([b'fake tokens'], resume_tokens)
3514
self.assertEqual([b'fake missing keys'], missing_keys)
2524
3515
self.assertFinished(client)
2526
3517
def make_stream_with_inv_deltas(self, fmt):
2534
3525
* texts substream: (some-rev, some-file)
2536
3527
# Define a stream using generators so that it isn't rewindable.
2537
inv = inventory.Inventory(revision_id='rev1')
2538
inv.root.revision = 'rev1'
3528
inv = inventory.Inventory(revision_id=b'rev1')
3529
inv.root.revision = b'rev1'
2539
3531
def stream_with_inv_delta():
2540
3532
yield ('inventories', inventories_substream())
2541
3533
yield ('inventory-deltas', inventory_delta_substream())
2542
3534
yield ('texts', [
2543
3535
versionedfile.FulltextContentFactory(
2544
('some-rev', 'some-file'), (), None, 'content')])
3536
(b'some-rev', b'some-file'), (), None, b'content')])
2545
3538
def inventories_substream():
2546
3539
# An empty inventory fulltext. This will be streamed normally.
2547
3540
text = fmt._serializer.write_inventory_to_string(inv)
2548
3541
yield versionedfile.FulltextContentFactory(
2549
('rev1',), (), None, text)
3542
(b'rev1',), (), None, text)
2550
3544
def inventory_delta_substream():
2551
3545
# An inventory delta. This can't be streamed via this verb, so it
2552
3546
# will trigger a fallback to VFS insert_stream.
2553
3547
entry = inv.make_entry(
2554
'directory', 'newdir', inv.root.file_id, 'newdir-id')
2555
entry.revision = 'ghost'
2556
delta = [(None, 'newdir', 'newdir-id', entry)]
3548
'directory', 'newdir', inv.root.file_id, b'newdir-id')
3549
entry.revision = b'ghost'
3550
delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3551
serializer = inventory_delta.InventoryDeltaSerializer(
2558
3552
versioned_root=True, tree_references=False)
2559
lines = serializer.delta_to_lines('rev1', 'rev2', delta)
3553
lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3554
yield versionedfile.ChunkedContentFactory(
2561
('rev2',), (('rev1',)), None, lines)
3555
(b'rev2',), ((b'rev1',)), None, lines)
2562
3556
# Another delta.
2563
lines = serializer.delta_to_lines('rev1', 'rev3', delta)
3557
lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3558
yield versionedfile.ChunkedContentFactory(
2565
('rev3',), (('rev1',)), None, lines)
3559
(b'rev3',), ((b'rev1',)), None, lines)
2566
3560
return stream_with_inv_delta()
2784
3792
def test_NoSuchRevision(self):
2785
3793
branch = self.make_branch('')
2787
3795
translated_error = self.translateTuple(
2788
('NoSuchRevision', revid), branch=branch)
3796
(b'NoSuchRevision', revid), branch=branch)
2789
3797
expected_error = errors.NoSuchRevision(branch, revid)
2790
3798
self.assertEqual(expected_error, translated_error)
2792
3800
def test_nosuchrevision(self):
2793
3801
repository = self.make_repository('')
2795
3803
translated_error = self.translateTuple(
2796
('nosuchrevision', revid), repository=repository)
3804
(b'nosuchrevision', revid), repository=repository)
2797
3805
expected_error = errors.NoSuchRevision(repository, revid)
2798
3806
self.assertEqual(expected_error, translated_error)
2800
3808
def test_nobranch(self):
2801
bzrdir = self.make_bzrdir('')
2802
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3809
bzrdir = self.make_controldir('')
3810
translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3811
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3812
self.assertEqual(expected_error, translated_error)
2806
3814
def test_nobranch_one_arg(self):
2807
bzrdir = self.make_bzrdir('')
3815
bzrdir = self.make_controldir('')
2808
3816
translated_error = self.translateTuple(
2809
('nobranch', 'extra detail'), bzrdir=bzrdir)
3817
(b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3818
expected_error = errors.NotBranchError(
2811
3819
path=bzrdir.root_transport.base,
2812
3820
detail='extra detail')
2813
3821
self.assertEqual(expected_error, translated_error)
3823
def test_norepository(self):
3824
bzrdir = self.make_controldir('')
3825
translated_error = self.translateTuple((b'norepository',),
3827
expected_error = errors.NoRepositoryPresent(bzrdir)
3828
self.assertEqual(expected_error, translated_error)
2815
3830
def test_LockContention(self):
2816
translated_error = self.translateTuple(('LockContention',))
3831
translated_error = self.translateTuple((b'LockContention',))
2817
3832
expected_error = errors.LockContention('(remote lock)')
2818
3833
self.assertEqual(expected_error, translated_error)
2820
3835
def test_UnlockableTransport(self):
2821
bzrdir = self.make_bzrdir('')
3836
bzrdir = self.make_controldir('')
2822
3837
translated_error = self.translateTuple(
2823
('UnlockableTransport',), bzrdir=bzrdir)
3838
(b'UnlockableTransport',), bzrdir=bzrdir)
2824
3839
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3840
self.assertEqual(expected_error, translated_error)
2827
3842
def test_LockFailed(self):
2828
3843
lock = 'str() of a server lock'
2829
3844
why = 'str() of why'
2830
translated_error = self.translateTuple(('LockFailed', lock, why))
3845
translated_error = self.translateTuple(
3846
(b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3847
expected_error = errors.LockFailed(lock, why)
2832
3848
self.assertEqual(expected_error, translated_error)
2834
3850
def test_TokenMismatch(self):
2835
3851
token = 'a lock token'
2836
translated_error = self.translateTuple(('TokenMismatch',), token=token)
3852
translated_error = self.translateTuple(
3853
(b'TokenMismatch',), token=token)
2837
3854
expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3855
self.assertEqual(expected_error, translated_error)
2841
3858
branch = self.make_branch('a')
2842
3859
other_branch = self.make_branch('b')
2843
3860
translated_error = self.translateTuple(
2844
('Diverged',), branch=branch, other_branch=other_branch)
3861
(b'Diverged',), branch=branch, other_branch=other_branch)
2845
3862
expected_error = errors.DivergedBranches(branch, other_branch)
2846
3863
self.assertEqual(expected_error, translated_error)
3865
def test_NotStacked(self):
3866
branch = self.make_branch('')
3867
translated_error = self.translateTuple((b'NotStacked',), branch=branch)
3868
expected_error = errors.NotStacked(branch)
3869
self.assertEqual(expected_error, translated_error)
2848
3871
def test_ReadError_no_args(self):
2849
3872
path = 'a path'
2850
translated_error = self.translateTuple(('ReadError',), path=path)
3873
translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3874
expected_error = errors.ReadError(path)
2852
3875
self.assertEqual(expected_error, translated_error)
2854
3877
def test_ReadError(self):
2855
3878
path = 'a path'
2856
translated_error = self.translateTuple(('ReadError', path))
3879
translated_error = self.translateTuple(
3880
(b'ReadError', path.encode('utf-8')))
2857
3881
expected_error = errors.ReadError(path)
2858
3882
self.assertEqual(expected_error, translated_error)
2860
3884
def test_IncompatibleRepositories(self):
2861
translated_error = self.translateTuple(('IncompatibleRepositories',
2862
"repo1", "repo2", "details here"))
3885
translated_error = self.translateTuple((b'IncompatibleRepositories',
3886
b"repo1", b"repo2", b"details here"))
2863
3887
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
3889
self.assertEqual(expected_error, translated_error)
3891
def test_GhostRevisionsHaveNoRevno(self):
3892
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3893
b"revid1", b"revid2"))
3894
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
2865
3895
self.assertEqual(expected_error, translated_error)
2867
3897
def test_PermissionDenied_no_args(self):
2868
3898
path = 'a path'
2869
translated_error = self.translateTuple(('PermissionDenied',), path=path)
3899
translated_error = self.translateTuple((b'PermissionDenied',),
2870
3901
expected_error = errors.PermissionDenied(path)
2871
3902
self.assertEqual(expected_error, translated_error)
2873
3904
def test_PermissionDenied_one_arg(self):
2874
3905
path = 'a path'
2875
translated_error = self.translateTuple(('PermissionDenied', path))
3906
translated_error = self.translateTuple(
3907
(b'PermissionDenied', path.encode('utf-8')))
2876
3908
expected_error = errors.PermissionDenied(path)
2877
3909
self.assertEqual(expected_error, translated_error)
2891
3923
path = 'a path'
2892
3924
extra = 'a string with extra info'
2893
3925
translated_error = self.translateTuple(
2894
('PermissionDenied', path, extra))
3926
(b'PermissionDenied', path.encode('utf-8'), extra.encode('utf-8')))
2895
3927
expected_error = errors.PermissionDenied(path, extra)
2896
3928
self.assertEqual(expected_error, translated_error)
3930
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3932
def test_NoSuchFile_context_path(self):
3933
local_path = "local path"
3934
translated_error = self.translateTuple((b'ReadError', b"remote path"),
3936
expected_error = errors.ReadError(local_path)
3937
self.assertEqual(expected_error, translated_error)
3939
def test_NoSuchFile_without_context(self):
3940
remote_path = "remote path"
3941
translated_error = self.translateTuple(
3942
(b'ReadError', remote_path.encode('utf-8')))
3943
expected_error = errors.ReadError(remote_path)
3944
self.assertEqual(expected_error, translated_error)
3946
def test_ReadOnlyError(self):
3947
translated_error = self.translateTuple((b'ReadOnlyError',))
3948
expected_error = errors.TransportNotPossible("readonly transport")
3949
self.assertEqual(expected_error, translated_error)
3951
def test_MemoryError(self):
3952
translated_error = self.translateTuple((b'MemoryError',))
3953
self.assertStartsWith(str(translated_error),
3954
"remote server out of memory")
3956
def test_generic_IndexError_no_classname(self):
3957
err = errors.ErrorFromSmartServer(
3958
(b'error', b"list index out of range"))
3959
translated_error = self.translateErrorFromSmartServer(err)
3960
expected_error = errors.UnknownErrorFromSmartServer(err)
3961
self.assertEqual(expected_error, translated_error)
3963
# GZ 2011-03-02: TODO test generic non-ascii error string
3965
def test_generic_KeyError(self):
3966
err = errors.ErrorFromSmartServer((b'error', b'KeyError', b"1"))
3967
translated_error = self.translateErrorFromSmartServer(err)
3968
expected_error = errors.UnknownErrorFromSmartServer(err)
3969
self.assertEqual(expected_error, translated_error)
3971
def test_RevnoOutOfBounds(self):
3972
translated_error = self.translateTuple(
3973
((b'revno-outofbounds', 5, 0, 3)), path=b'path')
3974
expected_error = errors.RevnoOutOfBounds(5, (0, 3))
3975
self.assertEqual(expected_error, translated_error)
2899
3978
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3979
"""Unit tests for breezy.bzr.remote._translate_error's robustness.
2902
3981
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3982
translate successfully. This class about how _translate_err behaves when
3143
4222
def test_copy_content_into_avoids_revision_history(self):
3144
4223
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4224
builder = self.make_branch_builder('remote')
4225
builder.build_commit(message="Commit.")
3147
4226
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4227
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4228
local.repository.fetch(remote_branch.repository)
3150
4229
self.hpss_calls = []
3151
4230
remote_branch.copy_content_into(local)
3152
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4231
self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
4233
def test_fetch_everything_needs_just_one_call(self):
4234
local = self.make_branch('local')
4235
builder = self.make_branch_builder('remote')
4236
builder.build_commit(message="Commit.")
4237
remote_branch_url = self.smart_server.get_url() + 'remote'
4238
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4239
self.hpss_calls = []
4240
local.repository.fetch(
4241
remote_branch.repository,
4242
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4243
self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
4245
def override_verb(self, verb_name, verb):
4246
request_handlers = request.request_handlers
4247
orig_verb = request_handlers.get(verb_name)
4248
orig_info = request_handlers.get_info(verb_name)
4249
request_handlers.register(verb_name, verb, override_existing=True)
4250
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4251
override_existing=True, info=orig_info)
4253
def test_fetch_everything_backwards_compat(self):
4254
"""Can fetch with EverythingResult even with pre 2.4 servers.
4256
Pre-2.4 do not support 'everything' searches with the
4257
Repository.get_stream_1.19 verb.
4261
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4262
"""A version of the Repository.get_stream_1.19 verb patched to
4263
reject 'everything' searches the way 2.3 and earlier do.
4266
def recreate_search(self, repository, search_bytes,
4267
discard_excess=False):
4268
verb_log.append(search_bytes.split(b'\n', 1)[0])
4269
if search_bytes == b'everything':
4271
request.FailedSmartServerResponse((b'BadSearch',)))
4272
return super(OldGetStreamVerb,
4273
self).recreate_search(repository, search_bytes,
4274
discard_excess=discard_excess)
4275
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4276
local = self.make_branch('local')
4277
builder = self.make_branch_builder('remote')
4278
builder.build_commit(message="Commit.")
4279
remote_branch_url = self.smart_server.get_url() + 'remote'
4280
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4281
self.hpss_calls = []
4282
local.repository.fetch(
4283
remote_branch.repository,
4284
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4285
# make sure the overridden verb was used
4286
self.assertLength(1, verb_log)
4287
# more than one HPSS call is needed, but because it's a VFS callback
4288
# its hard to predict exactly how many.
4289
self.assertTrue(len(self.hpss_calls) > 1)
4292
class TestUpdateBoundBranchWithModifiedBoundLocation(
4293
tests.TestCaseWithTransport):
4294
"""Ensure correct handling of bound_location modifications.
4296
This is tested against a smart server as http://pad.lv/786980 was about a
4297
ReadOnlyError (write attempt during a read-only transaction) which can only
4298
happen in this context.
4302
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4303
self.transport_server = test_server.SmartTCPServer_for_testing
4305
def make_master_and_checkout(self, master_name, checkout_name):
4306
# Create the master branch and its associated checkout
4307
self.master = self.make_branch_and_tree(master_name)
4308
self.checkout = self.master.branch.create_checkout(checkout_name)
4309
# Modify the master branch so there is something to update
4310
self.master.commit('add stuff')
4311
self.last_revid = self.master.commit('even more stuff')
4312
self.bound_location = self.checkout.branch.get_bound_location()
4314
def assertUpdateSucceeds(self, new_location):
4315
self.checkout.branch.set_bound_location(new_location)
4316
self.checkout.update()
4317
self.assertEqual(self.last_revid, self.checkout.last_revision())
4319
def test_without_final_slash(self):
4320
self.make_master_and_checkout('master', 'checkout')
4321
# For unclear reasons some users have a bound_location without a final
4322
# '/', simulate that by forcing such a value
4323
self.assertEndsWith(self.bound_location, '/')
4324
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4326
def test_plus_sign(self):
4327
self.make_master_and_checkout('+master', 'checkout')
4328
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4330
def test_tilda(self):
4331
# Embed ~ in the middle of the path just to avoid any $HOME
4333
self.make_master_and_checkout('mas~ter', 'checkout')
4334
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4337
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4339
def test_no_context(self):
4340
class OutOfCoffee(errors.BzrError):
4341
"""A dummy exception for testing."""
4343
def __init__(self, urgency):
4344
self.urgency = urgency
4345
remote.no_context_error_translators.register(b"OutOfCoffee",
4346
lambda err: OutOfCoffee(err.error_args[0]))
4347
transport = MemoryTransport()
4348
client = FakeClient(transport.base)
4349
client.add_expected_call(
4350
b'Branch.get_stacked_on_url', (b'quack/',),
4351
b'error', (b'NotStacked',))
4352
client.add_expected_call(
4353
b'Branch.last_revision_info',
4355
b'error', (b'OutOfCoffee', b'low'))
4356
transport.mkdir('quack')
4357
transport = transport.clone('quack')
4358
branch = self.make_remote_branch(transport, client)
4359
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4360
self.assertFinished(client)
4362
def test_with_context(self):
4363
class OutOfTea(errors.BzrError):
4364
def __init__(self, branch, urgency):
4365
self.branch = branch
4366
self.urgency = urgency
4367
remote.error_translators.register(b"OutOfTea",
4368
lambda err, find, path: OutOfTea(
4369
err.error_args[0].decode(
4372
transport = MemoryTransport()
4373
client = FakeClient(transport.base)
4374
client.add_expected_call(
4375
b'Branch.get_stacked_on_url', (b'quack/',),
4376
b'error', (b'NotStacked',))
4377
client.add_expected_call(
4378
b'Branch.last_revision_info',
4380
b'error', (b'OutOfTea', b'low'))
4381
transport.mkdir('quack')
4382
transport = transport.clone('quack')
4383
branch = self.make_remote_branch(transport, client)
4384
self.assertRaises(OutOfTea, branch.last_revision_info)
4385
self.assertFinished(client)
4388
class TestRepositoryPack(TestRemoteRepository):
4390
def test_pack(self):
4391
transport_path = 'quack'
4392
repo, client = self.setup_fake_client_and_repository(transport_path)
4393
client.add_expected_call(
4394
b'Repository.lock_write', (b'quack/', b''),
4395
b'success', (b'ok', b'token'))
4396
client.add_expected_call(
4397
b'Repository.pack', (b'quack/', b'token', b'False'),
4398
b'success', (b'ok',), )
4399
client.add_expected_call(
4400
b'Repository.unlock', (b'quack/', b'token'),
4401
b'success', (b'ok', ))
4404
def test_pack_with_hint(self):
4405
transport_path = 'quack'
4406
repo, client = self.setup_fake_client_and_repository(transport_path)
4407
client.add_expected_call(
4408
b'Repository.lock_write', (b'quack/', b''),
4409
b'success', (b'ok', b'token'))
4410
client.add_expected_call(
4411
b'Repository.pack', (b'quack/', b'token', b'False'),
4412
b'success', (b'ok',), )
4413
client.add_expected_call(
4414
b'Repository.unlock', (b'quack/', b'token', b'False'),
4415
b'success', (b'ok', ))
4416
repo.pack(['hinta', 'hintb'])
4419
class TestRepositoryIterInventories(TestRemoteRepository):
4420
"""Test Repository.iter_inventories."""
4422
def _serialize_inv_delta(self, old_name, new_name, delta):
4423
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4424
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4426
def test_single_empty(self):
4427
transport_path = 'quack'
4428
repo, client = self.setup_fake_client_and_repository(transport_path)
4429
fmt = controldir.format_registry.get('2a')().repository_format
4431
stream = [('inventory-deltas', [
4432
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4433
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4434
client.add_expected_call(
4435
b'VersionedFileRepository.get_inventories', (
4436
b'quack/', b'unordered'),
4437
b'success', (b'ok', ),
4438
_stream_to_byte_stream(stream, fmt))
4439
ret = list(repo.iter_inventories([b"somerevid"]))
4440
self.assertLength(1, ret)
4442
self.assertEqual(b"somerevid", inv.revision_id)
4444
def test_empty(self):
4445
transport_path = 'quack'
4446
repo, client = self.setup_fake_client_and_repository(transport_path)
4447
ret = list(repo.iter_inventories([]))
4448
self.assertEqual(ret, [])
4450
def test_missing(self):
4451
transport_path = 'quack'
4452
repo, client = self.setup_fake_client_and_repository(transport_path)
4453
client.add_expected_call(
4454
b'VersionedFileRepository.get_inventories', (
4455
b'quack/', b'unordered'),
4456
b'success', (b'ok', ), iter([]))
4457
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4461
class TestRepositoryRevisionTreeArchive(TestRemoteRepository):
4462
"""Test Repository.iter_inventories."""
4464
def _serialize_inv_delta(self, old_name, new_name, delta):
4465
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4466
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4468
def test_simple(self):
4469
transport_path = 'quack'
4470
repo, client = self.setup_fake_client_and_repository(transport_path)
4471
fmt = controldir.format_registry.get('2a')().repository_format
4473
stream = [('inventory-deltas', [
4474
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4475
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4476
client.add_expected_call(
4477
b'VersionedFileRepository.get_inventories', (
4478
b'quack/', b'unordered'),
4479
b'success', (b'ok', ),
4480
_stream_to_byte_stream(stream, fmt))
4482
with tarfile.open(mode='w', fileobj=f) as tf:
4483
info = tarfile.TarInfo('somefile')
4485
contents = b'some data'
4486
info.type = tarfile.REGTYPE
4488
info.size = len(contents)
4489
tf.addfile(info, BytesIO(contents))
4490
client.add_expected_call(
4491
b'Repository.revision_archive', (b'quack/',
4492
b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4493
b'success', (b'ok', ),
4495
tree = repo.revision_tree(b'somerevid')
4496
self.assertEqual(f.getvalue(), b''.join(
4497
tree.archive('tar', 'foo.tar')))
4500
class TestRepositoryAnnotate(TestRemoteRepository):
4501
"""Test RemoteRevisionTree.annotate.."""
4503
def _serialize_inv_delta(self, old_name, new_name, delta):
4504
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4505
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4507
def test_simple(self):
4508
transport_path = 'quack'
4509
repo, client = self.setup_fake_client_and_repository(transport_path)
4510
fmt = controldir.format_registry.get('2a')().repository_format
4513
('inventory-deltas', [
4514
versionedfile.FulltextContentFactory(
4515
b'somerevid', None, None,
4516
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4517
client.add_expected_call(
4518
b'VersionedFileRepository.get_inventories', (
4519
b'quack/', b'unordered'),
4520
b'success', (b'ok', ),
4521
_stream_to_byte_stream(stream, fmt))
4522
client.add_expected_call(
4523
b'Repository.annotate_file_revision',
4524
(b'quack/', b'somerevid', b'filename', b'', b'current:'),
4525
b'success', (b'ok', ),
4526
bencode.bencode([[b'baserevid', b'line 1\n'],
4527
[b'somerevid', b'line2\n']]))
4528
tree = repo.revision_tree(b'somerevid')
4530
(b'baserevid', b'line 1\n'),
4531
(b'somerevid', b'line2\n')],
4532
list(tree.annotate_iter('filename')))