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}),
103
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
81
{'transport_server': test_server.SmartTCPServer_for_testing})]
82
return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
105
{'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)
480
494
self.assertEqual(None, result._branch_format)
481
495
self.assertFinished(client)
497
def test_unknown(self):
498
transport = self.get_transport('quack')
499
referenced = self.make_branch('referenced')
500
expected = referenced.controldir.cloning_metadir()
501
client = FakeClient(transport.base)
502
client.add_expected_call(
503
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
504
b'success', (b'unknown', b'unknown', (b'branch', b''))),
505
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
507
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
510
class TestBzrDirCheckoutMetaDir(TestRemote):
512
def test__get_checkout_format(self):
513
transport = MemoryTransport()
514
client = FakeClient(transport.base)
515
reference_bzrdir_format = controldir.format_registry.get('default')()
516
control_name = reference_bzrdir_format.network_name()
517
client.add_expected_call(
518
b'BzrDir.checkout_metadir', (b'quack/', ),
519
b'success', (control_name, b'', b''))
520
transport.mkdir('quack')
521
transport = transport.clone('quack')
522
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
524
result = a_controldir.checkout_metadir()
525
# We should have got a reference control dir with default branch and
526
# repository formats.
527
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
528
self.assertEqual(None, result._repository_format)
529
self.assertEqual(None, result._branch_format)
530
self.assertFinished(client)
532
def test_unknown_format(self):
533
transport = MemoryTransport()
534
client = FakeClient(transport.base)
535
client.add_expected_call(
536
b'BzrDir.checkout_metadir', (b'quack/',),
537
b'success', (b'dontknow', b'', b''))
538
transport.mkdir('quack')
539
transport = transport.clone('quack')
540
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
542
self.assertRaises(errors.UnknownFormatError,
543
a_controldir.checkout_metadir)
544
self.assertFinished(client)
547
class TestBzrDirGetBranches(TestRemote):
549
def test_get_branches(self):
550
transport = MemoryTransport()
551
client = FakeClient(transport.base)
552
reference_bzrdir_format = controldir.format_registry.get('default')()
553
branch_name = reference_bzrdir_format.get_branch_format().network_name()
554
client.add_success_response_with_body(
556
b"foo": (b"branch", branch_name),
557
b"": (b"branch", branch_name)}), b"success")
558
client.add_success_response(
559
b'ok', b'', b'no', b'no', b'no',
560
reference_bzrdir_format.repository_format.network_name())
561
client.add_error_response(b'NotStacked')
562
client.add_success_response(
563
b'ok', b'', b'no', b'no', b'no',
564
reference_bzrdir_format.repository_format.network_name())
565
client.add_error_response(b'NotStacked')
566
transport.mkdir('quack')
567
transport = transport.clone('quack')
568
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
570
result = a_controldir.get_branches()
571
self.assertEqual({"", "foo"}, set(result.keys()))
573
[('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
574
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
575
('call', b'Branch.get_stacked_on_url', (b'quack/', )),
576
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
577
('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
581
class TestBzrDirDestroyBranch(TestRemote):
583
def test_destroy_default(self):
584
transport = self.get_transport('quack')
585
referenced = self.make_branch('referenced')
586
client = FakeClient(transport.base)
587
client.add_expected_call(
588
b'BzrDir.destroy_branch', (b'quack/', ),
589
b'success', (b'ok',)),
590
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
592
a_controldir.destroy_branch()
593
self.assertFinished(client)
596
class TestBzrDirHasWorkingTree(TestRemote):
598
def test_has_workingtree(self):
599
transport = self.get_transport('quack')
600
client = FakeClient(transport.base)
601
client.add_expected_call(
602
b'BzrDir.has_workingtree', (b'quack/',),
603
b'success', (b'yes',)),
604
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
606
self.assertTrue(a_controldir.has_workingtree())
607
self.assertFinished(client)
609
def test_no_workingtree(self):
610
transport = self.get_transport('quack')
611
client = FakeClient(transport.base)
612
client.add_expected_call(
613
b'BzrDir.has_workingtree', (b'quack/',),
614
b'success', (b'no',)),
615
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
617
self.assertFalse(a_controldir.has_workingtree())
618
self.assertFinished(client)
621
class TestBzrDirDestroyRepository(TestRemote):
623
def test_destroy_repository(self):
624
transport = self.get_transport('quack')
625
client = FakeClient(transport.base)
626
client.add_expected_call(
627
b'BzrDir.destroy_repository', (b'quack/',),
628
b'success', (b'ok',)),
629
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
631
a_controldir.destroy_repository()
632
self.assertFinished(client)
484
635
class TestBzrDirOpen(TestRemote):
632
783
network_name = reference_format.network_name()
633
784
branch_network_name = self.get_branch_format().network_name()
634
785
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(),
786
b'BzrDir.open_branchV3', (b'~hello/',),
787
b'success', (b'branch', branch_network_name))
788
client.add_expected_call(
789
b'BzrDir.find_repositoryV3', (b'~hello/',),
790
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
791
client.add_expected_call(
792
b'Branch.get_stacked_on_url', (b'~hello/',),
793
b'error', (b'NotStacked',))
794
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
645
796
result = bzrdir.open_branch()
646
797
self.assertFinished(client)
648
def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
799
def check_open_repository(self, rich_root, subtrees, external_lookup=b'no'):
649
800
reference_format = self.get_repo_format()
650
801
network_name = reference_format.network_name()
651
802
transport = MemoryTransport()
652
803
transport.mkdir('quack')
653
804
transport = transport.clone('quack')
655
rich_response = 'yes'
806
rich_response = b'yes'
808
rich_response = b'no'
659
subtree_response = 'yes'
810
subtree_response = b'yes'
661
subtree_response = 'no'
812
subtree_response = b'no'
662
813
client = FakeClient(transport.base)
663
814
client.add_success_response(
664
'ok', '', rich_response, subtree_response, external_lookup,
815
b'ok', b'', rich_response, subtree_response, external_lookup,
666
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
817
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
819
result = bzrdir.open_repository()
669
820
self.assertEqual(
670
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
821
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
672
823
self.assertIsInstance(result, RemoteRepository)
673
self.assertEqual(bzrdir, result.bzrdir)
824
self.assertEqual(bzrdir, result.controldir)
674
825
self.assertEqual(rich_root, result._format.rich_root_data)
675
826
self.assertEqual(subtrees, result._format.supports_tree_reference)
706
857
transport = transport.clone('quack')
707
858
self.make_repository('quack')
708
859
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()
860
reference_bzrdir_format = controldir.format_registry.get('default')()
861
reference_format = reference_bzrdir_format.get_branch_format()
862
network_name = reference_format.network_name()
863
reference_repo_fmt = reference_bzrdir_format.repository_format
864
reference_repo_name = reference_repo_fmt.network_name()
865
client.add_expected_call(
866
b'BzrDir.create_branch', (b'quack/', network_name),
867
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
868
reference_repo_name))
869
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
871
branch = a_controldir.create_branch()
872
# We should have got a remote branch
873
self.assertIsInstance(branch, remote.RemoteBranch)
874
# its format should have the settings from the response
875
format = branch._format
876
self.assertEqual(network_name, format.network_name())
878
def test_already_open_repo_and_reused_medium(self):
879
"""Bug 726584: create_branch(..., repository=repo) should work
880
regardless of what the smart medium's base URL is.
882
self.transport_server = test_server.SmartTCPServer_for_testing
883
transport = self.get_transport('.')
884
repo = self.make_repository('quack')
885
# Client's medium rooted a transport root (not at the bzrdir)
886
client = FakeClient(transport.base)
887
transport = transport.clone('quack')
888
reference_bzrdir_format = controldir.format_registry.get('default')()
889
reference_format = reference_bzrdir_format.get_branch_format()
890
network_name = reference_format.network_name()
891
reference_repo_fmt = reference_bzrdir_format.repository_format
892
reference_repo_name = reference_repo_fmt.network_name()
893
client.add_expected_call(
894
b'BzrDir.create_branch', (b'extra/quack/', network_name),
895
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
896
reference_repo_name))
897
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
899
branch = a_controldir.create_branch(repository=repo)
721
900
# We should have got a remote branch
722
901
self.assertIsInstance(branch, remote.RemoteBranch)
723
902
# its format should have the settings from the response
772
951
server_url = 'bzr://example.com/'
773
952
self.permit_url(server_url)
774
953
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')
954
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
955
client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
956
client.add_success_response(b'ok', b'', b'no', b'no')
778
957
# A real repository instance will be created to determine the network
780
959
client.add_success_response_with_body(
781
"Bazaar-NG meta directory, format 1\n", 'ok')
960
b"Bazaar-NG meta directory, format 1\n", b'ok')
961
client.add_success_response(b'stat', b'0', b'65535')
782
962
client.add_success_response_with_body(
783
reference_format.get_format_string(), 'ok')
963
reference_format.get_format_string(), b'ok')
784
964
# PackRepository wants to do a stat
785
client.add_success_response('stat', '0', '65535')
965
client.add_success_response(b'stat', b'0', b'65535')
786
966
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
788
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
968
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
790
970
repo = bzrdir.open_repository()
791
971
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',)),
972
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
973
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
974
('call', b'BzrDir.find_repository', (b'quack/',)),
975
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
976
('call', b'stat', (b'/quack/.bzr',)),
977
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
978
('call', b'stat', (b'/quack/.bzr/repository',)),
800
981
self.assertEqual(network_name, repo._format.network_name())
806
987
server_url = 'bzr://example.com/'
807
988
self.permit_url(server_url)
808
989
client = FakeClient(server_url)
809
client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
client.add_success_response('ok', '', 'no', 'no', 'no')
990
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
991
client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
992
# A real repository instance will be created to determine the network
813
994
client.add_success_response_with_body(
814
"Bazaar-NG meta directory, format 1\n", 'ok')
995
b"Bazaar-NG meta directory, format 1\n", b'ok')
996
client.add_success_response(b'stat', b'0', b'65535')
815
997
client.add_success_response_with_body(
816
reference_format.get_format_string(), 'ok')
998
reference_format.get_format_string(), b'ok')
817
999
# PackRepository wants to do a stat
818
client.add_success_response('stat', '0', '65535')
1000
client.add_success_response(b'stat', b'0', b'65535')
819
1001
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
821
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
1003
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
823
1005
repo = bzrdir.open_repository()
824
1006
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',)),
1007
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1008
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1009
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1010
('call', b'stat', (b'/quack/.bzr',)),
1011
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
1012
('call', b'stat', (b'/quack/.bzr/repository',)),
832
1015
self.assertEqual(network_name, repo._format.network_name())
1134
1371
self.calls.append(('set_tags_bytes', bytes))
1135
1372
real_branch = StubRealBranch()
1136
1373
branch._real_branch = real_branch
1137
branch._set_tags_bytes('tags bytes')
1374
branch._set_tags_bytes(b'tags bytes')
1138
1375
# 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)
1377
branch._set_tags_bytes(b'tags bytes')
1378
self.assertFinished(client)
1380
[('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
1383
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1385
def test_uses_last_revision_info_and_tags_by_default(self):
1386
transport = MemoryTransport()
1387
client = FakeClient(transport.base)
1388
client.add_expected_call(
1389
b'Branch.get_stacked_on_url', (b'quack/',),
1390
b'error', (b'NotStacked',))
1391
client.add_expected_call(
1392
b'Branch.last_revision_info', (b'quack/',),
1393
b'success', (b'ok', b'1', b'rev-tip'))
1394
client.add_expected_call(
1395
b'Branch.get_config_file', (b'quack/',),
1396
b'success', (b'ok',), b'')
1397
transport.mkdir('quack')
1398
transport = transport.clone('quack')
1399
branch = self.make_remote_branch(transport, client)
1400
result = branch.heads_to_fetch()
1401
self.assertFinished(client)
1402
self.assertEqual(({b'rev-tip'}, set()), result)
1404
def test_uses_last_revision_info_and_tags_when_set(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'branch.fetch_tags = True')
1416
# XXX: this will break if the default format's serialization of tags
1417
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1418
client.add_expected_call(
1419
b'Branch.get_tags_bytes', (b'quack/',),
1420
b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
1421
transport.mkdir('quack')
1422
transport = transport.clone('quack')
1423
branch = self.make_remote_branch(transport, client)
1424
result = branch.heads_to_fetch()
1425
self.assertFinished(client)
1427
({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
1429
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1430
transport = MemoryTransport()
1431
client = FakeClient(transport.base)
1432
client.add_expected_call(
1433
b'Branch.get_stacked_on_url', (b'quack/',),
1434
b'error', (b'NotStacked',))
1435
client.add_expected_call(
1436
b'Branch.heads_to_fetch', (b'quack/',),
1437
b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
1438
transport.mkdir('quack')
1439
transport = transport.clone('quack')
1440
branch = self.make_remote_branch(transport, client)
1441
branch._format._use_default_local_heads_to_fetch = lambda: False
1442
result = branch.heads_to_fetch()
1443
self.assertFinished(client)
1444
self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
1446
def make_branch_with_tags(self):
1447
self.setup_smart_server_with_call_log()
1448
# Make a branch with a single revision.
1449
builder = self.make_branch_builder('foo')
1450
builder.start_series()
1451
builder.build_snapshot(None, [
1452
('add', ('', b'root-id', 'directory', ''))],
1454
builder.finish_series()
1455
branch = builder.get_branch()
1456
# Add two tags to that branch
1457
branch.tags.set_tag('tag-1', b'rev-1')
1458
branch.tags.set_tag('tag-2', b'rev-2')
1461
def test_backwards_compatible(self):
1462
br = self.make_branch_with_tags()
1463
br.get_config_stack().set('branch.fetch_tags', True)
1464
self.addCleanup(br.lock_read().unlock)
1465
# Disable the heads_to_fetch verb
1466
verb = b'Branch.heads_to_fetch'
1467
self.disable_verb(verb)
1468
self.reset_smart_call_log()
1469
result = br.heads_to_fetch()
1470
self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
1472
[b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
1473
[call.call.method for call in self.hpss_calls])
1475
def test_backwards_compatible_no_tags(self):
1476
br = self.make_branch_with_tags()
1477
br.get_config_stack().set('branch.fetch_tags', False)
1478
self.addCleanup(br.lock_read().unlock)
1479
# Disable the heads_to_fetch verb
1480
verb = b'Branch.heads_to_fetch'
1481
self.disable_verb(verb)
1482
self.reset_smart_call_log()
1483
result = br.heads_to_fetch()
1484
self.assertEqual(({b'tip'}, set()), result)
1486
[b'Branch.last_revision_info'],
1487
[call.call.method for call in self.hpss_calls])
1146
1490
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1292
1636
client = FakeClient(transport.base)
1293
1637
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'),
1638
b'Branch.get_stacked_on_url', (b'branch/',),
1639
b'error', (b'NotStacked',))
1640
client.add_expected_call(
1641
b'Branch.lock_write', (b'branch/', b'', b''),
1642
b'success', (b'ok', b'branch token', b'repo token'))
1643
client.add_expected_call(
1644
b'Branch.last_revision_info',
1646
b'success', (b'ok', b'0', b'null:'))
1647
client.add_expected_call(
1648
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
1649
b'success', (b'ok',))
1650
client.add_expected_call(
1651
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1652
b'success', (b'ok',))
1309
1653
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
1654
branch.lock_write()
1314
result = branch.set_revision_history([])
1655
result = branch._set_last_revision(NULL_REVISION)
1315
1656
branch.unlock()
1316
1657
self.assertEqual(None, result)
1317
1658
self.assertFinished(client)
1319
1660
def test_set_nonempty(self):
1320
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1661
# set_last_revision_info(N, rev-idN) is translated to calling
1321
1662
# Branch.set_last_revision(path, rev-idN) on the wire.
1322
1663
transport = MemoryTransport()
1323
1664
transport.mkdir('branch')
1326
1667
client = FakeClient(transport.base)
1327
1668
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'),
1669
b'Branch.get_stacked_on_url', (b'branch/',),
1670
b'error', (b'NotStacked',))
1671
client.add_expected_call(
1672
b'Branch.lock_write', (b'branch/', b'', b''),
1673
b'success', (b'ok', b'branch token', b'repo token'))
1674
client.add_expected_call(
1675
b'Branch.last_revision_info',
1677
b'success', (b'ok', b'0', b'null:'))
1678
lines = [b'rev-id2']
1679
encoded_body = bz2.compress(b'\n'.join(lines))
1680
client.add_success_response_with_body(encoded_body, b'ok')
1681
client.add_expected_call(
1682
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
1683
b'success', (b'ok',))
1684
client.add_expected_call(
1685
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1686
b'success', (b'ok',))
1346
1687
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
1688
# Lock the branch, reset the record of remote calls.
1351
1689
branch.lock_write()
1352
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1690
result = branch._set_last_revision(b'rev-id2')
1353
1691
branch.unlock()
1354
1692
self.assertEqual(None, result)
1355
1693
self.assertFinished(client)
1361
1699
# A response of 'NoSuchRevision' is translated into an exception.
1362
1700
client = FakeClient(transport.base)
1363
1701
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:'))
1702
b'Branch.get_stacked_on_url', (b'branch/',),
1703
b'error', (b'NotStacked',))
1704
client.add_expected_call(
1705
b'Branch.lock_write', (b'branch/', b'', b''),
1706
b'success', (b'ok', b'branch token', b'repo token'))
1707
client.add_expected_call(
1708
b'Branch.last_revision_info',
1710
b'success', (b'ok', b'0', b'null:'))
1373
1711
# 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'),
1714
encoded_body = bz2.compress(b'\n'.join(lines))
1715
client.add_success_response_with_body(encoded_body, b'ok')
1716
client.add_expected_call(
1717
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1718
b'error', (b'NoSuchRevision', b'rev-id'))
1719
client.add_expected_call(
1720
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1721
b'success', (b'ok',))
1385
1723
branch = self.make_remote_branch(transport, client)
1386
1724
branch.lock_write()
1387
1725
self.assertRaises(
1388
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1726
errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1727
branch.unlock()
1390
1728
self.assertFinished(client)
1400
1738
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1739
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1740
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'),
1741
b'Branch.get_stacked_on_url', (b'branch/',),
1742
b'error', (b'NotStacked',))
1743
client.add_expected_call(
1744
b'Branch.lock_write', (b'branch/', b'', b''),
1745
b'success', (b'ok', b'branch token', b'repo token'))
1746
client.add_expected_call(
1747
b'Branch.last_revision_info',
1749
b'success', (b'ok', b'0', b'null:'))
1751
encoded_body = bz2.compress(b'\n'.join(lines))
1752
client.add_success_response_with_body(encoded_body, b'ok')
1753
client.add_expected_call(
1754
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1755
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1756
client.add_expected_call(
1757
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1758
b'success', (b'ok',))
1421
1759
branch = self.make_remote_branch(transport, client)
1422
branch._ensure_real = lambda: None
1423
1760
branch.lock_write()
1424
1761
# The 'TipChangeRejected' error response triggered by calling
1425
# set_revision_history causes a TipChangeRejected exception.
1762
# set_last_revision_info causes a TipChangeRejected exception.
1426
1763
err = self.assertRaises(
1427
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1764
errors.TipChangeRejected,
1765
branch._set_last_revision, b'rev-id')
1428
1766
# The UTF-8 message from the response has been decoded into a unicode
1430
self.assertIsInstance(err.msg, unicode)
1768
self.assertIsInstance(err.msg, text_type)
1431
1769
self.assertEqual(rejection_msg_unicode, err.msg)
1432
1770
branch.unlock()
1433
1771
self.assertFinished(client)
1652
1990
branch.unlock()
1653
1991
self.assertFinished(client)
1993
def test_set_option_with_dict(self):
1994
client = FakeClient()
1995
client.add_expected_call(
1996
b'Branch.get_stacked_on_url', (b'memory:///',),
1997
b'error', (b'NotStacked',),)
1998
client.add_expected_call(
1999
b'Branch.lock_write', (b'memory:///', b'', b''),
2000
b'success', (b'ok', b'branch token', b'repo token'))
2001
encoded_dict_value = b'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
2002
client.add_expected_call(
2003
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2004
b'repo token', encoded_dict_value, b'foo', b''),
2006
client.add_expected_call(
2007
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2008
b'success', (b'ok',))
2009
transport = MemoryTransport()
2010
branch = self.make_remote_branch(transport, client)
2012
config = branch._get_config()
2014
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
2017
self.assertFinished(client)
1655
2019
def test_backwards_compat_set_option(self):
1656
2020
self.setup_smart_server_with_call_log()
1657
2021
branch = self.make_branch('.')
1658
verb = 'Branch.set_config_option'
2022
verb = b'Branch.set_config_option'
1659
2023
self.disable_verb(verb)
1660
2024
branch.lock_write()
1661
2025
self.addCleanup(branch.unlock)
1662
2026
self.reset_smart_call_log()
1663
2027
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2028
self.assertLength(11, self.hpss_calls)
1665
2029
self.assertEqual('value', branch._get_config().get_option('name'))
2031
def test_backwards_compat_set_option_with_dict(self):
2032
self.setup_smart_server_with_call_log()
2033
branch = self.make_branch('.')
2034
verb = b'Branch.set_config_option_dict'
2035
self.disable_verb(verb)
2037
self.addCleanup(branch.unlock)
2038
self.reset_smart_call_log()
2039
config = branch._get_config()
2040
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2041
config.set_option(value_dict, 'name')
2042
self.assertLength(11, self.hpss_calls)
2043
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2046
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2048
def test_get_branch_conf(self):
2049
# in an empty branch we decode the response properly
2050
client = FakeClient()
2051
client.add_expected_call(
2052
b'Branch.get_stacked_on_url', (b'memory:///',),
2053
b'error', (b'NotStacked',),)
2054
client.add_success_response_with_body(b'# config file body', b'ok')
2055
transport = MemoryTransport()
2056
branch = self.make_remote_branch(transport, client)
2057
config = branch.get_config_stack()
2059
config.get("log_format")
2061
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2062
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
2065
def test_set_branch_conf(self):
2066
client = FakeClient()
2067
client.add_expected_call(
2068
b'Branch.get_stacked_on_url', (b'memory:///',),
2069
b'error', (b'NotStacked',),)
2070
client.add_expected_call(
2071
b'Branch.lock_write', (b'memory:///', b'', b''),
2072
b'success', (b'ok', b'branch token', b'repo token'))
2073
client.add_expected_call(
2074
b'Branch.get_config_file', (b'memory:///', ),
2075
b'success', (b'ok', ), b"# line 1\n")
2076
client.add_expected_call(
2077
b'Branch.get_config_file', (b'memory:///', ),
2078
b'success', (b'ok', ), b"# line 1\n")
2079
client.add_expected_call(
2080
b'Branch.put_config_file', (b'memory:///', b'branch token',
2082
b'success', (b'ok',))
2083
client.add_expected_call(
2084
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2085
b'success', (b'ok',))
2086
transport = MemoryTransport()
2087
branch = self.make_remote_branch(transport, client)
2089
config = branch.get_config_stack()
2090
config.set('email', 'The Dude <lebowski@example.com>')
2092
self.assertFinished(client)
2094
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2095
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2096
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2097
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2098
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2099
(b'memory:///', b'branch token', b'repo token'),
2100
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2101
('call', b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'))],
1668
2105
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2120
self.assertFinished(client)
2123
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2125
def test_simple(self):
2126
transport = MemoryTransport()
2127
client = FakeClient(transport.base)
2128
client.add_expected_call(
2129
b'Branch.get_stacked_on_url', (b'quack/',),
2130
b'error', (b'NotStacked',),)
2131
client.add_expected_call(
2132
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2133
b'success', (b'ok', b'0',),)
2134
client.add_expected_call(
2135
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2136
b'error', (b'NoSuchRevision', b'unknown',),)
2137
transport.mkdir('quack')
2138
transport = transport.clone('quack')
2139
branch = self.make_remote_branch(transport, client)
2140
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2141
self.assertRaises(errors.NoSuchRevision,
2142
branch.revision_id_to_revno, b'unknown')
2143
self.assertFinished(client)
2145
def test_dotted(self):
2146
transport = MemoryTransport()
2147
client = FakeClient(transport.base)
2148
client.add_expected_call(
2149
b'Branch.get_stacked_on_url', (b'quack/',),
2150
b'error', (b'NotStacked',),)
2151
client.add_expected_call(
2152
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2153
b'success', (b'ok', b'0',),)
2154
client.add_expected_call(
2155
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2156
b'error', (b'NoSuchRevision', b'unknown',),)
2157
transport.mkdir('quack')
2158
transport = transport.clone('quack')
2159
branch = self.make_remote_branch(transport, client)
2160
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2161
self.assertRaises(errors.NoSuchRevision,
2162
branch.revision_id_to_dotted_revno, b'unknown')
2163
self.assertFinished(client)
2165
def test_dotted_no_smart_verb(self):
2166
self.setup_smart_server_with_call_log()
2167
branch = self.make_branch('.')
2168
self.disable_verb(b'Branch.revision_id_to_revno')
2169
self.reset_smart_call_log()
2170
self.assertEqual((0, ),
2171
branch.revision_id_to_dotted_revno(b'null:'))
2172
self.assertLength(8, self.hpss_calls)
1686
2175
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2177
def test__get_config(self):
1689
2178
client = FakeClient()
1690
client.add_success_response_with_body('default_stack_on = /\n', 'ok')
2179
client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2180
transport = MemoryTransport()
1692
2181
bzrdir = self.make_remote_bzrdir(transport, client)
1693
2182
config = bzrdir.get_config()
1694
2183
self.assertEqual('/', config.get_default_stack_on())
1695
2184
self.assertEqual(
1696
[('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
2185
[('call_expecting_body', b'BzrDir.get_config_file', (b'memory:///',))],
1699
2188
def test_set_option_uses_vfs(self):
1700
2189
self.setup_smart_server_with_call_log()
1701
bzrdir = self.make_bzrdir('.')
2190
bzrdir = self.make_controldir('.')
1702
2191
self.reset_smart_call_log()
1703
2192
config = bzrdir.get_config()
1704
2193
config.set_default_stack_on('/')
1705
self.assertLength(3, self.hpss_calls)
2194
self.assertLength(4, self.hpss_calls)
1707
2196
def test_backwards_compat_get_option(self):
1708
2197
self.setup_smart_server_with_call_log()
1709
bzrdir = self.make_bzrdir('.')
1710
verb = 'BzrDir.get_config_file'
2198
bzrdir = self.make_controldir('.')
2199
verb = b'BzrDir.get_config_file'
1711
2200
self.disable_verb(verb)
1712
2201
self.reset_smart_call_log()
1713
2202
self.assertEqual(None,
1714
2203
bzrdir._get_config().get_option('default_stack_on'))
1715
self.assertLength(3, self.hpss_calls)
2204
self.assertLength(4, self.hpss_calls)
1718
2207
class TestTransportIsReadonly(tests.TestCase):
1720
2209
def test_true(self):
1721
2210
client = FakeClient()
1722
client.add_success_response('yes')
2211
client.add_success_response(b'yes')
1723
2212
transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2213
_client=client)
1725
2214
self.assertEqual(True, transport.is_readonly())
1726
2215
self.assertEqual(
1727
[('call', 'Transport.is_readonly', ())],
2216
[('call', b'Transport.is_readonly', ())],
1730
2219
def test_false(self):
1731
2220
client = FakeClient()
1732
client.add_success_response('no')
2221
client.add_success_response(b'no')
1733
2222
transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2223
_client=client)
1735
2224
self.assertEqual(False, transport.is_readonly())
1736
2225
self.assertEqual(
1737
[('call', 'Transport.is_readonly', ())],
2226
[('call', b'Transport.is_readonly', ())],
1740
2229
def test_error_from_old_server(self):
2421
class TestRepositoryBreakLock(TestRemoteRepository):
2423
def test_break_lock(self):
2424
transport_path = 'quack'
2425
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
client.add_success_response(b'ok')
2429
[('call', b'Repository.break_lock', (b'quack/',))],
2433
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2435
def test_get_serializer_format(self):
2436
transport_path = 'hill'
2437
repo, client = self.setup_fake_client_and_repository(transport_path)
2438
client.add_success_response(b'ok', b'7')
2439
self.assertEqual(b'7', repo.get_serializer_format())
2441
[('call', b'VersionedFileRepository.get_serializer_format',
2446
class TestRepositoryReconcile(TestRemoteRepository):
2448
def test_reconcile(self):
2449
transport_path = 'hill'
2450
repo, client = self.setup_fake_client_and_repository(transport_path)
2451
body = (b"garbage_inventories: 2\n"
2452
b"inconsistent_parents: 3\n")
2453
client.add_expected_call(
2454
b'Repository.lock_write', (b'hill/', b''),
2455
b'success', (b'ok', b'a token'))
2456
client.add_success_response_with_body(body, b'ok')
2457
reconciler = repo.reconcile()
2459
[('call', b'Repository.lock_write', (b'hill/', b'')),
2460
('call_expecting_body', b'Repository.reconcile',
2461
(b'hill/', b'a token'))],
2463
self.assertEqual(2, reconciler.garbage_inventories)
2464
self.assertEqual(3, reconciler.inconsistent_parents)
2467
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2469
def test_text(self):
2470
# ('ok',), body with signature text
2471
transport_path = 'quack'
2472
repo, client = self.setup_fake_client_and_repository(transport_path)
2473
client.add_success_response_with_body(
2475
self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
2477
[('call_expecting_body', b'Repository.get_revision_signature_text',
2478
(b'quack/', b'revid'))],
2481
def test_no_signature(self):
2482
transport_path = 'quick'
2483
repo, client = self.setup_fake_client_and_repository(transport_path)
2484
client.add_error_response(b'nosuchrevision', b'unknown')
2485
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2488
[('call_expecting_body', b'Repository.get_revision_signature_text',
2489
(b'quick/', b'unknown'))],
1906
2493
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2495
def test_get_graph(self):
2257
2932
self.setup_smart_server_with_call_log()
2258
2933
tree = self.make_branch_and_memory_tree('.')
2259
2934
tree.lock_write()
2260
2936
rev1 = tree.commit('First')
2261
2937
rev2 = tree.commit('Second')
2263
2939
branch = tree.branch
2264
2940
self.assertFalse(branch.is_locked())
2265
2941
self.reset_smart_call_log()
2266
verb = 'Repository.get_rev_id_for_revno'
2942
verb = b'Repository.get_rev_id_for_revno'
2267
2943
self.disable_verb(verb)
2268
2944
self.assertEqual(rev1, branch.get_rev_id(1))
2269
2945
self.assertLength(1, [call for call in self.hpss_calls if
2270
2946
call.call.method == verb])
2949
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2951
def test_has_signature_for_revision_id(self):
2952
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2953
transport_path = 'quack'
2954
repo, client = self.setup_fake_client_and_repository(transport_path)
2955
client.add_success_response(b'yes')
2956
result = repo.has_signature_for_revision_id(b'A')
2958
[('call', b'Repository.has_signature_for_revision_id',
2959
(b'quack/', b'A'))],
2961
self.assertEqual(True, result)
2963
def test_is_not_shared(self):
2964
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2965
transport_path = 'qwack'
2966
repo, client = self.setup_fake_client_and_repository(transport_path)
2967
client.add_success_response(b'no')
2968
result = repo.has_signature_for_revision_id(b'A')
2970
[('call', b'Repository.has_signature_for_revision_id',
2971
(b'qwack/', b'A'))],
2973
self.assertEqual(False, result)
2976
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2978
def test_get_physical_lock_status_yes(self):
2979
transport_path = 'qwack'
2980
repo, client = self.setup_fake_client_and_repository(transport_path)
2981
client.add_success_response(b'yes')
2982
result = repo.get_physical_lock_status()
2984
[('call', b'Repository.get_physical_lock_status',
2987
self.assertEqual(True, result)
2989
def test_get_physical_lock_status_no(self):
2990
transport_path = 'qwack'
2991
repo, client = self.setup_fake_client_and_repository(transport_path)
2992
client.add_success_response(b'no')
2993
result = repo.get_physical_lock_status()
2995
[('call', b'Repository.get_physical_lock_status',
2998
self.assertEqual(False, result)
2273
3001
class TestRepositoryIsShared(TestRemoteRepository):
2275
3003
def test_is_shared(self):
2276
3004
# ('yes', ) for Repository.is_shared -> 'True'.
2277
3005
transport_path = 'quack'
2278
3006
repo, client = self.setup_fake_client_and_repository(transport_path)
2279
client.add_success_response('yes')
3007
client.add_success_response(b'yes')
2280
3008
result = repo.is_shared()
2281
3009
self.assertEqual(
2282
[('call', 'Repository.is_shared', ('quack/',))],
3010
[('call', b'Repository.is_shared', (b'quack/',))],
2284
3012
self.assertEqual(True, result)
2300
3053
def test_lock_write(self):
2301
3054
transport_path = 'quack'
2302
3055
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
3056
client.add_success_response(b'ok', b'a token')
3057
token = repo.lock_write().repository_token
2305
3058
self.assertEqual(
2306
[('call', 'Repository.lock_write', ('quack/', ''))],
3059
[('call', b'Repository.lock_write', (b'quack/', b''))],
2308
self.assertEqual('a token', result)
3061
self.assertEqual(b'a token', token)
2310
3063
def test_lock_write_already_locked(self):
2311
3064
transport_path = 'quack'
2312
3065
repo, client = self.setup_fake_client_and_repository(transport_path)
2313
client.add_error_response('LockContention')
3066
client.add_error_response(b'LockContention')
2314
3067
self.assertRaises(errors.LockContention, repo.lock_write)
2315
3068
self.assertEqual(
2316
[('call', 'Repository.lock_write', ('quack/', ''))],
3069
[('call', b'Repository.lock_write', (b'quack/', b''))],
2319
3072
def test_lock_write_unlockable(self):
2320
3073
transport_path = 'quack'
2321
3074
repo, client = self.setup_fake_client_and_repository(transport_path)
2322
client.add_error_response('UnlockableTransport')
3075
client.add_error_response(b'UnlockableTransport')
2323
3076
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3077
self.assertEqual(
2325
[('call', 'Repository.lock_write', ('quack/', ''))],
3078
[('call', b'Repository.lock_write', (b'quack/', b''))],
3082
class TestRepositoryWriteGroups(TestRemoteRepository):
3084
def test_start_write_group(self):
3085
transport_path = 'quack'
3086
repo, client = self.setup_fake_client_and_repository(transport_path)
3087
client.add_expected_call(
3088
b'Repository.lock_write', (b'quack/', b''),
3089
b'success', (b'ok', b'a token'))
3090
client.add_expected_call(
3091
b'Repository.start_write_group', (b'quack/', b'a token'),
3092
b'success', (b'ok', (b'token1', )))
3094
repo.start_write_group()
3096
def test_start_write_group_unsuspendable(self):
3097
# Some repositories do not support suspending write
3098
# groups. For those, fall back to the "real" repository.
3099
transport_path = 'quack'
3100
repo, client = self.setup_fake_client_and_repository(transport_path)
3101
def stub_ensure_real():
3102
client._calls.append(('_ensure_real',))
3103
repo._real_repository = _StubRealPackRepository(client._calls)
3104
repo._ensure_real = stub_ensure_real
3105
client.add_expected_call(
3106
b'Repository.lock_write', (b'quack/', b''),
3107
b'success', (b'ok', b'a token'))
3108
client.add_expected_call(
3109
b'Repository.start_write_group', (b'quack/', b'a token'),
3110
b'error', (b'UnsuspendableWriteGroup',))
3112
repo.start_write_group()
3113
self.assertEqual(client._calls[-2:], [
3115
('start_write_group',)])
3117
def test_commit_write_group(self):
3118
transport_path = 'quack'
3119
repo, client = self.setup_fake_client_and_repository(transport_path)
3120
client.add_expected_call(
3121
b'Repository.lock_write', (b'quack/', b''),
3122
b'success', (b'ok', b'a token'))
3123
client.add_expected_call(
3124
b'Repository.start_write_group', (b'quack/', b'a token'),
3125
b'success', (b'ok', [b'token1']))
3126
client.add_expected_call(
3127
b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
3128
b'success', (b'ok',))
3130
repo.start_write_group()
3131
repo.commit_write_group()
3133
def test_abort_write_group(self):
3134
transport_path = 'quack'
3135
repo, client = self.setup_fake_client_and_repository(transport_path)
3136
client.add_expected_call(
3137
b'Repository.lock_write', (b'quack/', b''),
3138
b'success', (b'ok', b'a token'))
3139
client.add_expected_call(
3140
b'Repository.start_write_group', (b'quack/', b'a token'),
3141
b'success', (b'ok', [b'token1']))
3142
client.add_expected_call(
3143
b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
3144
b'success', (b'ok',))
3146
repo.start_write_group()
3147
repo.abort_write_group(False)
3149
def test_suspend_write_group(self):
3150
transport_path = 'quack'
3151
repo, client = self.setup_fake_client_and_repository(transport_path)
3152
self.assertEqual([], repo.suspend_write_group())
3154
def test_resume_write_group(self):
3155
transport_path = 'quack'
3156
repo, client = self.setup_fake_client_and_repository(transport_path)
3157
client.add_expected_call(
3158
b'Repository.lock_write', (b'quack/', b''),
3159
b'success', (b'ok', b'a token'))
3160
client.add_expected_call(
3161
b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
3162
b'success', (b'ok',))
3164
repo.resume_write_group(['token1'])
2329
3167
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3169
def test_backwards_compat(self):
2332
3170
self.setup_smart_server_with_call_log()
2333
3171
repo = self.make_repository('.')
2334
3172
self.reset_smart_call_log()
2335
verb = 'Repository.set_make_working_trees'
3173
verb = b'Repository.set_make_working_trees'
2336
3174
self.disable_verb(verb)
2337
3175
repo.set_make_working_trees(True)
2338
3176
call_count = len([call for call in self.hpss_calls if
2419
3284
def setUp(self):
2420
TestRemoteRepository.setUp(self)
2421
self.disable_verb('Repository.insert_stream_1.19')
3285
super(TestRepositoryInsertStream, self).setUp()
3286
self.disable_verb(b'Repository.insert_stream_1.19')
2423
3288
def test_unlocked_repo(self):
2424
3289
transport_path = 'quack'
2425
3290
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3291
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/', ''),
3292
b'Repository.insert_stream_1.19', (b'quack/', b''),
3293
b'unknown', (b'Repository.insert_stream_1.19',))
3294
client.add_expected_call(
3295
b'Repository.insert_stream', (b'quack/', b''),
3296
b'success', (b'ok',))
3297
client.add_expected_call(
3298
b'Repository.insert_stream', (b'quack/', b''),
3299
b'success', (b'ok',))
2435
3300
self.checkInsertEmptyStream(repo, client)
2437
3302
def test_locked_repo_with_no_lock_token(self):
2438
3303
transport_path = 'quack'
2439
3304
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3305
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/', ''),
3306
b'Repository.lock_write', (b'quack/', b''),
3307
b'success', (b'ok', b''))
3308
client.add_expected_call(
3309
b'Repository.insert_stream_1.19', (b'quack/', b''),
3310
b'unknown', (b'Repository.insert_stream_1.19',))
3311
client.add_expected_call(
3312
b'Repository.insert_stream', (b'quack/', b''),
3313
b'success', (b'ok',))
3314
client.add_expected_call(
3315
b'Repository.insert_stream', (b'quack/', b''),
3316
b'success', (b'ok',))
2452
3317
repo.lock_write()
2453
3318
self.checkInsertEmptyStream(repo, client)
2534
3399
* texts substream: (some-rev, some-file)
2536
3401
# Define a stream using generators so that it isn't rewindable.
2537
inv = inventory.Inventory(revision_id='rev1')
2538
inv.root.revision = 'rev1'
3402
inv = inventory.Inventory(revision_id=b'rev1')
3403
inv.root.revision = b'rev1'
2539
3404
def stream_with_inv_delta():
2540
3405
yield ('inventories', inventories_substream())
2541
3406
yield ('inventory-deltas', inventory_delta_substream())
2542
3407
yield ('texts', [
2543
3408
versionedfile.FulltextContentFactory(
2544
('some-rev', 'some-file'), (), None, 'content')])
3409
(b'some-rev', b'some-file'), (), None, b'content')])
2545
3410
def inventories_substream():
2546
3411
# An empty inventory fulltext. This will be streamed normally.
2547
3412
text = fmt._serializer.write_inventory_to_string(inv)
2548
3413
yield versionedfile.FulltextContentFactory(
2549
('rev1',), (), None, text)
3414
(b'rev1',), (), None, text)
2550
3415
def inventory_delta_substream():
2551
3416
# An inventory delta. This can't be streamed via this verb, so it
2552
3417
# will trigger a fallback to VFS insert_stream.
2553
3418
entry = inv.make_entry(
2554
'directory', 'newdir', inv.root.file_id, 'newdir-id')
2555
entry.revision = 'ghost'
2556
delta = [(None, 'newdir', 'newdir-id', entry)]
3419
'directory', 'newdir', inv.root.file_id, b'newdir-id')
3420
entry.revision = b'ghost'
3421
delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3422
serializer = inventory_delta.InventoryDeltaSerializer(
2558
3423
versioned_root=True, tree_references=False)
2559
lines = serializer.delta_to_lines('rev1', 'rev2', delta)
3424
lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3425
yield versionedfile.ChunkedContentFactory(
2561
('rev2',), (('rev1',)), None, lines)
3426
(b'rev2',), ((b'rev1',)), None, lines)
2562
3427
# Another delta.
2563
lines = serializer.delta_to_lines('rev1', 'rev3', delta)
3428
lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3429
yield versionedfile.ChunkedContentFactory(
2565
('rev3',), (('rev1',)), None, lines)
3430
(b'rev3',), ((b'rev1',)), None, lines)
2566
3431
return stream_with_inv_delta()
2784
3662
def test_NoSuchRevision(self):
2785
3663
branch = self.make_branch('')
2787
3665
translated_error = self.translateTuple(
2788
('NoSuchRevision', revid), branch=branch)
3666
(b'NoSuchRevision', revid), branch=branch)
2789
3667
expected_error = errors.NoSuchRevision(branch, revid)
2790
3668
self.assertEqual(expected_error, translated_error)
2792
3670
def test_nosuchrevision(self):
2793
3671
repository = self.make_repository('')
2795
3673
translated_error = self.translateTuple(
2796
('nosuchrevision', revid), repository=repository)
3674
(b'nosuchrevision', revid), repository=repository)
2797
3675
expected_error = errors.NoSuchRevision(repository, revid)
2798
3676
self.assertEqual(expected_error, translated_error)
2800
3678
def test_nobranch(self):
2801
bzrdir = self.make_bzrdir('')
2802
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3679
bzrdir = self.make_controldir('')
3680
translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3681
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3682
self.assertEqual(expected_error, translated_error)
2806
3684
def test_nobranch_one_arg(self):
2807
bzrdir = self.make_bzrdir('')
3685
bzrdir = self.make_controldir('')
2808
3686
translated_error = self.translateTuple(
2809
('nobranch', 'extra detail'), bzrdir=bzrdir)
3687
(b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3688
expected_error = errors.NotBranchError(
2811
3689
path=bzrdir.root_transport.base,
2812
3690
detail='extra detail')
2813
3691
self.assertEqual(expected_error, translated_error)
3693
def test_norepository(self):
3694
bzrdir = self.make_controldir('')
3695
translated_error = self.translateTuple((b'norepository',),
3697
expected_error = errors.NoRepositoryPresent(bzrdir)
3698
self.assertEqual(expected_error, translated_error)
2815
3700
def test_LockContention(self):
2816
translated_error = self.translateTuple(('LockContention',))
3701
translated_error = self.translateTuple((b'LockContention',))
2817
3702
expected_error = errors.LockContention('(remote lock)')
2818
3703
self.assertEqual(expected_error, translated_error)
2820
3705
def test_UnlockableTransport(self):
2821
bzrdir = self.make_bzrdir('')
3706
bzrdir = self.make_controldir('')
2822
3707
translated_error = self.translateTuple(
2823
('UnlockableTransport',), bzrdir=bzrdir)
3708
(b'UnlockableTransport',), bzrdir=bzrdir)
2824
3709
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3710
self.assertEqual(expected_error, translated_error)
2827
3712
def test_LockFailed(self):
2828
3713
lock = 'str() of a server lock'
2829
3714
why = 'str() of why'
2830
translated_error = self.translateTuple(('LockFailed', lock, why))
3715
translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3716
expected_error = errors.LockFailed(lock, why)
2832
3717
self.assertEqual(expected_error, translated_error)
2834
3719
def test_TokenMismatch(self):
2835
3720
token = 'a lock token'
2836
translated_error = self.translateTuple(('TokenMismatch',), token=token)
3721
translated_error = self.translateTuple((b'TokenMismatch',), token=token)
2837
3722
expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3723
self.assertEqual(expected_error, translated_error)
2841
3726
branch = self.make_branch('a')
2842
3727
other_branch = self.make_branch('b')
2843
3728
translated_error = self.translateTuple(
2844
('Diverged',), branch=branch, other_branch=other_branch)
3729
(b'Diverged',), branch=branch, other_branch=other_branch)
2845
3730
expected_error = errors.DivergedBranches(branch, other_branch)
2846
3731
self.assertEqual(expected_error, translated_error)
3733
def test_NotStacked(self):
3734
branch = self.make_branch('')
3735
translated_error = self.translateTuple((b'NotStacked',), branch=branch)
3736
expected_error = errors.NotStacked(branch)
3737
self.assertEqual(expected_error, translated_error)
2848
3739
def test_ReadError_no_args(self):
2849
3740
path = 'a path'
2850
translated_error = self.translateTuple(('ReadError',), path=path)
3741
translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3742
expected_error = errors.ReadError(path)
2852
3743
self.assertEqual(expected_error, translated_error)
2854
3745
def test_ReadError(self):
2855
3746
path = 'a path'
2856
translated_error = self.translateTuple(('ReadError', path))
3747
translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
2857
3748
expected_error = errors.ReadError(path)
2858
3749
self.assertEqual(expected_error, translated_error)
2860
3751
def test_IncompatibleRepositories(self):
2861
translated_error = self.translateTuple(('IncompatibleRepositories',
2862
"repo1", "repo2", "details here"))
3752
translated_error = self.translateTuple((b'IncompatibleRepositories',
3753
b"repo1", b"repo2", b"details here"))
2863
3754
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2864
3755
"details here")
2865
3756
self.assertEqual(expected_error, translated_error)
3758
def test_GhostRevisionsHaveNoRevno(self):
3759
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3760
b"revid1", b"revid2"))
3761
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
3762
self.assertEqual(expected_error, translated_error)
2867
3764
def test_PermissionDenied_no_args(self):
2868
3765
path = 'a path'
2869
translated_error = self.translateTuple(('PermissionDenied',), path=path)
3766
translated_error = self.translateTuple((b'PermissionDenied',),
2870
3768
expected_error = errors.PermissionDenied(path)
2871
3769
self.assertEqual(expected_error, translated_error)
2873
3771
def test_PermissionDenied_one_arg(self):
2874
3772
path = 'a path'
2875
translated_error = self.translateTuple(('PermissionDenied', path))
3773
translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
2876
3774
expected_error = errors.PermissionDenied(path)
2877
3775
self.assertEqual(expected_error, translated_error)
3143
4082
def test_copy_content_into_avoids_revision_history(self):
3144
4083
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4084
builder = self.make_branch_builder('remote')
4085
builder.build_commit(message="Commit.")
3147
4086
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4087
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4088
local.repository.fetch(remote_branch.repository)
3150
4089
self.hpss_calls = []
3151
4090
remote_branch.copy_content_into(local)
3152
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4091
self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
4093
def test_fetch_everything_needs_just_one_call(self):
4094
local = self.make_branch('local')
4095
builder = self.make_branch_builder('remote')
4096
builder.build_commit(message="Commit.")
4097
remote_branch_url = self.smart_server.get_url() + 'remote'
4098
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4099
self.hpss_calls = []
4100
local.repository.fetch(
4101
remote_branch.repository,
4102
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4103
self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
4105
def override_verb(self, verb_name, verb):
4106
request_handlers = request.request_handlers
4107
orig_verb = request_handlers.get(verb_name)
4108
orig_info = request_handlers.get_info(verb_name)
4109
request_handlers.register(verb_name, verb, override_existing=True)
4110
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4111
override_existing=True, info=orig_info)
4113
def test_fetch_everything_backwards_compat(self):
4114
"""Can fetch with EverythingResult even with pre 2.4 servers.
4116
Pre-2.4 do not support 'everything' searches with the
4117
Repository.get_stream_1.19 verb.
4120
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4121
"""A version of the Repository.get_stream_1.19 verb patched to
4122
reject 'everything' searches the way 2.3 and earlier do.
4124
def recreate_search(self, repository, search_bytes,
4125
discard_excess=False):
4126
verb_log.append(search_bytes.split(b'\n', 1)[0])
4127
if search_bytes == b'everything':
4129
request.FailedSmartServerResponse((b'BadSearch',)))
4130
return super(OldGetStreamVerb,
4131
self).recreate_search(repository, search_bytes,
4132
discard_excess=discard_excess)
4133
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4134
local = self.make_branch('local')
4135
builder = self.make_branch_builder('remote')
4136
builder.build_commit(message="Commit.")
4137
remote_branch_url = self.smart_server.get_url() + 'remote'
4138
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4139
self.hpss_calls = []
4140
local.repository.fetch(
4141
remote_branch.repository,
4142
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4143
# make sure the overridden verb was used
4144
self.assertLength(1, verb_log)
4145
# more than one HPSS call is needed, but because it's a VFS callback
4146
# its hard to predict exactly how many.
4147
self.assertTrue(len(self.hpss_calls) > 1)
4150
class TestUpdateBoundBranchWithModifiedBoundLocation(
4151
tests.TestCaseWithTransport):
4152
"""Ensure correct handling of bound_location modifications.
4154
This is tested against a smart server as http://pad.lv/786980 was about a
4155
ReadOnlyError (write attempt during a read-only transaction) which can only
4156
happen in this context.
4160
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4161
self.transport_server = test_server.SmartTCPServer_for_testing
4163
def make_master_and_checkout(self, master_name, checkout_name):
4164
# Create the master branch and its associated checkout
4165
self.master = self.make_branch_and_tree(master_name)
4166
self.checkout = self.master.branch.create_checkout(checkout_name)
4167
# Modify the master branch so there is something to update
4168
self.master.commit('add stuff')
4169
self.last_revid = self.master.commit('even more stuff')
4170
self.bound_location = self.checkout.branch.get_bound_location()
4172
def assertUpdateSucceeds(self, new_location):
4173
self.checkout.branch.set_bound_location(new_location)
4174
self.checkout.update()
4175
self.assertEqual(self.last_revid, self.checkout.last_revision())
4177
def test_without_final_slash(self):
4178
self.make_master_and_checkout('master', 'checkout')
4179
# For unclear reasons some users have a bound_location without a final
4180
# '/', simulate that by forcing such a value
4181
self.assertEndsWith(self.bound_location, '/')
4182
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4184
def test_plus_sign(self):
4185
self.make_master_and_checkout('+master', 'checkout')
4186
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4188
def test_tilda(self):
4189
# Embed ~ in the middle of the path just to avoid any $HOME
4191
self.make_master_and_checkout('mas~ter', 'checkout')
4192
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4195
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4197
def test_no_context(self):
4198
class OutOfCoffee(errors.BzrError):
4199
"""A dummy exception for testing."""
4201
def __init__(self, urgency):
4202
self.urgency = urgency
4203
remote.no_context_error_translators.register(b"OutOfCoffee",
4204
lambda err: OutOfCoffee(err.error_args[0]))
4205
transport = MemoryTransport()
4206
client = FakeClient(transport.base)
4207
client.add_expected_call(
4208
b'Branch.get_stacked_on_url', (b'quack/',),
4209
b'error', (b'NotStacked',))
4210
client.add_expected_call(
4211
b'Branch.last_revision_info',
4213
b'error', (b'OutOfCoffee', b'low'))
4214
transport.mkdir('quack')
4215
transport = transport.clone('quack')
4216
branch = self.make_remote_branch(transport, client)
4217
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4218
self.assertFinished(client)
4220
def test_with_context(self):
4221
class OutOfTea(errors.BzrError):
4222
def __init__(self, branch, urgency):
4223
self.branch = branch
4224
self.urgency = urgency
4225
remote.error_translators.register(b"OutOfTea",
4226
lambda err, find, path: OutOfTea(
4227
err.error_args[0].decode('utf-8'),
4229
transport = MemoryTransport()
4230
client = FakeClient(transport.base)
4231
client.add_expected_call(
4232
b'Branch.get_stacked_on_url', (b'quack/',),
4233
b'error', (b'NotStacked',))
4234
client.add_expected_call(
4235
b'Branch.last_revision_info',
4237
b'error', (b'OutOfTea', b'low'))
4238
transport.mkdir('quack')
4239
transport = transport.clone('quack')
4240
branch = self.make_remote_branch(transport, client)
4241
self.assertRaises(OutOfTea, branch.last_revision_info)
4242
self.assertFinished(client)
4245
class TestRepositoryPack(TestRemoteRepository):
4247
def test_pack(self):
4248
transport_path = 'quack'
4249
repo, client = self.setup_fake_client_and_repository(transport_path)
4250
client.add_expected_call(
4251
b'Repository.lock_write', (b'quack/', b''),
4252
b'success', (b'ok', b'token'))
4253
client.add_expected_call(
4254
b'Repository.pack', (b'quack/', b'token', b'False'),
4255
b'success', (b'ok',), )
4256
client.add_expected_call(
4257
b'Repository.unlock', (b'quack/', b'token'),
4258
b'success', (b'ok', ))
4261
def test_pack_with_hint(self):
4262
transport_path = 'quack'
4263
repo, client = self.setup_fake_client_and_repository(transport_path)
4264
client.add_expected_call(
4265
b'Repository.lock_write', (b'quack/', b''),
4266
b'success', (b'ok', b'token'))
4267
client.add_expected_call(
4268
b'Repository.pack', (b'quack/', b'token', b'False'),
4269
b'success', (b'ok',), )
4270
client.add_expected_call(
4271
b'Repository.unlock', (b'quack/', b'token', b'False'),
4272
b'success', (b'ok', ))
4273
repo.pack(['hinta', 'hintb'])
4276
class TestRepositoryIterInventories(TestRemoteRepository):
4277
"""Test Repository.iter_inventories."""
4279
def _serialize_inv_delta(self, old_name, new_name, delta):
4280
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4281
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4283
def test_single_empty(self):
4284
transport_path = 'quack'
4285
repo, client = self.setup_fake_client_and_repository(transport_path)
4286
fmt = controldir.format_registry.get('2a')().repository_format
4288
stream = [('inventory-deltas', [
4289
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4290
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4291
client.add_expected_call(
4292
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4293
b'success', (b'ok', ),
4294
_stream_to_byte_stream(stream, fmt))
4295
ret = list(repo.iter_inventories([b"somerevid"]))
4296
self.assertLength(1, ret)
4298
self.assertEqual(b"somerevid", inv.revision_id)
4300
def test_empty(self):
4301
transport_path = 'quack'
4302
repo, client = self.setup_fake_client_and_repository(transport_path)
4303
ret = list(repo.iter_inventories([]))
4304
self.assertEqual(ret, [])
4306
def test_missing(self):
4307
transport_path = 'quack'
4308
repo, client = self.setup_fake_client_and_repository(transport_path)
4309
client.add_expected_call(
4310
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4311
b'success', (b'ok', ), iter([]))
4312
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4316
class TestRepositoryRevisionTreeArchive(TestRemoteRepository):
4317
"""Test Repository.iter_inventories."""
4319
def _serialize_inv_delta(self, old_name, new_name, delta):
4320
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4321
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4323
def test_simple(self):
4324
transport_path = 'quack'
4325
repo, client = self.setup_fake_client_and_repository(transport_path)
4326
fmt = controldir.format_registry.get('2a')().repository_format
4328
stream = [('inventory-deltas', [
4329
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4330
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4331
client.add_expected_call(
4332
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4333
b'success', (b'ok', ),
4334
_stream_to_byte_stream(stream, fmt))
4336
with tarfile.open(mode='w', fileobj=f) as tf:
4337
info = tarfile.TarInfo('somefile')
4339
contents = b'some data'
4340
info.type = tarfile.REGTYPE
4342
info.size = len(contents)
4343
tf.addfile(info, BytesIO(contents))
4344
client.add_expected_call(
4345
b'Repository.revision_archive', (b'quack/', b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4346
b'success', (b'ok', ),
4348
tree = repo.revision_tree(b'somerevid')
4349
self.assertEqual(f.getvalue(), b''.join(tree.archive('tar', 'foo.tar')))
4352
class TestRepositoryAnnotate(TestRemoteRepository):
4353
"""Test RemoteRevisionTree.annotate.."""
4355
def _serialize_inv_delta(self, old_name, new_name, delta):
4356
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4357
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4359
def test_simple(self):
4360
transport_path = 'quack'
4361
repo, client = self.setup_fake_client_and_repository(transport_path)
4362
fmt = controldir.format_registry.get('2a')().repository_format
4364
stream = [('inventory-deltas', [
4365
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4366
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4367
client.add_expected_call(
4368
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4369
b'success', (b'ok', ),
4370
_stream_to_byte_stream(stream, fmt))
4371
client.add_expected_call(
4372
b'Repository.annotate_file_revision',
4373
(b'quack/', b'somerevid', b'filename', b'', b'current:'),
4374
b'success', (b'ok', ),
4375
bencode.bencode([[b'baserevid', b'line 1\n'],
4376
[b'somerevid', b'line2\n']]))
4377
tree = repo.revision_tree(b'somerevid')
4379
(b'baserevid', b'line 1\n'),
4380
(b'somerevid', b'line2\n')],
4381
list(tree.annotate_iter('filename')))