53
63
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,
65
from ..bzr import groupcompress_repo, knitpack_repo
66
from ..revision import (
70
from ..sixish import (
73
from ..bzr.smart import medium, request
74
from ..bzr.smart.client import _SmartClient
75
from ..bzr.smart.repository import (
76
SmartServerRepositoryGetParentMap,
77
SmartServerRepositoryGetStream_1_19,
78
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
83
from .scenarios import load_tests_apply_scenarios
84
from ..transport.memory import MemoryTransport
85
from ..transport.remote import (
70
87
RemoteSSHTransport,
71
88
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 = [
92
load_tests = load_tests_apply_scenarios
95
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
99
{'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):
101
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
105
super(BasicRemoteObjectTests, self).setUp()
89
106
self.transport = self.get_transport()
90
107
# make a branch that can be opened over the smart transport
91
108
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
109
self.addCleanup(self.transport.disconnect)
97
111
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
112
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
113
self.assertIsInstance(b, BzrDir)
101
115
def test_open_remote_branch(self):
102
116
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
117
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
118
branch = b.open_branch()
105
119
self.assertIsInstance(branch, Branch)
480
487
self.assertEqual(None, result._branch_format)
481
488
self.assertFinished(client)
490
def test_unknown(self):
491
transport = self.get_transport('quack')
492
referenced = self.make_branch('referenced')
493
expected = referenced.controldir.cloning_metadir()
494
client = FakeClient(transport.base)
495
client.add_expected_call(
496
'BzrDir.cloning_metadir', ('quack/', 'False'),
497
'success', ('unknown', 'unknown', ('branch', ''))),
498
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
500
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
503
class TestBzrDirCheckoutMetaDir(TestRemote):
505
def test__get_checkout_format(self):
506
transport = MemoryTransport()
507
client = FakeClient(transport.base)
508
reference_bzrdir_format = controldir.format_registry.get('default')()
509
control_name = reference_bzrdir_format.network_name()
510
client.add_expected_call(
511
'BzrDir.checkout_metadir', ('quack/', ),
512
'success', (control_name, '', ''))
513
transport.mkdir('quack')
514
transport = transport.clone('quack')
515
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
result = a_controldir.checkout_metadir()
518
# We should have got a reference control dir with default branch and
519
# repository formats.
520
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
521
self.assertEqual(None, result._repository_format)
522
self.assertEqual(None, result._branch_format)
523
self.assertFinished(client)
525
def test_unknown_format(self):
526
transport = MemoryTransport()
527
client = FakeClient(transport.base)
528
client.add_expected_call(
529
'BzrDir.checkout_metadir', ('quack/',),
530
'success', ('dontknow', '', ''))
531
transport.mkdir('quack')
532
transport = transport.clone('quack')
533
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
535
self.assertRaises(errors.UnknownFormatError,
536
a_controldir.checkout_metadir)
537
self.assertFinished(client)
540
class TestBzrDirGetBranches(TestRemote):
542
def test_get_branches(self):
543
transport = MemoryTransport()
544
client = FakeClient(transport.base)
545
reference_bzrdir_format = controldir.format_registry.get('default')()
546
branch_name = reference_bzrdir_format.get_branch_format().network_name()
547
client.add_success_response_with_body(
549
"foo": ("branch", branch_name),
550
"": ("branch", branch_name)}), "success")
551
client.add_success_response(
552
'ok', '', 'no', 'no', 'no',
553
reference_bzrdir_format.repository_format.network_name())
554
client.add_error_response('NotStacked')
555
client.add_success_response(
556
'ok', '', 'no', 'no', 'no',
557
reference_bzrdir_format.repository_format.network_name())
558
client.add_error_response('NotStacked')
559
transport.mkdir('quack')
560
transport = transport.clone('quack')
561
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
563
result = a_controldir.get_branches()
564
self.assertEqual({"", "foo"}, set(result.keys()))
566
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
567
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
568
('call', 'Branch.get_stacked_on_url', ('quack/', )),
569
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
570
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
574
class TestBzrDirDestroyBranch(TestRemote):
576
def test_destroy_default(self):
577
transport = self.get_transport('quack')
578
referenced = self.make_branch('referenced')
579
client = FakeClient(transport.base)
580
client.add_expected_call(
581
'BzrDir.destroy_branch', ('quack/', ),
583
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
585
a_controldir.destroy_branch()
586
self.assertFinished(client)
589
class TestBzrDirHasWorkingTree(TestRemote):
591
def test_has_workingtree(self):
592
transport = self.get_transport('quack')
593
client = FakeClient(transport.base)
594
client.add_expected_call(
595
'BzrDir.has_workingtree', ('quack/',),
596
'success', ('yes',)),
597
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
599
self.assertTrue(a_controldir.has_workingtree())
600
self.assertFinished(client)
602
def test_no_workingtree(self):
603
transport = self.get_transport('quack')
604
client = FakeClient(transport.base)
605
client.add_expected_call(
606
'BzrDir.has_workingtree', ('quack/',),
608
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
610
self.assertFalse(a_controldir.has_workingtree())
611
self.assertFinished(client)
614
class TestBzrDirDestroyRepository(TestRemote):
616
def test_destroy_repository(self):
617
transport = self.get_transport('quack')
618
client = FakeClient(transport.base)
619
client.add_expected_call(
620
'BzrDir.destroy_repository', ('quack/',),
622
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
624
a_controldir.destroy_repository()
625
self.assertFinished(client)
484
628
class TestBzrDirOpen(TestRemote):
715
859
'BzrDir.create_branch', ('quack/', network_name),
716
860
'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
861
reference_repo_name))
718
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
branch = a_bzrdir.create_branch()
862
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
864
branch = a_controldir.create_branch()
865
# We should have got a remote branch
866
self.assertIsInstance(branch, remote.RemoteBranch)
867
# its format should have the settings from the response
868
format = branch._format
869
self.assertEqual(network_name, format.network_name())
871
def test_already_open_repo_and_reused_medium(self):
872
"""Bug 726584: create_branch(..., repository=repo) should work
873
regardless of what the smart medium's base URL is.
875
self.transport_server = test_server.SmartTCPServer_for_testing
876
transport = self.get_transport('.')
877
repo = self.make_repository('quack')
878
# Client's medium rooted a transport root (not at the bzrdir)
879
client = FakeClient(transport.base)
880
transport = transport.clone('quack')
881
reference_bzrdir_format = controldir.format_registry.get('default')()
882
reference_format = reference_bzrdir_format.get_branch_format()
883
network_name = reference_format.network_name()
884
reference_repo_fmt = reference_bzrdir_format.repository_format
885
reference_repo_name = reference_repo_fmt.network_name()
886
client.add_expected_call(
887
'BzrDir.create_branch', ('extra/quack/', network_name),
888
'success', ('ok', network_name, '', 'no', 'no', 'yes',
889
reference_repo_name))
890
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
892
branch = a_controldir.create_branch(repository=repo)
721
893
# We should have got a remote branch
722
894
self.assertIsInstance(branch, remote.RemoteBranch)
723
895
# its format should have the settings from the response
967
1143
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1146
class TestBranchBreakLock(RemoteBranchTestCase):
1148
def test_break_lock(self):
1149
transport_path = 'quack'
1150
transport = MemoryTransport()
1151
client = FakeClient(transport.base)
1152
client.add_expected_call(
1153
'Branch.get_stacked_on_url', ('quack/',),
1154
'error', ('NotStacked',))
1155
client.add_expected_call(
1156
'Branch.break_lock', ('quack/',),
1158
transport.mkdir('quack')
1159
transport = transport.clone('quack')
1160
branch = self.make_remote_branch(transport, client)
1162
self.assertFinished(client)
1165
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1167
def test_get_physical_lock_status_yes(self):
1168
transport = MemoryTransport()
1169
client = FakeClient(transport.base)
1170
client.add_expected_call(
1171
'Branch.get_stacked_on_url', ('quack/',),
1172
'error', ('NotStacked',))
1173
client.add_expected_call(
1174
'Branch.get_physical_lock_status', ('quack/',),
1175
'success', ('yes',))
1176
transport.mkdir('quack')
1177
transport = transport.clone('quack')
1178
branch = self.make_remote_branch(transport, client)
1179
result = branch.get_physical_lock_status()
1180
self.assertFinished(client)
1181
self.assertEqual(True, result)
1183
def test_get_physical_lock_status_no(self):
1184
transport = MemoryTransport()
1185
client = FakeClient(transport.base)
1186
client.add_expected_call(
1187
'Branch.get_stacked_on_url', ('quack/',),
1188
'error', ('NotStacked',))
1189
client.add_expected_call(
1190
'Branch.get_physical_lock_status', ('quack/',),
1192
transport.mkdir('quack')
1193
transport = transport.clone('quack')
1194
branch = self.make_remote_branch(transport, client)
1195
result = branch.get_physical_lock_status()
1196
self.assertFinished(client)
1197
self.assertEqual(False, result)
970
1200
class TestBranchGetParent(RemoteBranchTestCase):
972
1202
def test_no_parent(self):
1143
1373
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1376
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1378
def test_uses_last_revision_info_and_tags_by_default(self):
1379
transport = MemoryTransport()
1380
client = FakeClient(transport.base)
1381
client.add_expected_call(
1382
'Branch.get_stacked_on_url', ('quack/',),
1383
'error', ('NotStacked',))
1384
client.add_expected_call(
1385
'Branch.last_revision_info', ('quack/',),
1386
'success', ('ok', '1', 'rev-tip'))
1387
client.add_expected_call(
1388
'Branch.get_config_file', ('quack/',),
1389
'success', ('ok',), '')
1390
transport.mkdir('quack')
1391
transport = transport.clone('quack')
1392
branch = self.make_remote_branch(transport, client)
1393
result = branch.heads_to_fetch()
1394
self.assertFinished(client)
1395
self.assertEqual(({'rev-tip'}, set()), result)
1397
def test_uses_last_revision_info_and_tags_when_set(self):
1398
transport = MemoryTransport()
1399
client = FakeClient(transport.base)
1400
client.add_expected_call(
1401
'Branch.get_stacked_on_url', ('quack/',),
1402
'error', ('NotStacked',))
1403
client.add_expected_call(
1404
'Branch.last_revision_info', ('quack/',),
1405
'success', ('ok', '1', 'rev-tip'))
1406
client.add_expected_call(
1407
'Branch.get_config_file', ('quack/',),
1408
'success', ('ok',), 'branch.fetch_tags = True')
1409
# XXX: this will break if the default format's serialization of tags
1410
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1411
client.add_expected_call(
1412
'Branch.get_tags_bytes', ('quack/',),
1413
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1414
transport.mkdir('quack')
1415
transport = transport.clone('quack')
1416
branch = self.make_remote_branch(transport, client)
1417
result = branch.heads_to_fetch()
1418
self.assertFinished(client)
1420
({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
1422
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1423
transport = MemoryTransport()
1424
client = FakeClient(transport.base)
1425
client.add_expected_call(
1426
'Branch.get_stacked_on_url', ('quack/',),
1427
'error', ('NotStacked',))
1428
client.add_expected_call(
1429
'Branch.heads_to_fetch', ('quack/',),
1430
'success', (['tip'], ['tagged-1', 'tagged-2']))
1431
transport.mkdir('quack')
1432
transport = transport.clone('quack')
1433
branch = self.make_remote_branch(transport, client)
1434
branch._format._use_default_local_heads_to_fetch = lambda: False
1435
result = branch.heads_to_fetch()
1436
self.assertFinished(client)
1437
self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
1439
def make_branch_with_tags(self):
1440
self.setup_smart_server_with_call_log()
1441
# Make a branch with a single revision.
1442
builder = self.make_branch_builder('foo')
1443
builder.start_series()
1444
builder.build_snapshot('tip', None, [
1445
('add', ('', 'root-id', 'directory', ''))])
1446
builder.finish_series()
1447
branch = builder.get_branch()
1448
# Add two tags to that branch
1449
branch.tags.set_tag('tag-1', 'rev-1')
1450
branch.tags.set_tag('tag-2', 'rev-2')
1453
def test_backwards_compatible(self):
1454
br = self.make_branch_with_tags()
1455
br.get_config_stack().set('branch.fetch_tags', True)
1456
self.addCleanup(br.lock_read().unlock)
1457
# Disable the heads_to_fetch verb
1458
verb = 'Branch.heads_to_fetch'
1459
self.disable_verb(verb)
1460
self.reset_smart_call_log()
1461
result = br.heads_to_fetch()
1462
self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
1464
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1465
[call.call.method for call in self.hpss_calls])
1467
def test_backwards_compatible_no_tags(self):
1468
br = self.make_branch_with_tags()
1469
br.get_config_stack().set('branch.fetch_tags', False)
1470
self.addCleanup(br.lock_read().unlock)
1471
# Disable the heads_to_fetch verb
1472
verb = 'Branch.heads_to_fetch'
1473
self.disable_verb(verb)
1474
self.reset_smart_call_log()
1475
result = br.heads_to_fetch()
1476
self.assertEqual(({'tip'}, set()), result)
1478
['Branch.last_revision_info'],
1479
[call.call.method for call in self.hpss_calls])
1146
1482
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1484
def test_empty_branch(self):
1661
2017
self.addCleanup(branch.unlock)
1662
2018
self.reset_smart_call_log()
1663
2019
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2020
self.assertLength(11, self.hpss_calls)
1665
2021
self.assertEqual('value', branch._get_config().get_option('name'))
2023
def test_backwards_compat_set_option_with_dict(self):
2024
self.setup_smart_server_with_call_log()
2025
branch = self.make_branch('.')
2026
verb = 'Branch.set_config_option_dict'
2027
self.disable_verb(verb)
2029
self.addCleanup(branch.unlock)
2030
self.reset_smart_call_log()
2031
config = branch._get_config()
2032
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2033
config.set_option(value_dict, 'name')
2034
self.assertLength(11, self.hpss_calls)
2035
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2038
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2040
def test_get_branch_conf(self):
2041
# in an empty branch we decode the response properly
2042
client = FakeClient()
2043
client.add_expected_call(
2044
'Branch.get_stacked_on_url', ('memory:///',),
2045
'error', ('NotStacked',),)
2046
client.add_success_response_with_body('# config file body', 'ok')
2047
transport = MemoryTransport()
2048
branch = self.make_remote_branch(transport, client)
2049
config = branch.get_config_stack()
2051
config.get("log_format")
2053
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2054
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2057
def test_set_branch_conf(self):
2058
client = FakeClient()
2059
client.add_expected_call(
2060
'Branch.get_stacked_on_url', ('memory:///',),
2061
'error', ('NotStacked',),)
2062
client.add_expected_call(
2063
'Branch.lock_write', ('memory:///', '', ''),
2064
'success', ('ok', 'branch token', 'repo token'))
2065
client.add_expected_call(
2066
'Branch.get_config_file', ('memory:///', ),
2067
'success', ('ok', ), "# line 1\n")
2068
client.add_expected_call(
2069
'Branch.get_config_file', ('memory:///', ),
2070
'success', ('ok', ), "# line 1\n")
2071
client.add_expected_call(
2072
'Branch.put_config_file', ('memory:///', 'branch token',
2075
client.add_expected_call(
2076
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2078
transport = MemoryTransport()
2079
branch = self.make_remote_branch(transport, client)
2081
config = branch.get_config_stack()
2082
config.set('email', 'The Dude <lebowski@example.com>')
2084
self.assertFinished(client)
2086
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2087
('call', 'Branch.lock_write', ('memory:///', '', '')),
2088
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2089
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2090
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2091
('memory:///', 'branch token', 'repo token'),
2092
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2093
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2097
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2112
self.assertFinished(client)
2115
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2117
def test_simple(self):
2118
transport = MemoryTransport()
2119
client = FakeClient(transport.base)
2120
client.add_expected_call(
2121
'Branch.get_stacked_on_url', ('quack/',),
2122
'error', ('NotStacked',),)
2123
client.add_expected_call(
2124
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2125
'success', ('ok', '0',),)
2126
client.add_expected_call(
2127
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2128
'error', ('NoSuchRevision', 'unknown',),)
2129
transport.mkdir('quack')
2130
transport = transport.clone('quack')
2131
branch = self.make_remote_branch(transport, client)
2132
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2133
self.assertRaises(errors.NoSuchRevision,
2134
branch.revision_id_to_revno, 'unknown')
2135
self.assertFinished(client)
2137
def test_dotted(self):
2138
transport = MemoryTransport()
2139
client = FakeClient(transport.base)
2140
client.add_expected_call(
2141
'Branch.get_stacked_on_url', ('quack/',),
2142
'error', ('NotStacked',),)
2143
client.add_expected_call(
2144
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2145
'success', ('ok', '0',),)
2146
client.add_expected_call(
2147
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2148
'error', ('NoSuchRevision', 'unknown',),)
2149
transport.mkdir('quack')
2150
transport = transport.clone('quack')
2151
branch = self.make_remote_branch(transport, client)
2152
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2153
self.assertRaises(errors.NoSuchRevision,
2154
branch.revision_id_to_dotted_revno, 'unknown')
2155
self.assertFinished(client)
2157
def test_dotted_no_smart_verb(self):
2158
self.setup_smart_server_with_call_log()
2159
branch = self.make_branch('.')
2160
self.disable_verb('Branch.revision_id_to_revno')
2161
self.reset_smart_call_log()
2162
self.assertEqual((0, ),
2163
branch.revision_id_to_dotted_revno('null:'))
2164
self.assertLength(8, self.hpss_calls)
1686
2167
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2169
def test__get_config(self):
2412
class TestRepositoryBreakLock(TestRemoteRepository):
2414
def test_break_lock(self):
2415
transport_path = 'quack'
2416
repo, client = self.setup_fake_client_and_repository(transport_path)
2417
client.add_success_response('ok')
2420
[('call', 'Repository.break_lock', ('quack/',))],
2424
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2426
def test_get_serializer_format(self):
2427
transport_path = 'hill'
2428
repo, client = self.setup_fake_client_and_repository(transport_path)
2429
client.add_success_response('ok', '7')
2430
self.assertEqual('7', repo.get_serializer_format())
2432
[('call', 'VersionedFileRepository.get_serializer_format',
2437
class TestRepositoryReconcile(TestRemoteRepository):
2439
def test_reconcile(self):
2440
transport_path = 'hill'
2441
repo, client = self.setup_fake_client_and_repository(transport_path)
2442
body = ("garbage_inventories: 2\n"
2443
"inconsistent_parents: 3\n")
2444
client.add_expected_call(
2445
'Repository.lock_write', ('hill/', ''),
2446
'success', ('ok', 'a token'))
2447
client.add_success_response_with_body(body, 'ok')
2448
reconciler = repo.reconcile()
2450
[('call', 'Repository.lock_write', ('hill/', '')),
2451
('call_expecting_body', 'Repository.reconcile',
2452
('hill/', 'a token'))],
2454
self.assertEqual(2, reconciler.garbage_inventories)
2455
self.assertEqual(3, reconciler.inconsistent_parents)
2458
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2460
def test_text(self):
2461
# ('ok',), body with signature text
2462
transport_path = 'quack'
2463
repo, client = self.setup_fake_client_and_repository(transport_path)
2464
client.add_success_response_with_body(
2466
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2468
[('call_expecting_body', 'Repository.get_revision_signature_text',
2469
('quack/', 'revid'))],
2472
def test_no_signature(self):
2473
transport_path = 'quick'
2474
repo, client = self.setup_fake_client_and_repository(transport_path)
2475
client.add_error_response('nosuchrevision', 'unknown')
2476
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2479
[('call_expecting_body', 'Repository.get_revision_signature_text',
2480
('quick/', 'unknown'))],
1906
2484
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2486
def test_get_graph(self):
3075
class TestRepositoryWriteGroups(TestRemoteRepository):
3077
def test_start_write_group(self):
3078
transport_path = 'quack'
3079
repo, client = self.setup_fake_client_and_repository(transport_path)
3080
client.add_expected_call(
3081
'Repository.lock_write', ('quack/', ''),
3082
'success', ('ok', 'a token'))
3083
client.add_expected_call(
3084
'Repository.start_write_group', ('quack/', 'a token'),
3085
'success', ('ok', ('token1', )))
3087
repo.start_write_group()
3089
def test_start_write_group_unsuspendable(self):
3090
# Some repositories do not support suspending write
3091
# groups. For those, fall back to the "real" repository.
3092
transport_path = 'quack'
3093
repo, client = self.setup_fake_client_and_repository(transport_path)
3094
def stub_ensure_real():
3095
client._calls.append(('_ensure_real',))
3096
repo._real_repository = _StubRealPackRepository(client._calls)
3097
repo._ensure_real = stub_ensure_real
3098
client.add_expected_call(
3099
'Repository.lock_write', ('quack/', ''),
3100
'success', ('ok', 'a token'))
3101
client.add_expected_call(
3102
'Repository.start_write_group', ('quack/', 'a token'),
3103
'error', ('UnsuspendableWriteGroup',))
3105
repo.start_write_group()
3106
self.assertEqual(client._calls[-2:], [
3108
('start_write_group',)])
3110
def test_commit_write_group(self):
3111
transport_path = 'quack'
3112
repo, client = self.setup_fake_client_and_repository(transport_path)
3113
client.add_expected_call(
3114
'Repository.lock_write', ('quack/', ''),
3115
'success', ('ok', 'a token'))
3116
client.add_expected_call(
3117
'Repository.start_write_group', ('quack/', 'a token'),
3118
'success', ('ok', ['token1']))
3119
client.add_expected_call(
3120
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3123
repo.start_write_group()
3124
repo.commit_write_group()
3126
def test_abort_write_group(self):
3127
transport_path = 'quack'
3128
repo, client = self.setup_fake_client_and_repository(transport_path)
3129
client.add_expected_call(
3130
'Repository.lock_write', ('quack/', ''),
3131
'success', ('ok', 'a token'))
3132
client.add_expected_call(
3133
'Repository.start_write_group', ('quack/', 'a token'),
3134
'success', ('ok', ['token1']))
3135
client.add_expected_call(
3136
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3139
repo.start_write_group()
3140
repo.abort_write_group(False)
3142
def test_suspend_write_group(self):
3143
transport_path = 'quack'
3144
repo, client = self.setup_fake_client_and_repository(transport_path)
3145
self.assertEqual([], repo.suspend_write_group())
3147
def test_resume_write_group(self):
3148
transport_path = 'quack'
3149
repo, client = self.setup_fake_client_and_repository(transport_path)
3150
client.add_expected_call(
3151
'Repository.lock_write', ('quack/', ''),
3152
'success', ('ok', 'a token'))
3153
client.add_expected_call(
3154
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3157
repo.resume_write_group(['token1'])
2329
3160
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3162
def test_backwards_compat(self):
2895
3780
expected_error = errors.PermissionDenied(path, extra)
2896
3781
self.assertEqual(expected_error, translated_error)
3783
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3785
def test_NoSuchFile_context_path(self):
3786
local_path = "local path"
3787
translated_error = self.translateTuple(('ReadError', "remote path"),
3789
expected_error = errors.ReadError(local_path)
3790
self.assertEqual(expected_error, translated_error)
3792
def test_NoSuchFile_without_context(self):
3793
remote_path = "remote path"
3794
translated_error = self.translateTuple(('ReadError', remote_path))
3795
expected_error = errors.ReadError(remote_path)
3796
self.assertEqual(expected_error, translated_error)
3798
def test_ReadOnlyError(self):
3799
translated_error = self.translateTuple(('ReadOnlyError',))
3800
expected_error = errors.TransportNotPossible("readonly transport")
3801
self.assertEqual(expected_error, translated_error)
3803
def test_MemoryError(self):
3804
translated_error = self.translateTuple(('MemoryError',))
3805
self.assertStartsWith(str(translated_error),
3806
"remote server out of memory")
3808
def test_generic_IndexError_no_classname(self):
3809
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3810
translated_error = self.translateErrorFromSmartServer(err)
3811
expected_error = errors.UnknownErrorFromSmartServer(err)
3812
self.assertEqual(expected_error, translated_error)
3814
# GZ 2011-03-02: TODO test generic non-ascii error string
3816
def test_generic_KeyError(self):
3817
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3818
translated_error = self.translateErrorFromSmartServer(err)
3819
expected_error = errors.UnknownErrorFromSmartServer(err)
3820
self.assertEqual(expected_error, translated_error)
2899
3823
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3824
"""Unit tests for breezy.bzr.remote._translate_error's robustness.
2902
3826
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3827
translate successfully. This class about how _translate_err behaves when
3143
4069
def test_copy_content_into_avoids_revision_history(self):
3144
4070
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4071
builder = self.make_branch_builder('remote')
4072
builder.build_commit(message="Commit.")
3147
4073
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4074
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4075
local.repository.fetch(remote_branch.repository)
3150
4076
self.hpss_calls = []
3151
4077
remote_branch.copy_content_into(local)
3152
4078
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4080
def test_fetch_everything_needs_just_one_call(self):
4081
local = self.make_branch('local')
4082
builder = self.make_branch_builder('remote')
4083
builder.build_commit(message="Commit.")
4084
remote_branch_url = self.smart_server.get_url() + 'remote'
4085
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4086
self.hpss_calls = []
4087
local.repository.fetch(
4088
remote_branch.repository,
4089
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4090
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4092
def override_verb(self, verb_name, verb):
4093
request_handlers = request.request_handlers
4094
orig_verb = request_handlers.get(verb_name)
4095
orig_info = request_handlers.get_info(verb_name)
4096
request_handlers.register(verb_name, verb, override_existing=True)
4097
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4098
override_existing=True, info=orig_info)
4100
def test_fetch_everything_backwards_compat(self):
4101
"""Can fetch with EverythingResult even with pre 2.4 servers.
4103
Pre-2.4 do not support 'everything' searches with the
4104
Repository.get_stream_1.19 verb.
4107
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4108
"""A version of the Repository.get_stream_1.19 verb patched to
4109
reject 'everything' searches the way 2.3 and earlier do.
4111
def recreate_search(self, repository, search_bytes,
4112
discard_excess=False):
4113
verb_log.append(search_bytes.split('\n', 1)[0])
4114
if search_bytes == 'everything':
4116
request.FailedSmartServerResponse(('BadSearch',)))
4117
return super(OldGetStreamVerb,
4118
self).recreate_search(repository, search_bytes,
4119
discard_excess=discard_excess)
4120
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4121
local = self.make_branch('local')
4122
builder = self.make_branch_builder('remote')
4123
builder.build_commit(message="Commit.")
4124
remote_branch_url = self.smart_server.get_url() + 'remote'
4125
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4126
self.hpss_calls = []
4127
local.repository.fetch(
4128
remote_branch.repository,
4129
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4130
# make sure the overridden verb was used
4131
self.assertLength(1, verb_log)
4132
# more than one HPSS call is needed, but because it's a VFS callback
4133
# its hard to predict exactly how many.
4134
self.assertTrue(len(self.hpss_calls) > 1)
4137
class TestUpdateBoundBranchWithModifiedBoundLocation(
4138
tests.TestCaseWithTransport):
4139
"""Ensure correct handling of bound_location modifications.
4141
This is tested against a smart server as http://pad.lv/786980 was about a
4142
ReadOnlyError (write attempt during a read-only transaction) which can only
4143
happen in this context.
4147
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4148
self.transport_server = test_server.SmartTCPServer_for_testing
4150
def make_master_and_checkout(self, master_name, checkout_name):
4151
# Create the master branch and its associated checkout
4152
self.master = self.make_branch_and_tree(master_name)
4153
self.checkout = self.master.branch.create_checkout(checkout_name)
4154
# Modify the master branch so there is something to update
4155
self.master.commit('add stuff')
4156
self.last_revid = self.master.commit('even more stuff')
4157
self.bound_location = self.checkout.branch.get_bound_location()
4159
def assertUpdateSucceeds(self, new_location):
4160
self.checkout.branch.set_bound_location(new_location)
4161
self.checkout.update()
4162
self.assertEqual(self.last_revid, self.checkout.last_revision())
4164
def test_without_final_slash(self):
4165
self.make_master_and_checkout('master', 'checkout')
4166
# For unclear reasons some users have a bound_location without a final
4167
# '/', simulate that by forcing such a value
4168
self.assertEndsWith(self.bound_location, '/')
4169
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4171
def test_plus_sign(self):
4172
self.make_master_and_checkout('+master', 'checkout')
4173
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4175
def test_tilda(self):
4176
# Embed ~ in the middle of the path just to avoid any $HOME
4178
self.make_master_and_checkout('mas~ter', 'checkout')
4179
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4182
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4184
def test_no_context(self):
4185
class OutOfCoffee(errors.BzrError):
4186
"""A dummy exception for testing."""
4188
def __init__(self, urgency):
4189
self.urgency = urgency
4190
remote.no_context_error_translators.register("OutOfCoffee",
4191
lambda err: OutOfCoffee(err.error_args[0]))
4192
transport = MemoryTransport()
4193
client = FakeClient(transport.base)
4194
client.add_expected_call(
4195
'Branch.get_stacked_on_url', ('quack/',),
4196
'error', ('NotStacked',))
4197
client.add_expected_call(
4198
'Branch.last_revision_info',
4200
'error', ('OutOfCoffee', 'low'))
4201
transport.mkdir('quack')
4202
transport = transport.clone('quack')
4203
branch = self.make_remote_branch(transport, client)
4204
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4205
self.assertFinished(client)
4207
def test_with_context(self):
4208
class OutOfTea(errors.BzrError):
4209
def __init__(self, branch, urgency):
4210
self.branch = branch
4211
self.urgency = urgency
4212
remote.error_translators.register("OutOfTea",
4213
lambda err, find, path: OutOfTea(err.error_args[0],
4215
transport = MemoryTransport()
4216
client = FakeClient(transport.base)
4217
client.add_expected_call(
4218
'Branch.get_stacked_on_url', ('quack/',),
4219
'error', ('NotStacked',))
4220
client.add_expected_call(
4221
'Branch.last_revision_info',
4223
'error', ('OutOfTea', 'low'))
4224
transport.mkdir('quack')
4225
transport = transport.clone('quack')
4226
branch = self.make_remote_branch(transport, client)
4227
self.assertRaises(OutOfTea, branch.last_revision_info)
4228
self.assertFinished(client)
4231
class TestRepositoryPack(TestRemoteRepository):
4233
def test_pack(self):
4234
transport_path = 'quack'
4235
repo, client = self.setup_fake_client_and_repository(transport_path)
4236
client.add_expected_call(
4237
'Repository.lock_write', ('quack/', ''),
4238
'success', ('ok', 'token'))
4239
client.add_expected_call(
4240
'Repository.pack', ('quack/', 'token', 'False'),
4241
'success', ('ok',), )
4242
client.add_expected_call(
4243
'Repository.unlock', ('quack/', 'token'),
4244
'success', ('ok', ))
4247
def test_pack_with_hint(self):
4248
transport_path = 'quack'
4249
repo, client = self.setup_fake_client_and_repository(transport_path)
4250
client.add_expected_call(
4251
'Repository.lock_write', ('quack/', ''),
4252
'success', ('ok', 'token'))
4253
client.add_expected_call(
4254
'Repository.pack', ('quack/', 'token', 'False'),
4255
'success', ('ok',), )
4256
client.add_expected_call(
4257
'Repository.unlock', ('quack/', 'token', 'False'),
4258
'success', ('ok', ))
4259
repo.pack(['hinta', 'hintb'])
4262
class TestRepositoryIterInventories(TestRemoteRepository):
4263
"""Test Repository.iter_inventories."""
4265
def _serialize_inv_delta(self, old_name, new_name, delta):
4266
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4267
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4269
def test_single_empty(self):
4270
transport_path = 'quack'
4271
repo, client = self.setup_fake_client_and_repository(transport_path)
4272
fmt = controldir.format_registry.get('2a')().repository_format
4274
stream = [('inventory-deltas', [
4275
versionedfile.FulltextContentFactory('somerevid', None, None,
4276
self._serialize_inv_delta('null:', 'somerevid', []))])]
4277
client.add_expected_call(
4278
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4279
'success', ('ok', ),
4280
_stream_to_byte_stream(stream, fmt))
4281
ret = list(repo.iter_inventories(["somerevid"]))
4282
self.assertLength(1, ret)
4284
self.assertEqual("somerevid", inv.revision_id)
4286
def test_empty(self):
4287
transport_path = 'quack'
4288
repo, client = self.setup_fake_client_and_repository(transport_path)
4289
ret = list(repo.iter_inventories([]))
4290
self.assertEqual(ret, [])
4292
def test_missing(self):
4293
transport_path = 'quack'
4294
repo, client = self.setup_fake_client_and_repository(transport_path)
4295
client.add_expected_call(
4296
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4297
'success', ('ok', ), iter([]))
4298
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(