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 (
76
from ..bzr.smart import medium, request
77
from ..bzr.smart.client import _SmartClient
78
from ..bzr.smart.repository import (
79
SmartServerRepositoryGetParentMap,
80
SmartServerRepositoryGetStream_1_19,
81
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
86
from .scenarios import load_tests_apply_scenarios
87
from ..transport.memory import MemoryTransport
88
from ..transport.remote import (
70
90
RemoteSSHTransport,
71
91
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 = [
95
load_tests = load_tests_apply_scenarios
98
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
102
{'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):
104
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
108
super(BasicRemoteObjectTests, self).setUp()
89
109
self.transport = self.get_transport()
90
110
# make a branch that can be opened over the smart transport
91
111
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
112
self.addCleanup(self.transport.disconnect)
97
114
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
115
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
116
self.assertIsInstance(b, BzrDir)
101
118
def test_open_remote_branch(self):
102
119
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
120
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
121
branch = b.open_branch()
105
122
self.assertIsInstance(branch, Branch)
480
490
self.assertEqual(None, result._branch_format)
481
491
self.assertFinished(client)
493
def test_unknown(self):
494
transport = self.get_transport('quack')
495
referenced = self.make_branch('referenced')
496
expected = referenced.controldir.cloning_metadir()
497
client = FakeClient(transport.base)
498
client.add_expected_call(
499
b'BzrDir.cloning_metadir', (b'quack/', b'False'),
500
b'success', (b'unknown', b'unknown', (b'branch', b''))),
501
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
503
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
506
class TestBzrDirCheckoutMetaDir(TestRemote):
508
def test__get_checkout_format(self):
509
transport = MemoryTransport()
510
client = FakeClient(transport.base)
511
reference_bzrdir_format = controldir.format_registry.get('default')()
512
control_name = reference_bzrdir_format.network_name()
513
client.add_expected_call(
514
b'BzrDir.checkout_metadir', (b'quack/', ),
515
b'success', (control_name, b'', b''))
516
transport.mkdir('quack')
517
transport = transport.clone('quack')
518
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
520
result = a_controldir.checkout_metadir()
521
# We should have got a reference control dir with default branch and
522
# repository formats.
523
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
524
self.assertEqual(None, result._repository_format)
525
self.assertEqual(None, result._branch_format)
526
self.assertFinished(client)
528
def test_unknown_format(self):
529
transport = MemoryTransport()
530
client = FakeClient(transport.base)
531
client.add_expected_call(
532
b'BzrDir.checkout_metadir', (b'quack/',),
533
b'success', (b'dontknow', b'', b''))
534
transport.mkdir('quack')
535
transport = transport.clone('quack')
536
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
538
self.assertRaises(errors.UnknownFormatError,
539
a_controldir.checkout_metadir)
540
self.assertFinished(client)
543
class TestBzrDirGetBranches(TestRemote):
545
def test_get_branches(self):
546
transport = MemoryTransport()
547
client = FakeClient(transport.base)
548
reference_bzrdir_format = controldir.format_registry.get('default')()
549
branch_name = reference_bzrdir_format.get_branch_format().network_name()
550
client.add_success_response_with_body(
552
b"foo": (b"branch", branch_name),
553
b"": (b"branch", branch_name)}), b"success")
554
client.add_success_response(
555
b'ok', b'', b'no', b'no', b'no',
556
reference_bzrdir_format.repository_format.network_name())
557
client.add_error_response(b'NotStacked')
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
transport.mkdir('quack')
563
transport = transport.clone('quack')
564
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
566
result = a_controldir.get_branches()
567
self.assertEqual({b"", b"foo"}, set(result.keys()))
569
[('call_expecting_body', b'BzrDir.get_branches', (b'quack/',)),
570
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
571
('call', b'Branch.get_stacked_on_url', (b'quack/', )),
572
('call', b'BzrDir.find_repositoryV3', (b'quack/', )),
573
('call', b'Branch.get_stacked_on_url', (b'quack/', ))],
577
class TestBzrDirDestroyBranch(TestRemote):
579
def test_destroy_default(self):
580
transport = self.get_transport('quack')
581
referenced = self.make_branch('referenced')
582
client = FakeClient(transport.base)
583
client.add_expected_call(
584
b'BzrDir.destroy_branch', (b'quack/', ),
585
b'success', (b'ok',)),
586
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
588
a_controldir.destroy_branch()
589
self.assertFinished(client)
592
class TestBzrDirHasWorkingTree(TestRemote):
594
def test_has_workingtree(self):
595
transport = self.get_transport('quack')
596
client = FakeClient(transport.base)
597
client.add_expected_call(
598
b'BzrDir.has_workingtree', (b'quack/',),
599
b'success', (b'yes',)),
600
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
602
self.assertTrue(a_controldir.has_workingtree())
603
self.assertFinished(client)
605
def test_no_workingtree(self):
606
transport = self.get_transport('quack')
607
client = FakeClient(transport.base)
608
client.add_expected_call(
609
b'BzrDir.has_workingtree', (b'quack/',),
610
b'success', (b'no',)),
611
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
613
self.assertFalse(a_controldir.has_workingtree())
614
self.assertFinished(client)
617
class TestBzrDirDestroyRepository(TestRemote):
619
def test_destroy_repository(self):
620
transport = self.get_transport('quack')
621
client = FakeClient(transport.base)
622
client.add_expected_call(
623
b'BzrDir.destroy_repository', (b'quack/',),
624
b'success', (b'ok',)),
625
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
627
a_controldir.destroy_repository()
628
self.assertFinished(client)
484
631
class TestBzrDirOpen(TestRemote):
632
779
network_name = reference_format.network_name()
633
780
branch_network_name = self.get_branch_format().network_name()
634
781
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(),
782
b'BzrDir.open_branchV3', (b'~hello/',),
783
b'success', (b'branch', branch_network_name))
784
client.add_expected_call(
785
b'BzrDir.find_repositoryV3', (b'~hello/',),
786
b'success', (b'ok', b'', b'no', b'no', b'no', network_name))
787
client.add_expected_call(
788
b'Branch.get_stacked_on_url', (b'~hello/',),
789
b'error', (b'NotStacked',))
790
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
645
792
result = bzrdir.open_branch()
646
793
self.assertFinished(client)
648
def check_open_repository(self, rich_root, subtrees, external_lookup='no'):
795
def check_open_repository(self, rich_root, subtrees, external_lookup=b'no'):
649
796
reference_format = self.get_repo_format()
650
797
network_name = reference_format.network_name()
651
798
transport = MemoryTransport()
652
799
transport.mkdir('quack')
653
800
transport = transport.clone('quack')
655
rich_response = 'yes'
802
rich_response = b'yes'
804
rich_response = b'no'
659
subtree_response = 'yes'
806
subtree_response = b'yes'
661
subtree_response = 'no'
808
subtree_response = b'no'
662
809
client = FakeClient(transport.base)
663
810
client.add_success_response(
664
'ok', '', rich_response, subtree_response, external_lookup,
811
b'ok', b'', rich_response, subtree_response, external_lookup,
666
bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
813
bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
668
815
result = bzrdir.open_repository()
669
816
self.assertEqual(
670
[('call', 'BzrDir.find_repositoryV3', ('quack/',))],
817
[('call', b'BzrDir.find_repositoryV3', (b'quack/',))],
672
819
self.assertIsInstance(result, RemoteRepository)
673
self.assertEqual(bzrdir, result.bzrdir)
820
self.assertEqual(bzrdir, result.controldir)
674
821
self.assertEqual(rich_root, result._format.rich_root_data)
675
822
self.assertEqual(subtrees, result._format.supports_tree_reference)
706
853
transport = transport.clone('quack')
707
854
self.make_repository('quack')
708
855
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()
856
reference_bzrdir_format = controldir.format_registry.get('default')()
857
reference_format = reference_bzrdir_format.get_branch_format()
858
network_name = reference_format.network_name()
859
reference_repo_fmt = reference_bzrdir_format.repository_format
860
reference_repo_name = reference_repo_fmt.network_name()
861
client.add_expected_call(
862
b'BzrDir.create_branch', (b'quack/', network_name),
863
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
864
reference_repo_name))
865
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
867
branch = a_controldir.create_branch()
868
# We should have got a remote branch
869
self.assertIsInstance(branch, remote.RemoteBranch)
870
# its format should have the settings from the response
871
format = branch._format
872
self.assertEqual(network_name, format.network_name())
874
def test_already_open_repo_and_reused_medium(self):
875
"""Bug 726584: create_branch(..., repository=repo) should work
876
regardless of what the smart medium's base URL is.
878
self.transport_server = test_server.SmartTCPServer_for_testing
879
transport = self.get_transport('.')
880
repo = self.make_repository('quack')
881
# Client's medium rooted a transport root (not at the bzrdir)
882
client = FakeClient(transport.base)
883
transport = transport.clone('quack')
884
reference_bzrdir_format = controldir.format_registry.get('default')()
885
reference_format = reference_bzrdir_format.get_branch_format()
886
network_name = reference_format.network_name()
887
reference_repo_fmt = reference_bzrdir_format.repository_format
888
reference_repo_name = reference_repo_fmt.network_name()
889
client.add_expected_call(
890
b'BzrDir.create_branch', (b'extra/quack/', network_name),
891
b'success', (b'ok', network_name, b'', b'no', b'no', b'yes',
892
reference_repo_name))
893
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
895
branch = a_controldir.create_branch(repository=repo)
721
896
# We should have got a remote branch
722
897
self.assertIsInstance(branch, remote.RemoteBranch)
723
898
# its format should have the settings from the response
772
947
server_url = 'bzr://example.com/'
773
948
self.permit_url(server_url)
774
949
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')
950
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
951
client.add_unknown_method_response(b'BzrDir.find_repositoryV2')
952
client.add_success_response(b'ok', b'', b'no', b'no')
778
953
# A real repository instance will be created to determine the network
780
955
client.add_success_response_with_body(
781
"Bazaar-NG meta directory, format 1\n", 'ok')
956
b"Bazaar-NG meta directory, format 1\n", b'ok')
957
client.add_success_response(b'stat', b'0', b'65535')
782
958
client.add_success_response_with_body(
783
reference_format.get_format_string(), 'ok')
959
reference_format.get_format_string(), b'ok')
784
960
# PackRepository wants to do a stat
785
client.add_success_response('stat', '0', '65535')
961
client.add_success_response(b'stat', b'0', b'65535')
786
962
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
788
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
964
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
790
966
repo = bzrdir.open_repository()
791
967
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',)),
968
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
969
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
970
('call', b'BzrDir.find_repository', (b'quack/',)),
971
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
972
('call', b'stat', (b'/quack/.bzr',)),
973
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
974
('call', b'stat', (b'/quack/.bzr/repository',)),
800
977
self.assertEqual(network_name, repo._format.network_name())
806
983
server_url = 'bzr://example.com/'
807
984
self.permit_url(server_url)
808
985
client = FakeClient(server_url)
809
client.add_unknown_method_response('BzrDir.find_repositoryV3')
810
client.add_success_response('ok', '', 'no', 'no', 'no')
986
client.add_unknown_method_response(b'BzrDir.find_repositoryV3')
987
client.add_success_response(b'ok', b'', b'no', b'no', b'no')
811
988
# A real repository instance will be created to determine the network
813
990
client.add_success_response_with_body(
814
"Bazaar-NG meta directory, format 1\n", 'ok')
991
b"Bazaar-NG meta directory, format 1\n", b'ok')
992
client.add_success_response(b'stat', b'0', b'65535')
815
993
client.add_success_response_with_body(
816
reference_format.get_format_string(), 'ok')
994
reference_format.get_format_string(), b'ok')
817
995
# PackRepository wants to do a stat
818
client.add_success_response('stat', '0', '65535')
996
client.add_success_response(b'stat', b'0', b'65535')
819
997
remote_transport = RemoteTransport(server_url + 'quack/', medium=False,
821
bzrdir = RemoteBzrDir(remote_transport, remote.RemoteBzrDirFormat(),
999
bzrdir = RemoteBzrDir(remote_transport, RemoteBzrDirFormat(),
823
1001
repo = bzrdir.open_repository()
824
1002
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',)),
1003
[('call', b'BzrDir.find_repositoryV3', (b'quack/',)),
1004
('call', b'BzrDir.find_repositoryV2', (b'quack/',)),
1005
('call_expecting_body', b'get', (b'/quack/.bzr/branch-format',)),
1006
('call', b'stat', (b'/quack/.bzr',)),
1007
('call_expecting_body', b'get', (b'/quack/.bzr/repository/format',)),
1008
('call', b'stat', (b'/quack/.bzr/repository',)),
832
1011
self.assertEqual(network_name, repo._format.network_name())
1134
1367
self.calls.append(('set_tags_bytes', bytes))
1135
1368
real_branch = StubRealBranch()
1136
1369
branch._real_branch = real_branch
1137
branch._set_tags_bytes('tags bytes')
1370
branch._set_tags_bytes(b'tags bytes')
1138
1371
# 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)
1373
branch._set_tags_bytes(b'tags bytes')
1374
self.assertFinished(client)
1376
[('set_tags_bytes', b'tags bytes')] * 2, real_branch.calls)
1379
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1381
def test_uses_last_revision_info_and_tags_by_default(self):
1382
transport = MemoryTransport()
1383
client = FakeClient(transport.base)
1384
client.add_expected_call(
1385
b'Branch.get_stacked_on_url', (b'quack/',),
1386
b'error', (b'NotStacked',))
1387
client.add_expected_call(
1388
b'Branch.last_revision_info', (b'quack/',),
1389
b'success', (b'ok', b'1', b'rev-tip'))
1390
client.add_expected_call(
1391
b'Branch.get_config_file', (b'quack/',),
1392
b'success', (b'ok',), b'')
1393
transport.mkdir('quack')
1394
transport = transport.clone('quack')
1395
branch = self.make_remote_branch(transport, client)
1396
result = branch.heads_to_fetch()
1397
self.assertFinished(client)
1398
self.assertEqual(({b'rev-tip'}, set()), result)
1400
def test_uses_last_revision_info_and_tags_when_set(self):
1401
transport = MemoryTransport()
1402
client = FakeClient(transport.base)
1403
client.add_expected_call(
1404
b'Branch.get_stacked_on_url', (b'quack/',),
1405
b'error', (b'NotStacked',))
1406
client.add_expected_call(
1407
b'Branch.last_revision_info', (b'quack/',),
1408
b'success', (b'ok', b'1', b'rev-tip'))
1409
client.add_expected_call(
1410
b'Branch.get_config_file', (b'quack/',),
1411
b'success', (b'ok',), b'branch.fetch_tags = True')
1412
# XXX: this will break if the default format's serialization of tags
1413
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1414
client.add_expected_call(
1415
b'Branch.get_tags_bytes', (b'quack/',),
1416
b'success', (b'd5:tag-17:rev-foo5:tag-27:rev-bare',))
1417
transport.mkdir('quack')
1418
transport = transport.clone('quack')
1419
branch = self.make_remote_branch(transport, client)
1420
result = branch.heads_to_fetch()
1421
self.assertFinished(client)
1423
({b'rev-tip'}, {b'rev-foo', b'rev-bar'}), result)
1425
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1426
transport = MemoryTransport()
1427
client = FakeClient(transport.base)
1428
client.add_expected_call(
1429
b'Branch.get_stacked_on_url', (b'quack/',),
1430
b'error', (b'NotStacked',))
1431
client.add_expected_call(
1432
b'Branch.heads_to_fetch', (b'quack/',),
1433
b'success', ([b'tip'], [b'tagged-1', b'tagged-2']))
1434
transport.mkdir('quack')
1435
transport = transport.clone('quack')
1436
branch = self.make_remote_branch(transport, client)
1437
branch._format._use_default_local_heads_to_fetch = lambda: False
1438
result = branch.heads_to_fetch()
1439
self.assertFinished(client)
1440
self.assertEqual(({b'tip'}, {b'tagged-1', b'tagged-2'}), result)
1442
def make_branch_with_tags(self):
1443
self.setup_smart_server_with_call_log()
1444
# Make a branch with a single revision.
1445
builder = self.make_branch_builder('foo')
1446
builder.start_series()
1447
builder.build_snapshot(None, [
1448
('add', ('', b'root-id', 'directory', ''))],
1450
builder.finish_series()
1451
branch = builder.get_branch()
1452
# Add two tags to that branch
1453
branch.tags.set_tag('tag-1', b'rev-1')
1454
branch.tags.set_tag('tag-2', b'rev-2')
1457
def test_backwards_compatible(self):
1458
br = self.make_branch_with_tags()
1459
br.get_config_stack().set('branch.fetch_tags', True)
1460
self.addCleanup(br.lock_read().unlock)
1461
# Disable the heads_to_fetch verb
1462
verb = b'Branch.heads_to_fetch'
1463
self.disable_verb(verb)
1464
self.reset_smart_call_log()
1465
result = br.heads_to_fetch()
1466
self.assertEqual(({b'tip'}, {b'rev-1', b'rev-2'}), result)
1468
[b'Branch.last_revision_info', b'Branch.get_tags_bytes'],
1469
[call.call.method for call in self.hpss_calls])
1471
def test_backwards_compatible_no_tags(self):
1472
br = self.make_branch_with_tags()
1473
br.get_config_stack().set('branch.fetch_tags', False)
1474
self.addCleanup(br.lock_read().unlock)
1475
# Disable the heads_to_fetch verb
1476
verb = b'Branch.heads_to_fetch'
1477
self.disable_verb(verb)
1478
self.reset_smart_call_log()
1479
result = br.heads_to_fetch()
1480
self.assertEqual(({b'tip'}, set()), result)
1482
[b'Branch.last_revision_info'],
1483
[call.call.method for call in self.hpss_calls])
1146
1486
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1292
1632
client = FakeClient(transport.base)
1293
1633
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'),
1634
b'Branch.get_stacked_on_url', (b'branch/',),
1635
b'error', (b'NotStacked',))
1636
client.add_expected_call(
1637
b'Branch.lock_write', (b'branch/', b'', b''),
1638
b'success', (b'ok', b'branch token', b'repo token'))
1639
client.add_expected_call(
1640
b'Branch.last_revision_info',
1642
b'success', (b'ok', b'0', b'null:'))
1643
client.add_expected_call(
1644
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'null:',),
1645
b'success', (b'ok',))
1646
client.add_expected_call(
1647
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1648
b'success', (b'ok',))
1309
1649
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
1650
branch.lock_write()
1314
result = branch.set_revision_history([])
1651
result = branch._set_last_revision(NULL_REVISION)
1315
1652
branch.unlock()
1316
1653
self.assertEqual(None, result)
1317
1654
self.assertFinished(client)
1319
1656
def test_set_nonempty(self):
1320
# set_revision_history([rev-id1, ..., rev-idN]) is translated to calling
1657
# set_last_revision_info(N, rev-idN) is translated to calling
1321
1658
# Branch.set_last_revision(path, rev-idN) on the wire.
1322
1659
transport = MemoryTransport()
1323
1660
transport.mkdir('branch')
1326
1663
client = FakeClient(transport.base)
1327
1664
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'),
1665
b'Branch.get_stacked_on_url', (b'branch/',),
1666
b'error', (b'NotStacked',))
1667
client.add_expected_call(
1668
b'Branch.lock_write', (b'branch/', b'', b''),
1669
b'success', (b'ok', b'branch token', b'repo token'))
1670
client.add_expected_call(
1671
b'Branch.last_revision_info',
1673
b'success', (b'ok', b'0', b'null:'))
1674
lines = [b'rev-id2']
1675
encoded_body = bz2.compress(b'\n'.join(lines))
1676
client.add_success_response_with_body(encoded_body, b'ok')
1677
client.add_expected_call(
1678
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id2',),
1679
b'success', (b'ok',))
1680
client.add_expected_call(
1681
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1682
b'success', (b'ok',))
1346
1683
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
1684
# Lock the branch, reset the record of remote calls.
1351
1685
branch.lock_write()
1352
result = branch.set_revision_history(['rev-id1', 'rev-id2'])
1686
result = branch._set_last_revision(b'rev-id2')
1353
1687
branch.unlock()
1354
1688
self.assertEqual(None, result)
1355
1689
self.assertFinished(client)
1361
1695
# A response of 'NoSuchRevision' is translated into an exception.
1362
1696
client = FakeClient(transport.base)
1363
1697
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:'))
1698
b'Branch.get_stacked_on_url', (b'branch/',),
1699
b'error', (b'NotStacked',))
1700
client.add_expected_call(
1701
b'Branch.lock_write', (b'branch/', b'', b''),
1702
b'success', (b'ok', b'branch token', b'repo token'))
1703
client.add_expected_call(
1704
b'Branch.last_revision_info',
1706
b'success', (b'ok', b'0', b'null:'))
1373
1707
# 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'),
1710
encoded_body = bz2.compress(b'\n'.join(lines))
1711
client.add_success_response_with_body(encoded_body, b'ok')
1712
client.add_expected_call(
1713
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1714
b'error', (b'NoSuchRevision', b'rev-id'))
1715
client.add_expected_call(
1716
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1717
b'success', (b'ok',))
1385
1719
branch = self.make_remote_branch(transport, client)
1386
1720
branch.lock_write()
1387
1721
self.assertRaises(
1388
errors.NoSuchRevision, branch.set_revision_history, ['rev-id'])
1722
errors.NoSuchRevision, branch._set_last_revision, b'rev-id')
1389
1723
branch.unlock()
1390
1724
self.assertFinished(client)
1400
1734
rejection_msg_unicode = u'rejection message\N{INTERROBANG}'
1401
1735
rejection_msg_utf8 = rejection_msg_unicode.encode('utf8')
1402
1736
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'),
1737
b'Branch.get_stacked_on_url', (b'branch/',),
1738
b'error', (b'NotStacked',))
1739
client.add_expected_call(
1740
b'Branch.lock_write', (b'branch/', b'', b''),
1741
b'success', (b'ok', b'branch token', b'repo token'))
1742
client.add_expected_call(
1743
b'Branch.last_revision_info',
1745
b'success', (b'ok', b'0', b'null:'))
1747
encoded_body = bz2.compress(b'\n'.join(lines))
1748
client.add_success_response_with_body(encoded_body, b'ok')
1749
client.add_expected_call(
1750
b'Branch.set_last_revision', (b'branch/', b'branch token', b'repo token', b'rev-id',),
1751
b'error', (b'TipChangeRejected', rejection_msg_utf8))
1752
client.add_expected_call(
1753
b'Branch.unlock', (b'branch/', b'branch token', b'repo token'),
1754
b'success', (b'ok',))
1421
1755
branch = self.make_remote_branch(transport, client)
1422
branch._ensure_real = lambda: None
1423
1756
branch.lock_write()
1424
1757
# The 'TipChangeRejected' error response triggered by calling
1425
# set_revision_history causes a TipChangeRejected exception.
1758
# set_last_revision_info causes a TipChangeRejected exception.
1426
1759
err = self.assertRaises(
1427
errors.TipChangeRejected, branch.set_revision_history, ['rev-id'])
1760
errors.TipChangeRejected,
1761
branch._set_last_revision, b'rev-id')
1428
1762
# The UTF-8 message from the response has been decoded into a unicode
1430
self.assertIsInstance(err.msg, unicode)
1764
self.assertIsInstance(err.msg, text_type)
1431
1765
self.assertEqual(rejection_msg_unicode, err.msg)
1432
1766
branch.unlock()
1433
1767
self.assertFinished(client)
1652
1986
branch.unlock()
1653
1987
self.assertFinished(client)
1989
def test_set_option_with_dict(self):
1990
client = FakeClient()
1991
client.add_expected_call(
1992
b'Branch.get_stacked_on_url', (b'memory:///',),
1993
b'error', (b'NotStacked',),)
1994
client.add_expected_call(
1995
b'Branch.lock_write', (b'memory:///', b'', b''),
1996
b'success', (b'ok', b'branch token', b'repo token'))
1997
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1998
client.add_expected_call(
1999
b'Branch.set_config_option_dict', (b'memory:///', b'branch token',
2000
b'repo token', encoded_dict_value, b'foo', b''),
2002
client.add_expected_call(
2003
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2004
b'success', (b'ok',))
2005
transport = MemoryTransport()
2006
branch = self.make_remote_branch(transport, client)
2008
config = branch._get_config()
2010
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
2013
self.assertFinished(client)
1655
2015
def test_backwards_compat_set_option(self):
1656
2016
self.setup_smart_server_with_call_log()
1657
2017
branch = self.make_branch('.')
1658
verb = 'Branch.set_config_option'
2018
verb = b'Branch.set_config_option'
1659
2019
self.disable_verb(verb)
1660
2020
branch.lock_write()
1661
2021
self.addCleanup(branch.unlock)
1662
2022
self.reset_smart_call_log()
1663
2023
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2024
self.assertLength(11, self.hpss_calls)
1665
2025
self.assertEqual('value', branch._get_config().get_option('name'))
2027
def test_backwards_compat_set_option_with_dict(self):
2028
self.setup_smart_server_with_call_log()
2029
branch = self.make_branch('.')
2030
verb = b'Branch.set_config_option_dict'
2031
self.disable_verb(verb)
2033
self.addCleanup(branch.unlock)
2034
self.reset_smart_call_log()
2035
config = branch._get_config()
2036
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2037
config.set_option(value_dict, 'name')
2038
self.assertLength(11, self.hpss_calls)
2039
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2042
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2044
def test_get_branch_conf(self):
2045
# in an empty branch we decode the response properly
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_success_response_with_body(b'# config file body', b'ok')
2051
transport = MemoryTransport()
2052
branch = self.make_remote_branch(transport, client)
2053
config = branch.get_config_stack()
2055
config.get("log_format")
2057
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2058
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',))],
2061
def test_set_branch_conf(self):
2062
client = FakeClient()
2063
client.add_expected_call(
2064
b'Branch.get_stacked_on_url', (b'memory:///',),
2065
b'error', (b'NotStacked',),)
2066
client.add_expected_call(
2067
b'Branch.lock_write', (b'memory:///', b'', b''),
2068
b'success', (b'ok', b'branch token', b'repo token'))
2069
client.add_expected_call(
2070
b'Branch.get_config_file', (b'memory:///', ),
2071
b'success', (b'ok', ), b"# line 1\n")
2072
client.add_expected_call(
2073
b'Branch.get_config_file', (b'memory:///', ),
2074
b'success', (b'ok', ), b"# line 1\n")
2075
client.add_expected_call(
2076
b'Branch.put_config_file', (b'memory:///', b'branch token',
2078
b'success', (b'ok',))
2079
client.add_expected_call(
2080
b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'),
2081
b'success', (b'ok',))
2082
transport = MemoryTransport()
2083
branch = self.make_remote_branch(transport, client)
2085
config = branch.get_config_stack()
2086
config.set('email', 'The Dude <lebowski@example.com>')
2088
self.assertFinished(client)
2090
[('call', b'Branch.get_stacked_on_url', (b'memory:///',)),
2091
('call', b'Branch.lock_write', (b'memory:///', b'', b'')),
2092
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2093
('call_expecting_body', b'Branch.get_config_file', (b'memory:///',)),
2094
('call_with_body_bytes_expecting_body', b'Branch.put_config_file',
2095
(b'memory:///', b'branch token', b'repo token'),
2096
b'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2097
('call', b'Branch.unlock', (b'memory:///', b'branch token', b'repo token'))],
1668
2101
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2116
self.assertFinished(client)
2119
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2121
def test_simple(self):
2122
transport = MemoryTransport()
2123
client = FakeClient(transport.base)
2124
client.add_expected_call(
2125
b'Branch.get_stacked_on_url', (b'quack/',),
2126
b'error', (b'NotStacked',),)
2127
client.add_expected_call(
2128
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2129
b'success', (b'ok', b'0',),)
2130
client.add_expected_call(
2131
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2132
b'error', (b'NoSuchRevision', b'unknown',),)
2133
transport.mkdir('quack')
2134
transport = transport.clone('quack')
2135
branch = self.make_remote_branch(transport, client)
2136
self.assertEqual(0, branch.revision_id_to_revno(b'null:'))
2137
self.assertRaises(errors.NoSuchRevision,
2138
branch.revision_id_to_revno, b'unknown')
2139
self.assertFinished(client)
2141
def test_dotted(self):
2142
transport = MemoryTransport()
2143
client = FakeClient(transport.base)
2144
client.add_expected_call(
2145
b'Branch.get_stacked_on_url', (b'quack/',),
2146
b'error', (b'NotStacked',),)
2147
client.add_expected_call(
2148
b'Branch.revision_id_to_revno', (b'quack/', b'null:'),
2149
b'success', (b'ok', b'0',),)
2150
client.add_expected_call(
2151
b'Branch.revision_id_to_revno', (b'quack/', b'unknown'),
2152
b'error', (b'NoSuchRevision', b'unknown',),)
2153
transport.mkdir('quack')
2154
transport = transport.clone('quack')
2155
branch = self.make_remote_branch(transport, client)
2156
self.assertEqual((0, ), branch.revision_id_to_dotted_revno(b'null:'))
2157
self.assertRaises(errors.NoSuchRevision,
2158
branch.revision_id_to_dotted_revno, b'unknown')
2159
self.assertFinished(client)
2161
def test_dotted_no_smart_verb(self):
2162
self.setup_smart_server_with_call_log()
2163
branch = self.make_branch('.')
2164
self.disable_verb(b'Branch.revision_id_to_revno')
2165
self.reset_smart_call_log()
2166
self.assertEqual((0, ),
2167
branch.revision_id_to_dotted_revno(b'null:'))
2168
self.assertLength(8, self.hpss_calls)
1686
2171
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2173
def test__get_config(self):
1689
2174
client = FakeClient()
1690
client.add_success_response_with_body('default_stack_on = /\n', 'ok')
2175
client.add_success_response_with_body(b'default_stack_on = /\n', b'ok')
1691
2176
transport = MemoryTransport()
1692
2177
bzrdir = self.make_remote_bzrdir(transport, client)
1693
2178
config = bzrdir.get_config()
1694
2179
self.assertEqual('/', config.get_default_stack_on())
1695
2180
self.assertEqual(
1696
[('call_expecting_body', 'BzrDir.get_config_file', ('memory:///',))],
2181
[('call_expecting_body', b'BzrDir.get_config_file', (b'memory:///',))],
1699
2184
def test_set_option_uses_vfs(self):
1700
2185
self.setup_smart_server_with_call_log()
1701
bzrdir = self.make_bzrdir('.')
2186
bzrdir = self.make_controldir('.')
1702
2187
self.reset_smart_call_log()
1703
2188
config = bzrdir.get_config()
1704
2189
config.set_default_stack_on('/')
1705
self.assertLength(3, self.hpss_calls)
2190
self.assertLength(4, self.hpss_calls)
1707
2192
def test_backwards_compat_get_option(self):
1708
2193
self.setup_smart_server_with_call_log()
1709
bzrdir = self.make_bzrdir('.')
1710
verb = 'BzrDir.get_config_file'
2194
bzrdir = self.make_controldir('.')
2195
verb = b'BzrDir.get_config_file'
1711
2196
self.disable_verb(verb)
1712
2197
self.reset_smart_call_log()
1713
2198
self.assertEqual(None,
1714
2199
bzrdir._get_config().get_option('default_stack_on'))
1715
self.assertLength(3, self.hpss_calls)
2200
self.assertLength(4, self.hpss_calls)
1718
2203
class TestTransportIsReadonly(tests.TestCase):
1720
2205
def test_true(self):
1721
2206
client = FakeClient()
1722
client.add_success_response('yes')
2207
client.add_success_response(b'yes')
1723
2208
transport = RemoteTransport('bzr://example.com/', medium=False,
1724
2209
_client=client)
1725
2210
self.assertEqual(True, transport.is_readonly())
1726
2211
self.assertEqual(
1727
[('call', 'Transport.is_readonly', ())],
2212
[('call', b'Transport.is_readonly', ())],
1730
2215
def test_false(self):
1731
2216
client = FakeClient()
1732
client.add_success_response('no')
2217
client.add_success_response(b'no')
1733
2218
transport = RemoteTransport('bzr://example.com/', medium=False,
1734
2219
_client=client)
1735
2220
self.assertEqual(False, transport.is_readonly())
1736
2221
self.assertEqual(
1737
[('call', 'Transport.is_readonly', ())],
2222
[('call', b'Transport.is_readonly', ())],
1740
2225
def test_error_from_old_server(self):
2417
class TestRepositoryBreakLock(TestRemoteRepository):
2419
def test_break_lock(self):
2420
transport_path = 'quack'
2421
repo, client = self.setup_fake_client_and_repository(transport_path)
2422
client.add_success_response(b'ok')
2425
[('call', b'Repository.break_lock', (b'quack/',))],
2429
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2431
def test_get_serializer_format(self):
2432
transport_path = 'hill'
2433
repo, client = self.setup_fake_client_and_repository(transport_path)
2434
client.add_success_response(b'ok', b'7')
2435
self.assertEqual(b'7', repo.get_serializer_format())
2437
[('call', b'VersionedFileRepository.get_serializer_format',
2442
class TestRepositoryReconcile(TestRemoteRepository):
2444
def test_reconcile(self):
2445
transport_path = 'hill'
2446
repo, client = self.setup_fake_client_and_repository(transport_path)
2447
body = (b"garbage_inventories: 2\n"
2448
b"inconsistent_parents: 3\n")
2449
client.add_expected_call(
2450
b'Repository.lock_write', (b'hill/', b''),
2451
b'success', (b'ok', b'a token'))
2452
client.add_success_response_with_body(body, b'ok')
2453
reconciler = repo.reconcile()
2455
[('call', b'Repository.lock_write', (b'hill/', b'')),
2456
('call_expecting_body', b'Repository.reconcile',
2457
(b'hill/', b'a token'))],
2459
self.assertEqual(2, reconciler.garbage_inventories)
2460
self.assertEqual(3, reconciler.inconsistent_parents)
2463
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2465
def test_text(self):
2466
# ('ok',), body with signature text
2467
transport_path = 'quack'
2468
repo, client = self.setup_fake_client_and_repository(transport_path)
2469
client.add_success_response_with_body(
2471
self.assertEqual(b"THETEXT", repo.get_signature_text(b"revid"))
2473
[('call_expecting_body', b'Repository.get_revision_signature_text',
2474
(b'quack/', b'revid'))],
2477
def test_no_signature(self):
2478
transport_path = 'quick'
2479
repo, client = self.setup_fake_client_and_repository(transport_path)
2480
client.add_error_response(b'nosuchrevision', b'unknown')
2481
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2484
[('call_expecting_body', b'Repository.get_revision_signature_text',
2485
(b'quick/', b'unknown'))],
1906
2489
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2491
def test_get_graph(self):
2257
2928
self.setup_smart_server_with_call_log()
2258
2929
tree = self.make_branch_and_memory_tree('.')
2259
2930
tree.lock_write()
2260
2932
rev1 = tree.commit('First')
2261
2933
rev2 = tree.commit('Second')
2263
2935
branch = tree.branch
2264
2936
self.assertFalse(branch.is_locked())
2265
2937
self.reset_smart_call_log()
2266
verb = 'Repository.get_rev_id_for_revno'
2938
verb = b'Repository.get_rev_id_for_revno'
2267
2939
self.disable_verb(verb)
2268
2940
self.assertEqual(rev1, branch.get_rev_id(1))
2269
2941
self.assertLength(1, [call for call in self.hpss_calls if
2270
2942
call.call.method == verb])
2945
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2947
def test_has_signature_for_revision_id(self):
2948
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2949
transport_path = 'quack'
2950
repo, client = self.setup_fake_client_and_repository(transport_path)
2951
client.add_success_response(b'yes')
2952
result = repo.has_signature_for_revision_id(b'A')
2954
[('call', b'Repository.has_signature_for_revision_id',
2955
(b'quack/', b'A'))],
2957
self.assertEqual(True, result)
2959
def test_is_not_shared(self):
2960
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2961
transport_path = 'qwack'
2962
repo, client = self.setup_fake_client_and_repository(transport_path)
2963
client.add_success_response(b'no')
2964
result = repo.has_signature_for_revision_id(b'A')
2966
[('call', b'Repository.has_signature_for_revision_id',
2967
(b'qwack/', b'A'))],
2969
self.assertEqual(False, result)
2972
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2974
def test_get_physical_lock_status_yes(self):
2975
transport_path = 'qwack'
2976
repo, client = self.setup_fake_client_and_repository(transport_path)
2977
client.add_success_response(b'yes')
2978
result = repo.get_physical_lock_status()
2980
[('call', b'Repository.get_physical_lock_status',
2983
self.assertEqual(True, result)
2985
def test_get_physical_lock_status_no(self):
2986
transport_path = 'qwack'
2987
repo, client = self.setup_fake_client_and_repository(transport_path)
2988
client.add_success_response(b'no')
2989
result = repo.get_physical_lock_status()
2991
[('call', b'Repository.get_physical_lock_status',
2994
self.assertEqual(False, result)
2273
2997
class TestRepositoryIsShared(TestRemoteRepository):
2275
2999
def test_is_shared(self):
2276
3000
# ('yes', ) for Repository.is_shared -> 'True'.
2277
3001
transport_path = 'quack'
2278
3002
repo, client = self.setup_fake_client_and_repository(transport_path)
2279
client.add_success_response('yes')
3003
client.add_success_response(b'yes')
2280
3004
result = repo.is_shared()
2281
3005
self.assertEqual(
2282
[('call', 'Repository.is_shared', ('quack/',))],
3006
[('call', b'Repository.is_shared', (b'quack/',))],
2284
3008
self.assertEqual(True, result)
2300
3049
def test_lock_write(self):
2301
3050
transport_path = 'quack'
2302
3051
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
3052
client.add_success_response(b'ok', b'a token')
3053
token = repo.lock_write().repository_token
2305
3054
self.assertEqual(
2306
[('call', 'Repository.lock_write', ('quack/', ''))],
3055
[('call', b'Repository.lock_write', (b'quack/', b''))],
2308
self.assertEqual('a token', result)
3057
self.assertEqual(b'a token', token)
2310
3059
def test_lock_write_already_locked(self):
2311
3060
transport_path = 'quack'
2312
3061
repo, client = self.setup_fake_client_and_repository(transport_path)
2313
client.add_error_response('LockContention')
3062
client.add_error_response(b'LockContention')
2314
3063
self.assertRaises(errors.LockContention, repo.lock_write)
2315
3064
self.assertEqual(
2316
[('call', 'Repository.lock_write', ('quack/', ''))],
3065
[('call', b'Repository.lock_write', (b'quack/', b''))],
2319
3068
def test_lock_write_unlockable(self):
2320
3069
transport_path = 'quack'
2321
3070
repo, client = self.setup_fake_client_and_repository(transport_path)
2322
client.add_error_response('UnlockableTransport')
3071
client.add_error_response(b'UnlockableTransport')
2323
3072
self.assertRaises(errors.UnlockableTransport, repo.lock_write)
2324
3073
self.assertEqual(
2325
[('call', 'Repository.lock_write', ('quack/', ''))],
3074
[('call', b'Repository.lock_write', (b'quack/', b''))],
3078
class TestRepositoryWriteGroups(TestRemoteRepository):
3080
def test_start_write_group(self):
3081
transport_path = 'quack'
3082
repo, client = self.setup_fake_client_and_repository(transport_path)
3083
client.add_expected_call(
3084
b'Repository.lock_write', (b'quack/', b''),
3085
b'success', (b'ok', b'a token'))
3086
client.add_expected_call(
3087
b'Repository.start_write_group', (b'quack/', b'a token'),
3088
b'success', (b'ok', (b'token1', )))
3090
repo.start_write_group()
3092
def test_start_write_group_unsuspendable(self):
3093
# Some repositories do not support suspending write
3094
# groups. For those, fall back to the "real" repository.
3095
transport_path = 'quack'
3096
repo, client = self.setup_fake_client_and_repository(transport_path)
3097
def stub_ensure_real():
3098
client._calls.append(('_ensure_real',))
3099
repo._real_repository = _StubRealPackRepository(client._calls)
3100
repo._ensure_real = stub_ensure_real
3101
client.add_expected_call(
3102
b'Repository.lock_write', (b'quack/', b''),
3103
b'success', (b'ok', b'a token'))
3104
client.add_expected_call(
3105
b'Repository.start_write_group', (b'quack/', b'a token'),
3106
b'error', (b'UnsuspendableWriteGroup',))
3108
repo.start_write_group()
3109
self.assertEqual(client._calls[-2:], [
3111
('start_write_group',)])
3113
def test_commit_write_group(self):
3114
transport_path = 'quack'
3115
repo, client = self.setup_fake_client_and_repository(transport_path)
3116
client.add_expected_call(
3117
b'Repository.lock_write', (b'quack/', b''),
3118
b'success', (b'ok', b'a token'))
3119
client.add_expected_call(
3120
b'Repository.start_write_group', (b'quack/', b'a token'),
3121
b'success', (b'ok', [b'token1']))
3122
client.add_expected_call(
3123
b'Repository.commit_write_group', (b'quack/', b'a token', [b'token1']),
3124
b'success', (b'ok',))
3126
repo.start_write_group()
3127
repo.commit_write_group()
3129
def test_abort_write_group(self):
3130
transport_path = 'quack'
3131
repo, client = self.setup_fake_client_and_repository(transport_path)
3132
client.add_expected_call(
3133
b'Repository.lock_write', (b'quack/', b''),
3134
b'success', (b'ok', b'a token'))
3135
client.add_expected_call(
3136
b'Repository.start_write_group', (b'quack/', b'a token'),
3137
b'success', (b'ok', [b'token1']))
3138
client.add_expected_call(
3139
b'Repository.abort_write_group', (b'quack/', b'a token', [b'token1']),
3140
b'success', (b'ok',))
3142
repo.start_write_group()
3143
repo.abort_write_group(False)
3145
def test_suspend_write_group(self):
3146
transport_path = 'quack'
3147
repo, client = self.setup_fake_client_and_repository(transport_path)
3148
self.assertEqual([], repo.suspend_write_group())
3150
def test_resume_write_group(self):
3151
transport_path = 'quack'
3152
repo, client = self.setup_fake_client_and_repository(transport_path)
3153
client.add_expected_call(
3154
b'Repository.lock_write', (b'quack/', b''),
3155
b'success', (b'ok', b'a token'))
3156
client.add_expected_call(
3157
b'Repository.check_write_group', (b'quack/', b'a token', [b'token1']),
3158
b'success', (b'ok',))
3160
repo.resume_write_group([b'token1'])
2329
3163
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3165
def test_backwards_compat(self):
2332
3166
self.setup_smart_server_with_call_log()
2333
3167
repo = self.make_repository('.')
2334
3168
self.reset_smart_call_log()
2335
verb = 'Repository.set_make_working_trees'
3169
verb = b'Repository.set_make_working_trees'
2336
3170
self.disable_verb(verb)
2337
3171
repo.set_make_working_trees(True)
2338
3172
call_count = len([call for call in self.hpss_calls if
2419
3280
def setUp(self):
2420
TestRemoteRepository.setUp(self)
2421
self.disable_verb('Repository.insert_stream_1.19')
3281
super(TestRepositoryInsertStream, self).setUp()
3282
self.disable_verb(b'Repository.insert_stream_1.19')
2423
3284
def test_unlocked_repo(self):
2424
3285
transport_path = 'quack'
2425
3286
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
3287
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/', ''),
3288
b'Repository.insert_stream_1.19', (b'quack/', b''),
3289
b'unknown', (b'Repository.insert_stream_1.19',))
3290
client.add_expected_call(
3291
b'Repository.insert_stream', (b'quack/', b''),
3292
b'success', (b'ok',))
3293
client.add_expected_call(
3294
b'Repository.insert_stream', (b'quack/', b''),
3295
b'success', (b'ok',))
2435
3296
self.checkInsertEmptyStream(repo, client)
2437
3298
def test_locked_repo_with_no_lock_token(self):
2438
3299
transport_path = 'quack'
2439
3300
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
3301
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/', ''),
3302
b'Repository.lock_write', (b'quack/', b''),
3303
b'success', (b'ok', b''))
3304
client.add_expected_call(
3305
b'Repository.insert_stream_1.19', (b'quack/', b''),
3306
b'unknown', (b'Repository.insert_stream_1.19',))
3307
client.add_expected_call(
3308
b'Repository.insert_stream', (b'quack/', b''),
3309
b'success', (b'ok',))
3310
client.add_expected_call(
3311
b'Repository.insert_stream', (b'quack/', b''),
3312
b'success', (b'ok',))
2452
3313
repo.lock_write()
2453
3314
self.checkInsertEmptyStream(repo, client)
2534
3395
* texts substream: (some-rev, some-file)
2536
3397
# Define a stream using generators so that it isn't rewindable.
2537
inv = inventory.Inventory(revision_id='rev1')
2538
inv.root.revision = 'rev1'
3398
inv = inventory.Inventory(revision_id=b'rev1')
3399
inv.root.revision = b'rev1'
2539
3400
def stream_with_inv_delta():
2540
3401
yield ('inventories', inventories_substream())
2541
3402
yield ('inventory-deltas', inventory_delta_substream())
2542
3403
yield ('texts', [
2543
3404
versionedfile.FulltextContentFactory(
2544
('some-rev', 'some-file'), (), None, 'content')])
3405
(b'some-rev', b'some-file'), (), None, b'content')])
2545
3406
def inventories_substream():
2546
3407
# An empty inventory fulltext. This will be streamed normally.
2547
3408
text = fmt._serializer.write_inventory_to_string(inv)
2548
3409
yield versionedfile.FulltextContentFactory(
2549
('rev1',), (), None, text)
3410
(b'rev1',), (), None, text)
2550
3411
def inventory_delta_substream():
2551
3412
# An inventory delta. This can't be streamed via this verb, so it
2552
3413
# will trigger a fallback to VFS insert_stream.
2553
3414
entry = inv.make_entry(
2554
'directory', 'newdir', inv.root.file_id, 'newdir-id')
2555
entry.revision = 'ghost'
2556
delta = [(None, 'newdir', 'newdir-id', entry)]
3415
'directory', 'newdir', inv.root.file_id, b'newdir-id')
3416
entry.revision = b'ghost'
3417
delta = [(None, 'newdir', b'newdir-id', entry)]
2557
3418
serializer = inventory_delta.InventoryDeltaSerializer(
2558
3419
versioned_root=True, tree_references=False)
2559
lines = serializer.delta_to_lines('rev1', 'rev2', delta)
3420
lines = serializer.delta_to_lines(b'rev1', b'rev2', delta)
2560
3421
yield versionedfile.ChunkedContentFactory(
2561
('rev2',), (('rev1',)), None, lines)
3422
(b'rev2',), ((b'rev1',)), None, lines)
2562
3423
# Another delta.
2563
lines = serializer.delta_to_lines('rev1', 'rev3', delta)
3424
lines = serializer.delta_to_lines(b'rev1', b'rev3', delta)
2564
3425
yield versionedfile.ChunkedContentFactory(
2565
('rev3',), (('rev1',)), None, lines)
3426
(b'rev3',), ((b'rev1',)), None, lines)
2566
3427
return stream_with_inv_delta()
2784
3658
def test_NoSuchRevision(self):
2785
3659
branch = self.make_branch('')
2787
3661
translated_error = self.translateTuple(
2788
('NoSuchRevision', revid), branch=branch)
3662
(b'NoSuchRevision', revid), branch=branch)
2789
3663
expected_error = errors.NoSuchRevision(branch, revid)
2790
3664
self.assertEqual(expected_error, translated_error)
2792
3666
def test_nosuchrevision(self):
2793
3667
repository = self.make_repository('')
2795
3669
translated_error = self.translateTuple(
2796
('nosuchrevision', revid), repository=repository)
3670
(b'nosuchrevision', revid), repository=repository)
2797
3671
expected_error = errors.NoSuchRevision(repository, revid)
2798
3672
self.assertEqual(expected_error, translated_error)
2800
3674
def test_nobranch(self):
2801
bzrdir = self.make_bzrdir('')
2802
translated_error = self.translateTuple(('nobranch',), bzrdir=bzrdir)
3675
bzrdir = self.make_controldir('')
3676
translated_error = self.translateTuple((b'nobranch',), bzrdir=bzrdir)
2803
3677
expected_error = errors.NotBranchError(path=bzrdir.root_transport.base)
2804
3678
self.assertEqual(expected_error, translated_error)
2806
3680
def test_nobranch_one_arg(self):
2807
bzrdir = self.make_bzrdir('')
3681
bzrdir = self.make_controldir('')
2808
3682
translated_error = self.translateTuple(
2809
('nobranch', 'extra detail'), bzrdir=bzrdir)
3683
(b'nobranch', b'extra detail'), bzrdir=bzrdir)
2810
3684
expected_error = errors.NotBranchError(
2811
3685
path=bzrdir.root_transport.base,
2812
3686
detail='extra detail')
2813
3687
self.assertEqual(expected_error, translated_error)
3689
def test_norepository(self):
3690
bzrdir = self.make_controldir('')
3691
translated_error = self.translateTuple((b'norepository',),
3693
expected_error = errors.NoRepositoryPresent(bzrdir)
3694
self.assertEqual(expected_error, translated_error)
2815
3696
def test_LockContention(self):
2816
translated_error = self.translateTuple(('LockContention',))
3697
translated_error = self.translateTuple((b'LockContention',))
2817
3698
expected_error = errors.LockContention('(remote lock)')
2818
3699
self.assertEqual(expected_error, translated_error)
2820
3701
def test_UnlockableTransport(self):
2821
bzrdir = self.make_bzrdir('')
3702
bzrdir = self.make_controldir('')
2822
3703
translated_error = self.translateTuple(
2823
('UnlockableTransport',), bzrdir=bzrdir)
3704
(b'UnlockableTransport',), bzrdir=bzrdir)
2824
3705
expected_error = errors.UnlockableTransport(bzrdir.root_transport)
2825
3706
self.assertEqual(expected_error, translated_error)
2827
3708
def test_LockFailed(self):
2828
3709
lock = 'str() of a server lock'
2829
3710
why = 'str() of why'
2830
translated_error = self.translateTuple(('LockFailed', lock, why))
3711
translated_error = self.translateTuple((b'LockFailed', lock.encode('ascii'), why.encode('ascii')))
2831
3712
expected_error = errors.LockFailed(lock, why)
2832
3713
self.assertEqual(expected_error, translated_error)
2834
3715
def test_TokenMismatch(self):
2835
3716
token = 'a lock token'
2836
translated_error = self.translateTuple(('TokenMismatch',), token=token)
3717
translated_error = self.translateTuple((b'TokenMismatch',), token=token)
2837
3718
expected_error = errors.TokenMismatch(token, '(remote token)')
2838
3719
self.assertEqual(expected_error, translated_error)
2841
3722
branch = self.make_branch('a')
2842
3723
other_branch = self.make_branch('b')
2843
3724
translated_error = self.translateTuple(
2844
('Diverged',), branch=branch, other_branch=other_branch)
3725
(b'Diverged',), branch=branch, other_branch=other_branch)
2845
3726
expected_error = errors.DivergedBranches(branch, other_branch)
2846
3727
self.assertEqual(expected_error, translated_error)
3729
def test_NotStacked(self):
3730
branch = self.make_branch('')
3731
translated_error = self.translateTuple((b'NotStacked',), branch=branch)
3732
expected_error = errors.NotStacked(branch)
3733
self.assertEqual(expected_error, translated_error)
2848
3735
def test_ReadError_no_args(self):
2849
3736
path = 'a path'
2850
translated_error = self.translateTuple(('ReadError',), path=path)
3737
translated_error = self.translateTuple((b'ReadError',), path=path)
2851
3738
expected_error = errors.ReadError(path)
2852
3739
self.assertEqual(expected_error, translated_error)
2854
3741
def test_ReadError(self):
2855
3742
path = 'a path'
2856
translated_error = self.translateTuple(('ReadError', path))
3743
translated_error = self.translateTuple((b'ReadError', path.encode('utf-8')))
2857
3744
expected_error = errors.ReadError(path)
2858
3745
self.assertEqual(expected_error, translated_error)
2860
3747
def test_IncompatibleRepositories(self):
2861
translated_error = self.translateTuple(('IncompatibleRepositories',
2862
"repo1", "repo2", "details here"))
3748
translated_error = self.translateTuple((b'IncompatibleRepositories',
3749
b"repo1", b"repo2", b"details here"))
2863
3750
expected_error = errors.IncompatibleRepositories("repo1", "repo2",
2864
3751
"details here")
2865
3752
self.assertEqual(expected_error, translated_error)
3754
def test_GhostRevisionsHaveNoRevno(self):
3755
translated_error = self.translateTuple((b'GhostRevisionsHaveNoRevno',
3756
b"revid1", b"revid2"))
3757
expected_error = errors.GhostRevisionsHaveNoRevno(b"revid1", b"revid2")
3758
self.assertEqual(expected_error, translated_error)
2867
3760
def test_PermissionDenied_no_args(self):
2868
3761
path = 'a path'
2869
translated_error = self.translateTuple(('PermissionDenied',), path=path)
3762
translated_error = self.translateTuple((b'PermissionDenied',),
2870
3764
expected_error = errors.PermissionDenied(path)
2871
3765
self.assertEqual(expected_error, translated_error)
2873
3767
def test_PermissionDenied_one_arg(self):
2874
3768
path = 'a path'
2875
translated_error = self.translateTuple(('PermissionDenied', path))
3769
translated_error = self.translateTuple((b'PermissionDenied', path.encode('utf-8')))
2876
3770
expected_error = errors.PermissionDenied(path)
2877
3771
self.assertEqual(expected_error, translated_error)
3143
4078
def test_copy_content_into_avoids_revision_history(self):
3144
4079
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4080
builder = self.make_branch_builder('remote')
4081
builder.build_commit(message="Commit.")
3147
4082
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4083
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4084
local.repository.fetch(remote_branch.repository)
3150
4085
self.hpss_calls = []
3151
4086
remote_branch.copy_content_into(local)
3152
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4087
self.assertFalse(b'Branch.revision_history' in self.hpss_calls)
4089
def test_fetch_everything_needs_just_one_call(self):
4090
local = self.make_branch('local')
4091
builder = self.make_branch_builder('remote')
4092
builder.build_commit(message="Commit.")
4093
remote_branch_url = self.smart_server.get_url() + 'remote'
4094
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4095
self.hpss_calls = []
4096
local.repository.fetch(
4097
remote_branch.repository,
4098
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4099
self.assertEqual([b'Repository.get_stream_1.19'], self.hpss_calls)
4101
def override_verb(self, verb_name, verb):
4102
request_handlers = request.request_handlers
4103
orig_verb = request_handlers.get(verb_name)
4104
orig_info = request_handlers.get_info(verb_name)
4105
request_handlers.register(verb_name, verb, override_existing=True)
4106
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4107
override_existing=True, info=orig_info)
4109
def test_fetch_everything_backwards_compat(self):
4110
"""Can fetch with EverythingResult even with pre 2.4 servers.
4112
Pre-2.4 do not support 'everything' searches with the
4113
Repository.get_stream_1.19 verb.
4116
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4117
"""A version of the Repository.get_stream_1.19 verb patched to
4118
reject 'everything' searches the way 2.3 and earlier do.
4120
def recreate_search(self, repository, search_bytes,
4121
discard_excess=False):
4122
verb_log.append(search_bytes.split(b'\n', 1)[0])
4123
if search_bytes == b'everything':
4125
request.FailedSmartServerResponse((b'BadSearch',)))
4126
return super(OldGetStreamVerb,
4127
self).recreate_search(repository, search_bytes,
4128
discard_excess=discard_excess)
4129
self.override_verb(b'Repository.get_stream_1.19', OldGetStreamVerb)
4130
local = self.make_branch('local')
4131
builder = self.make_branch_builder('remote')
4132
builder.build_commit(message="Commit.")
4133
remote_branch_url = self.smart_server.get_url() + 'remote'
4134
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4135
self.hpss_calls = []
4136
local.repository.fetch(
4137
remote_branch.repository,
4138
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4139
# make sure the overridden verb was used
4140
self.assertLength(1, verb_log)
4141
# more than one HPSS call is needed, but because it's a VFS callback
4142
# its hard to predict exactly how many.
4143
self.assertTrue(len(self.hpss_calls) > 1)
4146
class TestUpdateBoundBranchWithModifiedBoundLocation(
4147
tests.TestCaseWithTransport):
4148
"""Ensure correct handling of bound_location modifications.
4150
This is tested against a smart server as http://pad.lv/786980 was about a
4151
ReadOnlyError (write attempt during a read-only transaction) which can only
4152
happen in this context.
4156
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4157
self.transport_server = test_server.SmartTCPServer_for_testing
4159
def make_master_and_checkout(self, master_name, checkout_name):
4160
# Create the master branch and its associated checkout
4161
self.master = self.make_branch_and_tree(master_name)
4162
self.checkout = self.master.branch.create_checkout(checkout_name)
4163
# Modify the master branch so there is something to update
4164
self.master.commit('add stuff')
4165
self.last_revid = self.master.commit('even more stuff')
4166
self.bound_location = self.checkout.branch.get_bound_location()
4168
def assertUpdateSucceeds(self, new_location):
4169
self.checkout.branch.set_bound_location(new_location)
4170
self.checkout.update()
4171
self.assertEqual(self.last_revid, self.checkout.last_revision())
4173
def test_without_final_slash(self):
4174
self.make_master_and_checkout('master', 'checkout')
4175
# For unclear reasons some users have a bound_location without a final
4176
# '/', simulate that by forcing such a value
4177
self.assertEndsWith(self.bound_location, '/')
4178
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4180
def test_plus_sign(self):
4181
self.make_master_and_checkout('+master', 'checkout')
4182
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4184
def test_tilda(self):
4185
# Embed ~ in the middle of the path just to avoid any $HOME
4187
self.make_master_and_checkout('mas~ter', 'checkout')
4188
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4191
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4193
def test_no_context(self):
4194
class OutOfCoffee(errors.BzrError):
4195
"""A dummy exception for testing."""
4197
def __init__(self, urgency):
4198
self.urgency = urgency
4199
remote.no_context_error_translators.register(b"OutOfCoffee",
4200
lambda err: OutOfCoffee(err.error_args[0]))
4201
transport = MemoryTransport()
4202
client = FakeClient(transport.base)
4203
client.add_expected_call(
4204
b'Branch.get_stacked_on_url', (b'quack/',),
4205
b'error', (b'NotStacked',))
4206
client.add_expected_call(
4207
b'Branch.last_revision_info',
4209
b'error', (b'OutOfCoffee', b'low'))
4210
transport.mkdir('quack')
4211
transport = transport.clone('quack')
4212
branch = self.make_remote_branch(transport, client)
4213
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4214
self.assertFinished(client)
4216
def test_with_context(self):
4217
class OutOfTea(errors.BzrError):
4218
def __init__(self, branch, urgency):
4219
self.branch = branch
4220
self.urgency = urgency
4221
remote.error_translators.register(b"OutOfTea",
4222
lambda err, find, path: OutOfTea(
4223
err.error_args[0].decode('utf-8'),
4225
transport = MemoryTransport()
4226
client = FakeClient(transport.base)
4227
client.add_expected_call(
4228
b'Branch.get_stacked_on_url', (b'quack/',),
4229
b'error', (b'NotStacked',))
4230
client.add_expected_call(
4231
b'Branch.last_revision_info',
4233
b'error', (b'OutOfTea', b'low'))
4234
transport.mkdir('quack')
4235
transport = transport.clone('quack')
4236
branch = self.make_remote_branch(transport, client)
4237
self.assertRaises(OutOfTea, branch.last_revision_info)
4238
self.assertFinished(client)
4241
class TestRepositoryPack(TestRemoteRepository):
4243
def test_pack(self):
4244
transport_path = 'quack'
4245
repo, client = self.setup_fake_client_and_repository(transport_path)
4246
client.add_expected_call(
4247
b'Repository.lock_write', (b'quack/', b''),
4248
b'success', (b'ok', b'token'))
4249
client.add_expected_call(
4250
b'Repository.pack', (b'quack/', b'token', b'False'),
4251
b'success', (b'ok',), )
4252
client.add_expected_call(
4253
b'Repository.unlock', (b'quack/', b'token'),
4254
b'success', (b'ok', ))
4257
def test_pack_with_hint(self):
4258
transport_path = 'quack'
4259
repo, client = self.setup_fake_client_and_repository(transport_path)
4260
client.add_expected_call(
4261
b'Repository.lock_write', (b'quack/', b''),
4262
b'success', (b'ok', b'token'))
4263
client.add_expected_call(
4264
b'Repository.pack', (b'quack/', b'token', b'False'),
4265
b'success', (b'ok',), )
4266
client.add_expected_call(
4267
b'Repository.unlock', (b'quack/', b'token', b'False'),
4268
b'success', (b'ok', ))
4269
repo.pack([b'hinta', b'hintb'])
4272
class TestRepositoryIterInventories(TestRemoteRepository):
4273
"""Test Repository.iter_inventories."""
4275
def _serialize_inv_delta(self, old_name, new_name, delta):
4276
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4277
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4279
def test_single_empty(self):
4280
transport_path = 'quack'
4281
repo, client = self.setup_fake_client_and_repository(transport_path)
4282
fmt = controldir.format_registry.get('2a')().repository_format
4284
stream = [('inventory-deltas', [
4285
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4286
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4287
client.add_expected_call(
4288
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4289
b'success', (b'ok', ),
4290
_stream_to_byte_stream(stream, fmt))
4291
ret = list(repo.iter_inventories([b"somerevid"]))
4292
self.assertLength(1, ret)
4294
self.assertEqual(b"somerevid", inv.revision_id)
4296
def test_empty(self):
4297
transport_path = 'quack'
4298
repo, client = self.setup_fake_client_and_repository(transport_path)
4299
ret = list(repo.iter_inventories([]))
4300
self.assertEqual(ret, [])
4302
def test_missing(self):
4303
transport_path = 'quack'
4304
repo, client = self.setup_fake_client_and_repository(transport_path)
4305
client.add_expected_call(
4306
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4307
b'success', (b'ok', ), iter([]))
4308
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(
4312
class TestRepositoryRevisionTreeArchive(TestRemoteRepository):
4313
"""Test Repository.iter_inventories."""
4315
def _serialize_inv_delta(self, old_name, new_name, delta):
4316
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4317
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4319
def test_simple(self):
4320
transport_path = 'quack'
4321
repo, client = self.setup_fake_client_and_repository(transport_path)
4322
fmt = controldir.format_registry.get('2a')().repository_format
4324
stream = [('inventory-deltas', [
4325
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4326
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4327
client.add_expected_call(
4328
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4329
b'success', (b'ok', ),
4330
_stream_to_byte_stream(stream, fmt))
4332
with tarfile.open(mode='w', fileobj=f) as tf:
4333
info = tarfile.TarInfo('somefile')
4335
contents = b'some data'
4336
info.type = tarfile.REGTYPE
4338
info.size = len(contents)
4339
tf.addfile(info, BytesIO(contents))
4340
client.add_expected_call(
4341
b'Repository.revision_archive', (b'quack/', b'somerevid', b'tar', b'foo.tar', b'', b'', None),
4342
b'success', (b'ok', ),
4344
tree = repo.revision_tree(b'somerevid')
4345
self.assertEqual(f.getvalue(), b''.join(tree.archive('tar', 'foo.tar')))
4348
class TestRepositoryAnnotate(TestRemoteRepository):
4349
"""Test RemoteRevisionTree.annotate.."""
4351
def _serialize_inv_delta(self, old_name, new_name, delta):
4352
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4353
return b"".join(serializer.delta_to_lines(old_name, new_name, delta))
4355
def test_simple(self):
4356
transport_path = 'quack'
4357
repo, client = self.setup_fake_client_and_repository(transport_path)
4358
fmt = controldir.format_registry.get('2a')().repository_format
4360
stream = [('inventory-deltas', [
4361
versionedfile.FulltextContentFactory(b'somerevid', None, None,
4362
self._serialize_inv_delta(b'null:', b'somerevid', []))])]
4363
client.add_expected_call(
4364
b'VersionedFileRepository.get_inventories', (b'quack/', b'unordered'),
4365
b'success', (b'ok', ),
4366
_stream_to_byte_stream(stream, fmt))
4367
client.add_expected_call(
4368
b'Repository.annotate_file_revision',
4369
(b'quack/', b'somerevid', b'filename', b'', b'current:'),
4370
b'success', (b'ok', ),
4371
bencode.bencode([[b'baserevid', b'line 1\n'],
4372
[b'somerevid', b'line2\n']]))
4373
tree = repo.revision_tree(b'somerevid')
4375
(b'baserevid', b'line 1\n'),
4376
(b'somerevid', b'line2\n')],
4377
list(tree.annotate_iter('filename')))