53
64
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
58
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
60
from bzrlib.tests import (
62
split_suite_by_condition,
66
from ..bzr import groupcompress_repo, knitpack_repo
67
from ..revision import (
71
from ..sixish import (
74
from ..bzr.smart import medium, request
75
from ..bzr.smart.client import _SmartClient
76
from ..bzr.smart.repository import (
77
SmartServerRepositoryGetParentMap,
78
SmartServerRepositoryGetStream_1_19,
79
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
84
from .scenarios import load_tests_apply_scenarios
85
from ..transport.memory import MemoryTransport
86
from ..transport.remote import (
70
88
RemoteSSHTransport,
71
89
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 = [
93
load_tests = load_tests_apply_scenarios
96
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
100
{'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):
102
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
106
super(BasicRemoteObjectTests, self).setUp()
89
107
self.transport = self.get_transport()
90
108
# make a branch that can be opened over the smart transport
91
109
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
110
self.addCleanup(self.transport.disconnect)
97
112
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
113
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
114
self.assertIsInstance(b, BzrDir)
101
116
def test_open_remote_branch(self):
102
117
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
118
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
119
branch = b.open_branch()
105
120
self.assertIsInstance(branch, Branch)
480
488
self.assertEqual(None, result._branch_format)
481
489
self.assertFinished(client)
491
def test_unknown(self):
492
transport = self.get_transport('quack')
493
referenced = self.make_branch('referenced')
494
expected = referenced.controldir.cloning_metadir()
495
client = FakeClient(transport.base)
496
client.add_expected_call(
497
'BzrDir.cloning_metadir', ('quack/', 'False'),
498
'success', ('unknown', 'unknown', ('branch', ''))),
499
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
501
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
504
class TestBzrDirCheckoutMetaDir(TestRemote):
506
def test__get_checkout_format(self):
507
transport = MemoryTransport()
508
client = FakeClient(transport.base)
509
reference_bzrdir_format = controldir.format_registry.get('default')()
510
control_name = reference_bzrdir_format.network_name()
511
client.add_expected_call(
512
'BzrDir.checkout_metadir', ('quack/', ),
513
'success', (control_name, '', ''))
514
transport.mkdir('quack')
515
transport = transport.clone('quack')
516
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
518
result = a_controldir.checkout_metadir()
519
# We should have got a reference control dir with default branch and
520
# repository formats.
521
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
522
self.assertEqual(None, result._repository_format)
523
self.assertEqual(None, result._branch_format)
524
self.assertFinished(client)
526
def test_unknown_format(self):
527
transport = MemoryTransport()
528
client = FakeClient(transport.base)
529
client.add_expected_call(
530
'BzrDir.checkout_metadir', ('quack/',),
531
'success', ('dontknow', '', ''))
532
transport.mkdir('quack')
533
transport = transport.clone('quack')
534
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
536
self.assertRaises(errors.UnknownFormatError,
537
a_controldir.checkout_metadir)
538
self.assertFinished(client)
541
class TestBzrDirGetBranches(TestRemote):
543
def test_get_branches(self):
544
transport = MemoryTransport()
545
client = FakeClient(transport.base)
546
reference_bzrdir_format = controldir.format_registry.get('default')()
547
branch_name = reference_bzrdir_format.get_branch_format().network_name()
548
client.add_success_response_with_body(
550
"foo": ("branch", branch_name),
551
"": ("branch", branch_name)}), "success")
552
client.add_success_response(
553
'ok', '', 'no', 'no', 'no',
554
reference_bzrdir_format.repository_format.network_name())
555
client.add_error_response('NotStacked')
556
client.add_success_response(
557
'ok', '', 'no', 'no', 'no',
558
reference_bzrdir_format.repository_format.network_name())
559
client.add_error_response('NotStacked')
560
transport.mkdir('quack')
561
transport = transport.clone('quack')
562
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
564
result = a_controldir.get_branches()
565
self.assertEqual({"", "foo"}, set(result.keys()))
567
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
568
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
569
('call', 'Branch.get_stacked_on_url', ('quack/', )),
570
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
571
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
575
class TestBzrDirDestroyBranch(TestRemote):
577
def test_destroy_default(self):
578
transport = self.get_transport('quack')
579
referenced = self.make_branch('referenced')
580
client = FakeClient(transport.base)
581
client.add_expected_call(
582
'BzrDir.destroy_branch', ('quack/', ),
584
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
586
a_controldir.destroy_branch()
587
self.assertFinished(client)
590
class TestBzrDirHasWorkingTree(TestRemote):
592
def test_has_workingtree(self):
593
transport = self.get_transport('quack')
594
client = FakeClient(transport.base)
595
client.add_expected_call(
596
'BzrDir.has_workingtree', ('quack/',),
597
'success', ('yes',)),
598
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
600
self.assertTrue(a_controldir.has_workingtree())
601
self.assertFinished(client)
603
def test_no_workingtree(self):
604
transport = self.get_transport('quack')
605
client = FakeClient(transport.base)
606
client.add_expected_call(
607
'BzrDir.has_workingtree', ('quack/',),
609
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
611
self.assertFalse(a_controldir.has_workingtree())
612
self.assertFinished(client)
615
class TestBzrDirDestroyRepository(TestRemote):
617
def test_destroy_repository(self):
618
transport = self.get_transport('quack')
619
client = FakeClient(transport.base)
620
client.add_expected_call(
621
'BzrDir.destroy_repository', ('quack/',),
623
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
625
a_controldir.destroy_repository()
626
self.assertFinished(client)
484
629
class TestBzrDirOpen(TestRemote):
715
860
'BzrDir.create_branch', ('quack/', network_name),
716
861
'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
862
reference_repo_name))
718
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
branch = a_bzrdir.create_branch()
863
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
865
branch = a_controldir.create_branch()
866
# We should have got a remote branch
867
self.assertIsInstance(branch, remote.RemoteBranch)
868
# its format should have the settings from the response
869
format = branch._format
870
self.assertEqual(network_name, format.network_name())
872
def test_already_open_repo_and_reused_medium(self):
873
"""Bug 726584: create_branch(..., repository=repo) should work
874
regardless of what the smart medium's base URL is.
876
self.transport_server = test_server.SmartTCPServer_for_testing
877
transport = self.get_transport('.')
878
repo = self.make_repository('quack')
879
# Client's medium rooted a transport root (not at the bzrdir)
880
client = FakeClient(transport.base)
881
transport = transport.clone('quack')
882
reference_bzrdir_format = controldir.format_registry.get('default')()
883
reference_format = reference_bzrdir_format.get_branch_format()
884
network_name = reference_format.network_name()
885
reference_repo_fmt = reference_bzrdir_format.repository_format
886
reference_repo_name = reference_repo_fmt.network_name()
887
client.add_expected_call(
888
'BzrDir.create_branch', ('extra/quack/', network_name),
889
'success', ('ok', network_name, '', 'no', 'no', 'yes',
890
reference_repo_name))
891
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
893
branch = a_controldir.create_branch(repository=repo)
721
894
# We should have got a remote branch
722
895
self.assertIsInstance(branch, remote.RemoteBranch)
723
896
# its format should have the settings from the response
967
1144
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1147
class TestBranchBreakLock(RemoteBranchTestCase):
1149
def test_break_lock(self):
1150
transport_path = 'quack'
1151
transport = MemoryTransport()
1152
client = FakeClient(transport.base)
1153
client.add_expected_call(
1154
'Branch.get_stacked_on_url', ('quack/',),
1155
'error', ('NotStacked',))
1156
client.add_expected_call(
1157
'Branch.break_lock', ('quack/',),
1159
transport.mkdir('quack')
1160
transport = transport.clone('quack')
1161
branch = self.make_remote_branch(transport, client)
1163
self.assertFinished(client)
1166
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1168
def test_get_physical_lock_status_yes(self):
1169
transport = MemoryTransport()
1170
client = FakeClient(transport.base)
1171
client.add_expected_call(
1172
'Branch.get_stacked_on_url', ('quack/',),
1173
'error', ('NotStacked',))
1174
client.add_expected_call(
1175
'Branch.get_physical_lock_status', ('quack/',),
1176
'success', ('yes',))
1177
transport.mkdir('quack')
1178
transport = transport.clone('quack')
1179
branch = self.make_remote_branch(transport, client)
1180
result = branch.get_physical_lock_status()
1181
self.assertFinished(client)
1182
self.assertEqual(True, result)
1184
def test_get_physical_lock_status_no(self):
1185
transport = MemoryTransport()
1186
client = FakeClient(transport.base)
1187
client.add_expected_call(
1188
'Branch.get_stacked_on_url', ('quack/',),
1189
'error', ('NotStacked',))
1190
client.add_expected_call(
1191
'Branch.get_physical_lock_status', ('quack/',),
1193
transport.mkdir('quack')
1194
transport = transport.clone('quack')
1195
branch = self.make_remote_branch(transport, client)
1196
result = branch.get_physical_lock_status()
1197
self.assertFinished(client)
1198
self.assertEqual(False, result)
970
1201
class TestBranchGetParent(RemoteBranchTestCase):
972
1203
def test_no_parent(self):
1143
1374
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1377
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1379
def test_uses_last_revision_info_and_tags_by_default(self):
1380
transport = MemoryTransport()
1381
client = FakeClient(transport.base)
1382
client.add_expected_call(
1383
'Branch.get_stacked_on_url', ('quack/',),
1384
'error', ('NotStacked',))
1385
client.add_expected_call(
1386
'Branch.last_revision_info', ('quack/',),
1387
'success', ('ok', '1', 'rev-tip'))
1388
client.add_expected_call(
1389
'Branch.get_config_file', ('quack/',),
1390
'success', ('ok',), '')
1391
transport.mkdir('quack')
1392
transport = transport.clone('quack')
1393
branch = self.make_remote_branch(transport, client)
1394
result = branch.heads_to_fetch()
1395
self.assertFinished(client)
1396
self.assertEqual(({'rev-tip'}, set()), result)
1398
def test_uses_last_revision_info_and_tags_when_set(self):
1399
transport = MemoryTransport()
1400
client = FakeClient(transport.base)
1401
client.add_expected_call(
1402
'Branch.get_stacked_on_url', ('quack/',),
1403
'error', ('NotStacked',))
1404
client.add_expected_call(
1405
'Branch.last_revision_info', ('quack/',),
1406
'success', ('ok', '1', 'rev-tip'))
1407
client.add_expected_call(
1408
'Branch.get_config_file', ('quack/',),
1409
'success', ('ok',), 'branch.fetch_tags = True')
1410
# XXX: this will break if the default format's serialization of tags
1411
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1412
client.add_expected_call(
1413
'Branch.get_tags_bytes', ('quack/',),
1414
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1415
transport.mkdir('quack')
1416
transport = transport.clone('quack')
1417
branch = self.make_remote_branch(transport, client)
1418
result = branch.heads_to_fetch()
1419
self.assertFinished(client)
1421
({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
1423
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1424
transport = MemoryTransport()
1425
client = FakeClient(transport.base)
1426
client.add_expected_call(
1427
'Branch.get_stacked_on_url', ('quack/',),
1428
'error', ('NotStacked',))
1429
client.add_expected_call(
1430
'Branch.heads_to_fetch', ('quack/',),
1431
'success', (['tip'], ['tagged-1', 'tagged-2']))
1432
transport.mkdir('quack')
1433
transport = transport.clone('quack')
1434
branch = self.make_remote_branch(transport, client)
1435
branch._format._use_default_local_heads_to_fetch = lambda: False
1436
result = branch.heads_to_fetch()
1437
self.assertFinished(client)
1438
self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
1440
def make_branch_with_tags(self):
1441
self.setup_smart_server_with_call_log()
1442
# Make a branch with a single revision.
1443
builder = self.make_branch_builder('foo')
1444
builder.start_series()
1445
builder.build_snapshot('tip', None, [
1446
('add', ('', 'root-id', 'directory', ''))])
1447
builder.finish_series()
1448
branch = builder.get_branch()
1449
# Add two tags to that branch
1450
branch.tags.set_tag('tag-1', 'rev-1')
1451
branch.tags.set_tag('tag-2', 'rev-2')
1454
def test_backwards_compatible(self):
1455
br = self.make_branch_with_tags()
1456
br.get_config_stack().set('branch.fetch_tags', True)
1457
self.addCleanup(br.lock_read().unlock)
1458
# Disable the heads_to_fetch verb
1459
verb = 'Branch.heads_to_fetch'
1460
self.disable_verb(verb)
1461
self.reset_smart_call_log()
1462
result = br.heads_to_fetch()
1463
self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
1465
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1466
[call.call.method for call in self.hpss_calls])
1468
def test_backwards_compatible_no_tags(self):
1469
br = self.make_branch_with_tags()
1470
br.get_config_stack().set('branch.fetch_tags', False)
1471
self.addCleanup(br.lock_read().unlock)
1472
# Disable the heads_to_fetch verb
1473
verb = 'Branch.heads_to_fetch'
1474
self.disable_verb(verb)
1475
self.reset_smart_call_log()
1476
result = br.heads_to_fetch()
1477
self.assertEqual(({'tip'}, set()), result)
1479
['Branch.last_revision_info'],
1480
[call.call.method for call in self.hpss_calls])
1146
1483
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1485
def test_empty_branch(self):
1661
2018
self.addCleanup(branch.unlock)
1662
2019
self.reset_smart_call_log()
1663
2020
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2021
self.assertLength(11, self.hpss_calls)
1665
2022
self.assertEqual('value', branch._get_config().get_option('name'))
2024
def test_backwards_compat_set_option_with_dict(self):
2025
self.setup_smart_server_with_call_log()
2026
branch = self.make_branch('.')
2027
verb = 'Branch.set_config_option_dict'
2028
self.disable_verb(verb)
2030
self.addCleanup(branch.unlock)
2031
self.reset_smart_call_log()
2032
config = branch._get_config()
2033
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2034
config.set_option(value_dict, 'name')
2035
self.assertLength(11, self.hpss_calls)
2036
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2039
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2041
def test_get_branch_conf(self):
2042
# in an empty branch we decode the response properly
2043
client = FakeClient()
2044
client.add_expected_call(
2045
'Branch.get_stacked_on_url', ('memory:///',),
2046
'error', ('NotStacked',),)
2047
client.add_success_response_with_body('# config file body', 'ok')
2048
transport = MemoryTransport()
2049
branch = self.make_remote_branch(transport, client)
2050
config = branch.get_config_stack()
2052
config.get("log_format")
2054
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2055
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2058
def test_set_branch_conf(self):
2059
client = FakeClient()
2060
client.add_expected_call(
2061
'Branch.get_stacked_on_url', ('memory:///',),
2062
'error', ('NotStacked',),)
2063
client.add_expected_call(
2064
'Branch.lock_write', ('memory:///', '', ''),
2065
'success', ('ok', 'branch token', 'repo token'))
2066
client.add_expected_call(
2067
'Branch.get_config_file', ('memory:///', ),
2068
'success', ('ok', ), "# line 1\n")
2069
client.add_expected_call(
2070
'Branch.get_config_file', ('memory:///', ),
2071
'success', ('ok', ), "# line 1\n")
2072
client.add_expected_call(
2073
'Branch.put_config_file', ('memory:///', 'branch token',
2076
client.add_expected_call(
2077
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2079
transport = MemoryTransport()
2080
branch = self.make_remote_branch(transport, client)
2082
config = branch.get_config_stack()
2083
config.set('email', 'The Dude <lebowski@example.com>')
2085
self.assertFinished(client)
2087
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2088
('call', 'Branch.lock_write', ('memory:///', '', '')),
2089
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2090
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2091
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2092
('memory:///', 'branch token', 'repo token'),
2093
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2094
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2098
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2113
self.assertFinished(client)
2116
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2118
def test_simple(self):
2119
transport = MemoryTransport()
2120
client = FakeClient(transport.base)
2121
client.add_expected_call(
2122
'Branch.get_stacked_on_url', ('quack/',),
2123
'error', ('NotStacked',),)
2124
client.add_expected_call(
2125
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2126
'success', ('ok', '0',),)
2127
client.add_expected_call(
2128
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2129
'error', ('NoSuchRevision', 'unknown',),)
2130
transport.mkdir('quack')
2131
transport = transport.clone('quack')
2132
branch = self.make_remote_branch(transport, client)
2133
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2134
self.assertRaises(errors.NoSuchRevision,
2135
branch.revision_id_to_revno, 'unknown')
2136
self.assertFinished(client)
2138
def test_dotted(self):
2139
transport = MemoryTransport()
2140
client = FakeClient(transport.base)
2141
client.add_expected_call(
2142
'Branch.get_stacked_on_url', ('quack/',),
2143
'error', ('NotStacked',),)
2144
client.add_expected_call(
2145
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2146
'success', ('ok', '0',),)
2147
client.add_expected_call(
2148
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2149
'error', ('NoSuchRevision', 'unknown',),)
2150
transport.mkdir('quack')
2151
transport = transport.clone('quack')
2152
branch = self.make_remote_branch(transport, client)
2153
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2154
self.assertRaises(errors.NoSuchRevision,
2155
branch.revision_id_to_dotted_revno, 'unknown')
2156
self.assertFinished(client)
2158
def test_dotted_no_smart_verb(self):
2159
self.setup_smart_server_with_call_log()
2160
branch = self.make_branch('.')
2161
self.disable_verb('Branch.revision_id_to_revno')
2162
self.reset_smart_call_log()
2163
self.assertEqual((0, ),
2164
branch.revision_id_to_dotted_revno('null:'))
2165
self.assertLength(8, self.hpss_calls)
1686
2168
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2170
def test__get_config(self):
2413
class TestRepositoryBreakLock(TestRemoteRepository):
2415
def test_break_lock(self):
2416
transport_path = 'quack'
2417
repo, client = self.setup_fake_client_and_repository(transport_path)
2418
client.add_success_response('ok')
2421
[('call', 'Repository.break_lock', ('quack/',))],
2425
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2427
def test_get_serializer_format(self):
2428
transport_path = 'hill'
2429
repo, client = self.setup_fake_client_and_repository(transport_path)
2430
client.add_success_response('ok', '7')
2431
self.assertEqual('7', repo.get_serializer_format())
2433
[('call', 'VersionedFileRepository.get_serializer_format',
2438
class TestRepositoryReconcile(TestRemoteRepository):
2440
def test_reconcile(self):
2441
transport_path = 'hill'
2442
repo, client = self.setup_fake_client_and_repository(transport_path)
2443
body = ("garbage_inventories: 2\n"
2444
"inconsistent_parents: 3\n")
2445
client.add_expected_call(
2446
'Repository.lock_write', ('hill/', ''),
2447
'success', ('ok', 'a token'))
2448
client.add_success_response_with_body(body, 'ok')
2449
reconciler = repo.reconcile()
2451
[('call', 'Repository.lock_write', ('hill/', '')),
2452
('call_expecting_body', 'Repository.reconcile',
2453
('hill/', 'a token'))],
2455
self.assertEqual(2, reconciler.garbage_inventories)
2456
self.assertEqual(3, reconciler.inconsistent_parents)
2459
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2461
def test_text(self):
2462
# ('ok',), body with signature text
2463
transport_path = 'quack'
2464
repo, client = self.setup_fake_client_and_repository(transport_path)
2465
client.add_success_response_with_body(
2467
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2469
[('call_expecting_body', 'Repository.get_revision_signature_text',
2470
('quack/', 'revid'))],
2473
def test_no_signature(self):
2474
transport_path = 'quick'
2475
repo, client = self.setup_fake_client_and_repository(transport_path)
2476
client.add_error_response('nosuchrevision', 'unknown')
2477
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2480
[('call_expecting_body', 'Repository.get_revision_signature_text',
2481
('quick/', 'unknown'))],
1906
2485
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2487
def test_get_graph(self):
3076
class TestRepositoryWriteGroups(TestRemoteRepository):
3078
def test_start_write_group(self):
3079
transport_path = 'quack'
3080
repo, client = self.setup_fake_client_and_repository(transport_path)
3081
client.add_expected_call(
3082
'Repository.lock_write', ('quack/', ''),
3083
'success', ('ok', 'a token'))
3084
client.add_expected_call(
3085
'Repository.start_write_group', ('quack/', 'a token'),
3086
'success', ('ok', ('token1', )))
3088
repo.start_write_group()
3090
def test_start_write_group_unsuspendable(self):
3091
# Some repositories do not support suspending write
3092
# groups. For those, fall back to the "real" repository.
3093
transport_path = 'quack'
3094
repo, client = self.setup_fake_client_and_repository(transport_path)
3095
def stub_ensure_real():
3096
client._calls.append(('_ensure_real',))
3097
repo._real_repository = _StubRealPackRepository(client._calls)
3098
repo._ensure_real = stub_ensure_real
3099
client.add_expected_call(
3100
'Repository.lock_write', ('quack/', ''),
3101
'success', ('ok', 'a token'))
3102
client.add_expected_call(
3103
'Repository.start_write_group', ('quack/', 'a token'),
3104
'error', ('UnsuspendableWriteGroup',))
3106
repo.start_write_group()
3107
self.assertEqual(client._calls[-2:], [
3109
('start_write_group',)])
3111
def test_commit_write_group(self):
3112
transport_path = 'quack'
3113
repo, client = self.setup_fake_client_and_repository(transport_path)
3114
client.add_expected_call(
3115
'Repository.lock_write', ('quack/', ''),
3116
'success', ('ok', 'a token'))
3117
client.add_expected_call(
3118
'Repository.start_write_group', ('quack/', 'a token'),
3119
'success', ('ok', ['token1']))
3120
client.add_expected_call(
3121
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3124
repo.start_write_group()
3125
repo.commit_write_group()
3127
def test_abort_write_group(self):
3128
transport_path = 'quack'
3129
repo, client = self.setup_fake_client_and_repository(transport_path)
3130
client.add_expected_call(
3131
'Repository.lock_write', ('quack/', ''),
3132
'success', ('ok', 'a token'))
3133
client.add_expected_call(
3134
'Repository.start_write_group', ('quack/', 'a token'),
3135
'success', ('ok', ['token1']))
3136
client.add_expected_call(
3137
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3140
repo.start_write_group()
3141
repo.abort_write_group(False)
3143
def test_suspend_write_group(self):
3144
transport_path = 'quack'
3145
repo, client = self.setup_fake_client_and_repository(transport_path)
3146
self.assertEqual([], repo.suspend_write_group())
3148
def test_resume_write_group(self):
3149
transport_path = 'quack'
3150
repo, client = self.setup_fake_client_and_repository(transport_path)
3151
client.add_expected_call(
3152
'Repository.lock_write', ('quack/', ''),
3153
'success', ('ok', 'a token'))
3154
client.add_expected_call(
3155
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3158
repo.resume_write_group(['token1'])
2329
3161
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3163
def test_backwards_compat(self):
2895
3781
expected_error = errors.PermissionDenied(path, extra)
2896
3782
self.assertEqual(expected_error, translated_error)
3784
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3786
def test_NoSuchFile_context_path(self):
3787
local_path = "local path"
3788
translated_error = self.translateTuple(('ReadError', "remote path"),
3790
expected_error = errors.ReadError(local_path)
3791
self.assertEqual(expected_error, translated_error)
3793
def test_NoSuchFile_without_context(self):
3794
remote_path = "remote path"
3795
translated_error = self.translateTuple(('ReadError', remote_path))
3796
expected_error = errors.ReadError(remote_path)
3797
self.assertEqual(expected_error, translated_error)
3799
def test_ReadOnlyError(self):
3800
translated_error = self.translateTuple(('ReadOnlyError',))
3801
expected_error = errors.TransportNotPossible("readonly transport")
3802
self.assertEqual(expected_error, translated_error)
3804
def test_MemoryError(self):
3805
translated_error = self.translateTuple(('MemoryError',))
3806
self.assertStartsWith(str(translated_error),
3807
"remote server out of memory")
3809
def test_generic_IndexError_no_classname(self):
3810
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3811
translated_error = self.translateErrorFromSmartServer(err)
3812
expected_error = errors.UnknownErrorFromSmartServer(err)
3813
self.assertEqual(expected_error, translated_error)
3815
# GZ 2011-03-02: TODO test generic non-ascii error string
3817
def test_generic_KeyError(self):
3818
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3819
translated_error = self.translateErrorFromSmartServer(err)
3820
expected_error = errors.UnknownErrorFromSmartServer(err)
3821
self.assertEqual(expected_error, translated_error)
2899
3824
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3825
"""Unit tests for breezy.bzr.remote._translate_error's robustness.
2902
3827
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3828
translate successfully. This class about how _translate_err behaves when
3143
4070
def test_copy_content_into_avoids_revision_history(self):
3144
4071
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4072
builder = self.make_branch_builder('remote')
4073
builder.build_commit(message="Commit.")
3147
4074
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4075
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4076
local.repository.fetch(remote_branch.repository)
3150
4077
self.hpss_calls = []
3151
4078
remote_branch.copy_content_into(local)
3152
4079
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4081
def test_fetch_everything_needs_just_one_call(self):
4082
local = self.make_branch('local')
4083
builder = self.make_branch_builder('remote')
4084
builder.build_commit(message="Commit.")
4085
remote_branch_url = self.smart_server.get_url() + 'remote'
4086
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4087
self.hpss_calls = []
4088
local.repository.fetch(
4089
remote_branch.repository,
4090
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4091
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4093
def override_verb(self, verb_name, verb):
4094
request_handlers = request.request_handlers
4095
orig_verb = request_handlers.get(verb_name)
4096
orig_info = request_handlers.get_info(verb_name)
4097
request_handlers.register(verb_name, verb, override_existing=True)
4098
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4099
override_existing=True, info=orig_info)
4101
def test_fetch_everything_backwards_compat(self):
4102
"""Can fetch with EverythingResult even with pre 2.4 servers.
4104
Pre-2.4 do not support 'everything' searches with the
4105
Repository.get_stream_1.19 verb.
4108
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4109
"""A version of the Repository.get_stream_1.19 verb patched to
4110
reject 'everything' searches the way 2.3 and earlier do.
4112
def recreate_search(self, repository, search_bytes,
4113
discard_excess=False):
4114
verb_log.append(search_bytes.split('\n', 1)[0])
4115
if search_bytes == 'everything':
4117
request.FailedSmartServerResponse(('BadSearch',)))
4118
return super(OldGetStreamVerb,
4119
self).recreate_search(repository, search_bytes,
4120
discard_excess=discard_excess)
4121
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4122
local = self.make_branch('local')
4123
builder = self.make_branch_builder('remote')
4124
builder.build_commit(message="Commit.")
4125
remote_branch_url = self.smart_server.get_url() + 'remote'
4126
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4127
self.hpss_calls = []
4128
local.repository.fetch(
4129
remote_branch.repository,
4130
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4131
# make sure the overridden verb was used
4132
self.assertLength(1, verb_log)
4133
# more than one HPSS call is needed, but because it's a VFS callback
4134
# its hard to predict exactly how many.
4135
self.assertTrue(len(self.hpss_calls) > 1)
4138
class TestUpdateBoundBranchWithModifiedBoundLocation(
4139
tests.TestCaseWithTransport):
4140
"""Ensure correct handling of bound_location modifications.
4142
This is tested against a smart server as http://pad.lv/786980 was about a
4143
ReadOnlyError (write attempt during a read-only transaction) which can only
4144
happen in this context.
4148
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4149
self.transport_server = test_server.SmartTCPServer_for_testing
4151
def make_master_and_checkout(self, master_name, checkout_name):
4152
# Create the master branch and its associated checkout
4153
self.master = self.make_branch_and_tree(master_name)
4154
self.checkout = self.master.branch.create_checkout(checkout_name)
4155
# Modify the master branch so there is something to update
4156
self.master.commit('add stuff')
4157
self.last_revid = self.master.commit('even more stuff')
4158
self.bound_location = self.checkout.branch.get_bound_location()
4160
def assertUpdateSucceeds(self, new_location):
4161
self.checkout.branch.set_bound_location(new_location)
4162
self.checkout.update()
4163
self.assertEqual(self.last_revid, self.checkout.last_revision())
4165
def test_without_final_slash(self):
4166
self.make_master_and_checkout('master', 'checkout')
4167
# For unclear reasons some users have a bound_location without a final
4168
# '/', simulate that by forcing such a value
4169
self.assertEndsWith(self.bound_location, '/')
4170
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4172
def test_plus_sign(self):
4173
self.make_master_and_checkout('+master', 'checkout')
4174
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4176
def test_tilda(self):
4177
# Embed ~ in the middle of the path just to avoid any $HOME
4179
self.make_master_and_checkout('mas~ter', 'checkout')
4180
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4183
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4185
def test_no_context(self):
4186
class OutOfCoffee(errors.BzrError):
4187
"""A dummy exception for testing."""
4189
def __init__(self, urgency):
4190
self.urgency = urgency
4191
remote.no_context_error_translators.register("OutOfCoffee",
4192
lambda err: OutOfCoffee(err.error_args[0]))
4193
transport = MemoryTransport()
4194
client = FakeClient(transport.base)
4195
client.add_expected_call(
4196
'Branch.get_stacked_on_url', ('quack/',),
4197
'error', ('NotStacked',))
4198
client.add_expected_call(
4199
'Branch.last_revision_info',
4201
'error', ('OutOfCoffee', 'low'))
4202
transport.mkdir('quack')
4203
transport = transport.clone('quack')
4204
branch = self.make_remote_branch(transport, client)
4205
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4206
self.assertFinished(client)
4208
def test_with_context(self):
4209
class OutOfTea(errors.BzrError):
4210
def __init__(self, branch, urgency):
4211
self.branch = branch
4212
self.urgency = urgency
4213
remote.error_translators.register("OutOfTea",
4214
lambda err, find, path: OutOfTea(err.error_args[0],
4216
transport = MemoryTransport()
4217
client = FakeClient(transport.base)
4218
client.add_expected_call(
4219
'Branch.get_stacked_on_url', ('quack/',),
4220
'error', ('NotStacked',))
4221
client.add_expected_call(
4222
'Branch.last_revision_info',
4224
'error', ('OutOfTea', 'low'))
4225
transport.mkdir('quack')
4226
transport = transport.clone('quack')
4227
branch = self.make_remote_branch(transport, client)
4228
self.assertRaises(OutOfTea, branch.last_revision_info)
4229
self.assertFinished(client)
4232
class TestRepositoryPack(TestRemoteRepository):
4234
def test_pack(self):
4235
transport_path = 'quack'
4236
repo, client = self.setup_fake_client_and_repository(transport_path)
4237
client.add_expected_call(
4238
'Repository.lock_write', ('quack/', ''),
4239
'success', ('ok', 'token'))
4240
client.add_expected_call(
4241
'Repository.pack', ('quack/', 'token', 'False'),
4242
'success', ('ok',), )
4243
client.add_expected_call(
4244
'Repository.unlock', ('quack/', 'token'),
4245
'success', ('ok', ))
4248
def test_pack_with_hint(self):
4249
transport_path = 'quack'
4250
repo, client = self.setup_fake_client_and_repository(transport_path)
4251
client.add_expected_call(
4252
'Repository.lock_write', ('quack/', ''),
4253
'success', ('ok', 'token'))
4254
client.add_expected_call(
4255
'Repository.pack', ('quack/', 'token', 'False'),
4256
'success', ('ok',), )
4257
client.add_expected_call(
4258
'Repository.unlock', ('quack/', 'token', 'False'),
4259
'success', ('ok', ))
4260
repo.pack(['hinta', 'hintb'])
4263
class TestRepositoryIterInventories(TestRemoteRepository):
4264
"""Test Repository.iter_inventories."""
4266
def _serialize_inv_delta(self, old_name, new_name, delta):
4267
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4268
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4270
def test_single_empty(self):
4271
transport_path = 'quack'
4272
repo, client = self.setup_fake_client_and_repository(transport_path)
4273
fmt = controldir.format_registry.get('2a')().repository_format
4275
stream = [('inventory-deltas', [
4276
versionedfile.FulltextContentFactory('somerevid', None, None,
4277
self._serialize_inv_delta('null:', 'somerevid', []))])]
4278
client.add_expected_call(
4279
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4280
'success', ('ok', ),
4281
_stream_to_byte_stream(stream, fmt))
4282
ret = list(repo.iter_inventories(["somerevid"]))
4283
self.assertLength(1, ret)
4285
self.assertEqual("somerevid", inv.revision_id)
4287
def test_empty(self):
4288
transport_path = 'quack'
4289
repo, client = self.setup_fake_client_and_repository(transport_path)
4290
ret = list(repo.iter_inventories([]))
4291
self.assertEqual(ret, [])
4293
def test_missing(self):
4294
transport_path = 'quack'
4295
repo, client = self.setup_fake_client_and_repository(transport_path)
4296
client.add_expected_call(
4297
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4298
'success', ('ok', ), iter([]))
4299
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(