53
59
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,
61
from ..repofmt import groupcompress_repo, knitpack_repo
62
from ..revision import (
66
from ..sixish import (
69
from ..smart import medium, request
70
from ..smart.client import _SmartClient
71
from ..smart.repository import (
72
SmartServerRepositoryGetParentMap,
73
SmartServerRepositoryGetStream_1_19,
74
_stream_to_byte_stream,
76
from ..symbol_versioning import deprecated_in
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
80
from .scenarios import load_tests_apply_scenarios
81
from ..transport.memory import MemoryTransport
82
from ..transport.remote import (
70
84
RemoteSSHTransport,
71
85
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 = [
89
load_tests = load_tests_apply_scenarios
92
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
96
{'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):
98
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
102
super(BasicRemoteObjectTests, self).setUp()
89
103
self.transport = self.get_transport()
90
104
# make a branch that can be opened over the smart transport
91
105
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
106
self.addCleanup(self.transport.disconnect)
97
108
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
109
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
110
self.assertIsInstance(b, BzrDir)
101
112
def test_open_remote_branch(self):
102
113
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
114
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
115
branch = b.open_branch()
105
116
self.assertIsInstance(branch, Branch)
480
484
self.assertEqual(None, result._branch_format)
481
485
self.assertFinished(client)
487
def test_unknown(self):
488
transport = self.get_transport('quack')
489
referenced = self.make_branch('referenced')
490
expected = referenced.bzrdir.cloning_metadir()
491
client = FakeClient(transport.base)
492
client.add_expected_call(
493
'BzrDir.cloning_metadir', ('quack/', 'False'),
494
'success', ('unknown', 'unknown', ('branch', ''))),
495
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
497
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
500
class TestBzrDirCheckoutMetaDir(TestRemote):
502
def test__get_checkout_format(self):
503
transport = MemoryTransport()
504
client = FakeClient(transport.base)
505
reference_bzrdir_format = controldir.format_registry.get('default')()
506
control_name = reference_bzrdir_format.network_name()
507
client.add_expected_call(
508
'BzrDir.checkout_metadir', ('quack/', ),
509
'success', (control_name, '', ''))
510
transport.mkdir('quack')
511
transport = transport.clone('quack')
512
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
514
result = a_bzrdir.checkout_metadir()
515
# We should have got a reference control dir with default branch and
516
# repository formats.
517
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
518
self.assertEqual(None, result._repository_format)
519
self.assertEqual(None, result._branch_format)
520
self.assertFinished(client)
522
def test_unknown_format(self):
523
transport = MemoryTransport()
524
client = FakeClient(transport.base)
525
client.add_expected_call(
526
'BzrDir.checkout_metadir', ('quack/',),
527
'success', ('dontknow', '', ''))
528
transport.mkdir('quack')
529
transport = transport.clone('quack')
530
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
532
self.assertRaises(errors.UnknownFormatError,
533
a_bzrdir.checkout_metadir)
534
self.assertFinished(client)
537
class TestBzrDirGetBranches(TestRemote):
539
def test_get_branches(self):
540
transport = MemoryTransport()
541
client = FakeClient(transport.base)
542
reference_bzrdir_format = controldir.format_registry.get('default')()
543
branch_name = reference_bzrdir_format.get_branch_format().network_name()
544
client.add_success_response_with_body(
546
"foo": ("branch", branch_name),
547
"": ("branch", branch_name)}), "success")
548
client.add_success_response(
549
'ok', '', 'no', 'no', 'no',
550
reference_bzrdir_format.repository_format.network_name())
551
client.add_error_response('NotStacked')
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
transport.mkdir('quack')
557
transport = transport.clone('quack')
558
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
560
result = a_bzrdir.get_branches()
561
self.assertEqual({"", "foo"}, set(result.keys()))
563
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
564
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
565
('call', 'Branch.get_stacked_on_url', ('quack/', )),
566
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
567
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
571
class TestBzrDirDestroyBranch(TestRemote):
573
def test_destroy_default(self):
574
transport = self.get_transport('quack')
575
referenced = self.make_branch('referenced')
576
client = FakeClient(transport.base)
577
client.add_expected_call(
578
'BzrDir.destroy_branch', ('quack/', ),
580
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
582
a_bzrdir.destroy_branch()
583
self.assertFinished(client)
586
class TestBzrDirHasWorkingTree(TestRemote):
588
def test_has_workingtree(self):
589
transport = self.get_transport('quack')
590
client = FakeClient(transport.base)
591
client.add_expected_call(
592
'BzrDir.has_workingtree', ('quack/',),
593
'success', ('yes',)),
594
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
596
self.assertTrue(a_bzrdir.has_workingtree())
597
self.assertFinished(client)
599
def test_no_workingtree(self):
600
transport = self.get_transport('quack')
601
client = FakeClient(transport.base)
602
client.add_expected_call(
603
'BzrDir.has_workingtree', ('quack/',),
605
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
607
self.assertFalse(a_bzrdir.has_workingtree())
608
self.assertFinished(client)
611
class TestBzrDirDestroyRepository(TestRemote):
613
def test_destroy_repository(self):
614
transport = self.get_transport('quack')
615
client = FakeClient(transport.base)
616
client.add_expected_call(
617
'BzrDir.destroy_repository', ('quack/',),
619
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
621
a_bzrdir.destroy_repository()
622
self.assertFinished(client)
484
625
class TestBzrDirOpen(TestRemote):
967
1140
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1143
class TestBranchBreakLock(RemoteBranchTestCase):
1145
def test_break_lock(self):
1146
transport_path = 'quack'
1147
transport = MemoryTransport()
1148
client = FakeClient(transport.base)
1149
client.add_expected_call(
1150
'Branch.get_stacked_on_url', ('quack/',),
1151
'error', ('NotStacked',))
1152
client.add_expected_call(
1153
'Branch.break_lock', ('quack/',),
1155
transport.mkdir('quack')
1156
transport = transport.clone('quack')
1157
branch = self.make_remote_branch(transport, client)
1159
self.assertFinished(client)
1162
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1164
def test_get_physical_lock_status_yes(self):
1165
transport = MemoryTransport()
1166
client = FakeClient(transport.base)
1167
client.add_expected_call(
1168
'Branch.get_stacked_on_url', ('quack/',),
1169
'error', ('NotStacked',))
1170
client.add_expected_call(
1171
'Branch.get_physical_lock_status', ('quack/',),
1172
'success', ('yes',))
1173
transport.mkdir('quack')
1174
transport = transport.clone('quack')
1175
branch = self.make_remote_branch(transport, client)
1176
result = branch.get_physical_lock_status()
1177
self.assertFinished(client)
1178
self.assertEqual(True, result)
1180
def test_get_physical_lock_status_no(self):
1181
transport = MemoryTransport()
1182
client = FakeClient(transport.base)
1183
client.add_expected_call(
1184
'Branch.get_stacked_on_url', ('quack/',),
1185
'error', ('NotStacked',))
1186
client.add_expected_call(
1187
'Branch.get_physical_lock_status', ('quack/',),
1189
transport.mkdir('quack')
1190
transport = transport.clone('quack')
1191
branch = self.make_remote_branch(transport, client)
1192
result = branch.get_physical_lock_status()
1193
self.assertFinished(client)
1194
self.assertEqual(False, result)
970
1197
class TestBranchGetParent(RemoteBranchTestCase):
972
1199
def test_no_parent(self):
1143
1370
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1373
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1375
def test_uses_last_revision_info_and_tags_by_default(self):
1376
transport = MemoryTransport()
1377
client = FakeClient(transport.base)
1378
client.add_expected_call(
1379
'Branch.get_stacked_on_url', ('quack/',),
1380
'error', ('NotStacked',))
1381
client.add_expected_call(
1382
'Branch.last_revision_info', ('quack/',),
1383
'success', ('ok', '1', 'rev-tip'))
1384
client.add_expected_call(
1385
'Branch.get_config_file', ('quack/',),
1386
'success', ('ok',), '')
1387
transport.mkdir('quack')
1388
transport = transport.clone('quack')
1389
branch = self.make_remote_branch(transport, client)
1390
result = branch.heads_to_fetch()
1391
self.assertFinished(client)
1392
self.assertEqual(({'rev-tip'}, set()), result)
1394
def test_uses_last_revision_info_and_tags_when_set(self):
1395
transport = MemoryTransport()
1396
client = FakeClient(transport.base)
1397
client.add_expected_call(
1398
'Branch.get_stacked_on_url', ('quack/',),
1399
'error', ('NotStacked',))
1400
client.add_expected_call(
1401
'Branch.last_revision_info', ('quack/',),
1402
'success', ('ok', '1', 'rev-tip'))
1403
client.add_expected_call(
1404
'Branch.get_config_file', ('quack/',),
1405
'success', ('ok',), 'branch.fetch_tags = True')
1406
# XXX: this will break if the default format's serialization of tags
1407
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1408
client.add_expected_call(
1409
'Branch.get_tags_bytes', ('quack/',),
1410
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1411
transport.mkdir('quack')
1412
transport = transport.clone('quack')
1413
branch = self.make_remote_branch(transport, client)
1414
result = branch.heads_to_fetch()
1415
self.assertFinished(client)
1417
({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
1419
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1420
transport = MemoryTransport()
1421
client = FakeClient(transport.base)
1422
client.add_expected_call(
1423
'Branch.get_stacked_on_url', ('quack/',),
1424
'error', ('NotStacked',))
1425
client.add_expected_call(
1426
'Branch.heads_to_fetch', ('quack/',),
1427
'success', (['tip'], ['tagged-1', 'tagged-2']))
1428
transport.mkdir('quack')
1429
transport = transport.clone('quack')
1430
branch = self.make_remote_branch(transport, client)
1431
branch._format._use_default_local_heads_to_fetch = lambda: False
1432
result = branch.heads_to_fetch()
1433
self.assertFinished(client)
1434
self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
1436
def make_branch_with_tags(self):
1437
self.setup_smart_server_with_call_log()
1438
# Make a branch with a single revision.
1439
builder = self.make_branch_builder('foo')
1440
builder.start_series()
1441
builder.build_snapshot('tip', None, [
1442
('add', ('', 'root-id', 'directory', ''))])
1443
builder.finish_series()
1444
branch = builder.get_branch()
1445
# Add two tags to that branch
1446
branch.tags.set_tag('tag-1', 'rev-1')
1447
branch.tags.set_tag('tag-2', 'rev-2')
1450
def test_backwards_compatible(self):
1451
br = self.make_branch_with_tags()
1452
br.get_config_stack().set('branch.fetch_tags', True)
1453
self.addCleanup(br.lock_read().unlock)
1454
# Disable the heads_to_fetch verb
1455
verb = 'Branch.heads_to_fetch'
1456
self.disable_verb(verb)
1457
self.reset_smart_call_log()
1458
result = br.heads_to_fetch()
1459
self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
1461
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1462
[call.call.method for call in self.hpss_calls])
1464
def test_backwards_compatible_no_tags(self):
1465
br = self.make_branch_with_tags()
1466
br.get_config_stack().set('branch.fetch_tags', False)
1467
self.addCleanup(br.lock_read().unlock)
1468
# Disable the heads_to_fetch verb
1469
verb = 'Branch.heads_to_fetch'
1470
self.disable_verb(verb)
1471
self.reset_smart_call_log()
1472
result = br.heads_to_fetch()
1473
self.assertEqual(({'tip'}, set()), result)
1475
['Branch.last_revision_info'],
1476
[call.call.method for call in self.hpss_calls])
1146
1479
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1481
def test_empty_branch(self):
1661
2014
self.addCleanup(branch.unlock)
1662
2015
self.reset_smart_call_log()
1663
2016
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2017
self.assertLength(11, self.hpss_calls)
1665
2018
self.assertEqual('value', branch._get_config().get_option('name'))
2020
def test_backwards_compat_set_option_with_dict(self):
2021
self.setup_smart_server_with_call_log()
2022
branch = self.make_branch('.')
2023
verb = 'Branch.set_config_option_dict'
2024
self.disable_verb(verb)
2026
self.addCleanup(branch.unlock)
2027
self.reset_smart_call_log()
2028
config = branch._get_config()
2029
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2030
config.set_option(value_dict, 'name')
2031
self.assertLength(11, self.hpss_calls)
2032
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2035
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2037
def test_get_branch_conf(self):
2038
# in an empty branch we decode the response properly
2039
client = FakeClient()
2040
client.add_expected_call(
2041
'Branch.get_stacked_on_url', ('memory:///',),
2042
'error', ('NotStacked',),)
2043
client.add_success_response_with_body('# config file body', 'ok')
2044
transport = MemoryTransport()
2045
branch = self.make_remote_branch(transport, client)
2046
config = branch.get_config_stack()
2048
config.get("log_format")
2050
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2051
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2054
def test_set_branch_conf(self):
2055
client = FakeClient()
2056
client.add_expected_call(
2057
'Branch.get_stacked_on_url', ('memory:///',),
2058
'error', ('NotStacked',),)
2059
client.add_expected_call(
2060
'Branch.lock_write', ('memory:///', '', ''),
2061
'success', ('ok', 'branch token', 'repo token'))
2062
client.add_expected_call(
2063
'Branch.get_config_file', ('memory:///', ),
2064
'success', ('ok', ), "# line 1\n")
2065
client.add_expected_call(
2066
'Branch.get_config_file', ('memory:///', ),
2067
'success', ('ok', ), "# line 1\n")
2068
client.add_expected_call(
2069
'Branch.put_config_file', ('memory:///', 'branch token',
2072
client.add_expected_call(
2073
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2075
transport = MemoryTransport()
2076
branch = self.make_remote_branch(transport, client)
2078
config = branch.get_config_stack()
2079
config.set('email', 'The Dude <lebowski@example.com>')
2081
self.assertFinished(client)
2083
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2084
('call', 'Branch.lock_write', ('memory:///', '', '')),
2085
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2086
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2087
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2088
('memory:///', 'branch token', 'repo token'),
2089
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2090
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2094
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2109
self.assertFinished(client)
2112
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2114
def test_simple(self):
2115
transport = MemoryTransport()
2116
client = FakeClient(transport.base)
2117
client.add_expected_call(
2118
'Branch.get_stacked_on_url', ('quack/',),
2119
'error', ('NotStacked',),)
2120
client.add_expected_call(
2121
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2122
'success', ('ok', '0',),)
2123
client.add_expected_call(
2124
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2125
'error', ('NoSuchRevision', 'unknown',),)
2126
transport.mkdir('quack')
2127
transport = transport.clone('quack')
2128
branch = self.make_remote_branch(transport, client)
2129
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2130
self.assertRaises(errors.NoSuchRevision,
2131
branch.revision_id_to_revno, 'unknown')
2132
self.assertFinished(client)
2134
def test_dotted(self):
2135
transport = MemoryTransport()
2136
client = FakeClient(transport.base)
2137
client.add_expected_call(
2138
'Branch.get_stacked_on_url', ('quack/',),
2139
'error', ('NotStacked',),)
2140
client.add_expected_call(
2141
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2142
'success', ('ok', '0',),)
2143
client.add_expected_call(
2144
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2145
'error', ('NoSuchRevision', 'unknown',),)
2146
transport.mkdir('quack')
2147
transport = transport.clone('quack')
2148
branch = self.make_remote_branch(transport, client)
2149
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2150
self.assertRaises(errors.NoSuchRevision,
2151
branch.revision_id_to_dotted_revno, 'unknown')
2152
self.assertFinished(client)
2154
def test_dotted_no_smart_verb(self):
2155
self.setup_smart_server_with_call_log()
2156
branch = self.make_branch('.')
2157
self.disable_verb('Branch.revision_id_to_revno')
2158
self.reset_smart_call_log()
2159
self.assertEqual((0, ),
2160
branch.revision_id_to_dotted_revno('null:'))
2161
self.assertLength(8, self.hpss_calls)
1686
2164
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2166
def test__get_config(self):
2409
class TestRepositoryBreakLock(TestRemoteRepository):
2411
def test_break_lock(self):
2412
transport_path = 'quack'
2413
repo, client = self.setup_fake_client_and_repository(transport_path)
2414
client.add_success_response('ok')
2417
[('call', 'Repository.break_lock', ('quack/',))],
2421
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2423
def test_get_serializer_format(self):
2424
transport_path = 'hill'
2425
repo, client = self.setup_fake_client_and_repository(transport_path)
2426
client.add_success_response('ok', '7')
2427
self.assertEqual('7', repo.get_serializer_format())
2429
[('call', 'VersionedFileRepository.get_serializer_format',
2434
class TestRepositoryReconcile(TestRemoteRepository):
2436
def test_reconcile(self):
2437
transport_path = 'hill'
2438
repo, client = self.setup_fake_client_and_repository(transport_path)
2439
body = ("garbage_inventories: 2\n"
2440
"inconsistent_parents: 3\n")
2441
client.add_expected_call(
2442
'Repository.lock_write', ('hill/', ''),
2443
'success', ('ok', 'a token'))
2444
client.add_success_response_with_body(body, 'ok')
2445
reconciler = repo.reconcile()
2447
[('call', 'Repository.lock_write', ('hill/', '')),
2448
('call_expecting_body', 'Repository.reconcile',
2449
('hill/', 'a token'))],
2451
self.assertEqual(2, reconciler.garbage_inventories)
2452
self.assertEqual(3, reconciler.inconsistent_parents)
2455
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2457
def test_text(self):
2458
# ('ok',), body with signature text
2459
transport_path = 'quack'
2460
repo, client = self.setup_fake_client_and_repository(transport_path)
2461
client.add_success_response_with_body(
2463
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2465
[('call_expecting_body', 'Repository.get_revision_signature_text',
2466
('quack/', 'revid'))],
2469
def test_no_signature(self):
2470
transport_path = 'quick'
2471
repo, client = self.setup_fake_client_and_repository(transport_path)
2472
client.add_error_response('nosuchrevision', 'unknown')
2473
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2476
[('call_expecting_body', 'Repository.get_revision_signature_text',
2477
('quick/', 'unknown'))],
1906
2481
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2483
def test_get_graph(self):
3072
class TestRepositoryWriteGroups(TestRemoteRepository):
3074
def test_start_write_group(self):
3075
transport_path = 'quack'
3076
repo, client = self.setup_fake_client_and_repository(transport_path)
3077
client.add_expected_call(
3078
'Repository.lock_write', ('quack/', ''),
3079
'success', ('ok', 'a token'))
3080
client.add_expected_call(
3081
'Repository.start_write_group', ('quack/', 'a token'),
3082
'success', ('ok', ('token1', )))
3084
repo.start_write_group()
3086
def test_start_write_group_unsuspendable(self):
3087
# Some repositories do not support suspending write
3088
# groups. For those, fall back to the "real" repository.
3089
transport_path = 'quack'
3090
repo, client = self.setup_fake_client_and_repository(transport_path)
3091
def stub_ensure_real():
3092
client._calls.append(('_ensure_real',))
3093
repo._real_repository = _StubRealPackRepository(client._calls)
3094
repo._ensure_real = stub_ensure_real
3095
client.add_expected_call(
3096
'Repository.lock_write', ('quack/', ''),
3097
'success', ('ok', 'a token'))
3098
client.add_expected_call(
3099
'Repository.start_write_group', ('quack/', 'a token'),
3100
'error', ('UnsuspendableWriteGroup',))
3102
repo.start_write_group()
3103
self.assertEqual(client._calls[-2:], [
3105
('start_write_group',)])
3107
def test_commit_write_group(self):
3108
transport_path = 'quack'
3109
repo, client = self.setup_fake_client_and_repository(transport_path)
3110
client.add_expected_call(
3111
'Repository.lock_write', ('quack/', ''),
3112
'success', ('ok', 'a token'))
3113
client.add_expected_call(
3114
'Repository.start_write_group', ('quack/', 'a token'),
3115
'success', ('ok', ['token1']))
3116
client.add_expected_call(
3117
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3120
repo.start_write_group()
3121
repo.commit_write_group()
3123
def test_abort_write_group(self):
3124
transport_path = 'quack'
3125
repo, client = self.setup_fake_client_and_repository(transport_path)
3126
client.add_expected_call(
3127
'Repository.lock_write', ('quack/', ''),
3128
'success', ('ok', 'a token'))
3129
client.add_expected_call(
3130
'Repository.start_write_group', ('quack/', 'a token'),
3131
'success', ('ok', ['token1']))
3132
client.add_expected_call(
3133
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3136
repo.start_write_group()
3137
repo.abort_write_group(False)
3139
def test_suspend_write_group(self):
3140
transport_path = 'quack'
3141
repo, client = self.setup_fake_client_and_repository(transport_path)
3142
self.assertEqual([], repo.suspend_write_group())
3144
def test_resume_write_group(self):
3145
transport_path = 'quack'
3146
repo, client = self.setup_fake_client_and_repository(transport_path)
3147
client.add_expected_call(
3148
'Repository.lock_write', ('quack/', ''),
3149
'success', ('ok', 'a token'))
3150
client.add_expected_call(
3151
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3154
repo.resume_write_group(['token1'])
2329
3157
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3159
def test_backwards_compat(self):
2895
3777
expected_error = errors.PermissionDenied(path, extra)
2896
3778
self.assertEqual(expected_error, translated_error)
3780
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3782
def test_NoSuchFile_context_path(self):
3783
local_path = "local path"
3784
translated_error = self.translateTuple(('ReadError', "remote path"),
3786
expected_error = errors.ReadError(local_path)
3787
self.assertEqual(expected_error, translated_error)
3789
def test_NoSuchFile_without_context(self):
3790
remote_path = "remote path"
3791
translated_error = self.translateTuple(('ReadError', remote_path))
3792
expected_error = errors.ReadError(remote_path)
3793
self.assertEqual(expected_error, translated_error)
3795
def test_ReadOnlyError(self):
3796
translated_error = self.translateTuple(('ReadOnlyError',))
3797
expected_error = errors.TransportNotPossible("readonly transport")
3798
self.assertEqual(expected_error, translated_error)
3800
def test_MemoryError(self):
3801
translated_error = self.translateTuple(('MemoryError',))
3802
self.assertStartsWith(str(translated_error),
3803
"remote server out of memory")
3805
def test_generic_IndexError_no_classname(self):
3806
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3807
translated_error = self.translateErrorFromSmartServer(err)
3808
expected_error = errors.UnknownErrorFromSmartServer(err)
3809
self.assertEqual(expected_error, translated_error)
3811
# GZ 2011-03-02: TODO test generic non-ascii error string
3813
def test_generic_KeyError(self):
3814
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3815
translated_error = self.translateErrorFromSmartServer(err)
3816
expected_error = errors.UnknownErrorFromSmartServer(err)
3817
self.assertEqual(expected_error, translated_error)
2899
3820
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3821
"""Unit tests for breezy.remote._translate_error's robustness.
2902
3823
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3824
translate successfully. This class about how _translate_err behaves when
3143
4066
def test_copy_content_into_avoids_revision_history(self):
3144
4067
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4068
builder = self.make_branch_builder('remote')
4069
builder.build_commit(message="Commit.")
3147
4070
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4071
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4072
local.repository.fetch(remote_branch.repository)
3150
4073
self.hpss_calls = []
3151
4074
remote_branch.copy_content_into(local)
3152
4075
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4077
def test_fetch_everything_needs_just_one_call(self):
4078
local = self.make_branch('local')
4079
builder = self.make_branch_builder('remote')
4080
builder.build_commit(message="Commit.")
4081
remote_branch_url = self.smart_server.get_url() + 'remote'
4082
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4083
self.hpss_calls = []
4084
local.repository.fetch(
4085
remote_branch.repository,
4086
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4087
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4089
def override_verb(self, verb_name, verb):
4090
request_handlers = request.request_handlers
4091
orig_verb = request_handlers.get(verb_name)
4092
orig_info = request_handlers.get_info(verb_name)
4093
request_handlers.register(verb_name, verb, override_existing=True)
4094
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4095
override_existing=True, info=orig_info)
4097
def test_fetch_everything_backwards_compat(self):
4098
"""Can fetch with EverythingResult even with pre 2.4 servers.
4100
Pre-2.4 do not support 'everything' searches with the
4101
Repository.get_stream_1.19 verb.
4104
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4105
"""A version of the Repository.get_stream_1.19 verb patched to
4106
reject 'everything' searches the way 2.3 and earlier do.
4108
def recreate_search(self, repository, search_bytes,
4109
discard_excess=False):
4110
verb_log.append(search_bytes.split('\n', 1)[0])
4111
if search_bytes == 'everything':
4113
request.FailedSmartServerResponse(('BadSearch',)))
4114
return super(OldGetStreamVerb,
4115
self).recreate_search(repository, search_bytes,
4116
discard_excess=discard_excess)
4117
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4118
local = self.make_branch('local')
4119
builder = self.make_branch_builder('remote')
4120
builder.build_commit(message="Commit.")
4121
remote_branch_url = self.smart_server.get_url() + 'remote'
4122
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4123
self.hpss_calls = []
4124
local.repository.fetch(
4125
remote_branch.repository,
4126
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4127
# make sure the overridden verb was used
4128
self.assertLength(1, verb_log)
4129
# more than one HPSS call is needed, but because it's a VFS callback
4130
# its hard to predict exactly how many.
4131
self.assertTrue(len(self.hpss_calls) > 1)
4134
class TestUpdateBoundBranchWithModifiedBoundLocation(
4135
tests.TestCaseWithTransport):
4136
"""Ensure correct handling of bound_location modifications.
4138
This is tested against a smart server as http://pad.lv/786980 was about a
4139
ReadOnlyError (write attempt during a read-only transaction) which can only
4140
happen in this context.
4144
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4145
self.transport_server = test_server.SmartTCPServer_for_testing
4147
def make_master_and_checkout(self, master_name, checkout_name):
4148
# Create the master branch and its associated checkout
4149
self.master = self.make_branch_and_tree(master_name)
4150
self.checkout = self.master.branch.create_checkout(checkout_name)
4151
# Modify the master branch so there is something to update
4152
self.master.commit('add stuff')
4153
self.last_revid = self.master.commit('even more stuff')
4154
self.bound_location = self.checkout.branch.get_bound_location()
4156
def assertUpdateSucceeds(self, new_location):
4157
self.checkout.branch.set_bound_location(new_location)
4158
self.checkout.update()
4159
self.assertEqual(self.last_revid, self.checkout.last_revision())
4161
def test_without_final_slash(self):
4162
self.make_master_and_checkout('master', 'checkout')
4163
# For unclear reasons some users have a bound_location without a final
4164
# '/', simulate that by forcing such a value
4165
self.assertEndsWith(self.bound_location, '/')
4166
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4168
def test_plus_sign(self):
4169
self.make_master_and_checkout('+master', 'checkout')
4170
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4172
def test_tilda(self):
4173
# Embed ~ in the middle of the path just to avoid any $HOME
4175
self.make_master_and_checkout('mas~ter', 'checkout')
4176
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4179
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4181
def test_no_context(self):
4182
class OutOfCoffee(errors.BzrError):
4183
"""A dummy exception for testing."""
4185
def __init__(self, urgency):
4186
self.urgency = urgency
4187
remote.no_context_error_translators.register("OutOfCoffee",
4188
lambda err: OutOfCoffee(err.error_args[0]))
4189
transport = MemoryTransport()
4190
client = FakeClient(transport.base)
4191
client.add_expected_call(
4192
'Branch.get_stacked_on_url', ('quack/',),
4193
'error', ('NotStacked',))
4194
client.add_expected_call(
4195
'Branch.last_revision_info',
4197
'error', ('OutOfCoffee', 'low'))
4198
transport.mkdir('quack')
4199
transport = transport.clone('quack')
4200
branch = self.make_remote_branch(transport, client)
4201
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4202
self.assertFinished(client)
4204
def test_with_context(self):
4205
class OutOfTea(errors.BzrError):
4206
def __init__(self, branch, urgency):
4207
self.branch = branch
4208
self.urgency = urgency
4209
remote.error_translators.register("OutOfTea",
4210
lambda err, find, path: OutOfTea(err.error_args[0],
4212
transport = MemoryTransport()
4213
client = FakeClient(transport.base)
4214
client.add_expected_call(
4215
'Branch.get_stacked_on_url', ('quack/',),
4216
'error', ('NotStacked',))
4217
client.add_expected_call(
4218
'Branch.last_revision_info',
4220
'error', ('OutOfTea', 'low'))
4221
transport.mkdir('quack')
4222
transport = transport.clone('quack')
4223
branch = self.make_remote_branch(transport, client)
4224
self.assertRaises(OutOfTea, branch.last_revision_info)
4225
self.assertFinished(client)
4228
class TestRepositoryPack(TestRemoteRepository):
4230
def test_pack(self):
4231
transport_path = 'quack'
4232
repo, client = self.setup_fake_client_and_repository(transport_path)
4233
client.add_expected_call(
4234
'Repository.lock_write', ('quack/', ''),
4235
'success', ('ok', 'token'))
4236
client.add_expected_call(
4237
'Repository.pack', ('quack/', 'token', 'False'),
4238
'success', ('ok',), )
4239
client.add_expected_call(
4240
'Repository.unlock', ('quack/', 'token'),
4241
'success', ('ok', ))
4244
def test_pack_with_hint(self):
4245
transport_path = 'quack'
4246
repo, client = self.setup_fake_client_and_repository(transport_path)
4247
client.add_expected_call(
4248
'Repository.lock_write', ('quack/', ''),
4249
'success', ('ok', 'token'))
4250
client.add_expected_call(
4251
'Repository.pack', ('quack/', 'token', 'False'),
4252
'success', ('ok',), )
4253
client.add_expected_call(
4254
'Repository.unlock', ('quack/', 'token', 'False'),
4255
'success', ('ok', ))
4256
repo.pack(['hinta', 'hintb'])
4259
class TestRepositoryIterInventories(TestRemoteRepository):
4260
"""Test Repository.iter_inventories."""
4262
def _serialize_inv_delta(self, old_name, new_name, delta):
4263
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4264
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4266
def test_single_empty(self):
4267
transport_path = 'quack'
4268
repo, client = self.setup_fake_client_and_repository(transport_path)
4269
fmt = controldir.format_registry.get('2a')().repository_format
4271
stream = [('inventory-deltas', [
4272
versionedfile.FulltextContentFactory('somerevid', None, None,
4273
self._serialize_inv_delta('null:', 'somerevid', []))])]
4274
client.add_expected_call(
4275
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4276
'success', ('ok', ),
4277
_stream_to_byte_stream(stream, fmt))
4278
ret = list(repo.iter_inventories(["somerevid"]))
4279
self.assertLength(1, ret)
4281
self.assertEqual("somerevid", inv.revision_id)
4283
def test_empty(self):
4284
transport_path = 'quack'
4285
repo, client = self.setup_fake_client_and_repository(transport_path)
4286
ret = list(repo.iter_inventories([]))
4287
self.assertEqual(ret, [])
4289
def test_missing(self):
4290
transport_path = 'quack'
4291
repo, client = self.setup_fake_client_and_repository(transport_path)
4292
client.add_expected_call(
4293
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4294
'success', ('ok', ), iter([]))
4295
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(