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,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
79
from .scenarios import load_tests_apply_scenarios
80
from ..transport.memory import MemoryTransport
81
from ..transport.remote import (
70
83
RemoteSSHTransport,
71
84
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 = [
88
load_tests = load_tests_apply_scenarios
91
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
95
{'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):
97
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
101
super(BasicRemoteObjectTests, self).setUp()
89
102
self.transport = self.get_transport()
90
103
# make a branch that can be opened over the smart transport
91
104
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
105
self.addCleanup(self.transport.disconnect)
97
107
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
108
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
109
self.assertIsInstance(b, BzrDir)
101
111
def test_open_remote_branch(self):
102
112
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
113
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
114
branch = b.open_branch()
105
115
self.assertIsInstance(branch, Branch)
480
483
self.assertEqual(None, result._branch_format)
481
484
self.assertFinished(client)
486
def test_unknown(self):
487
transport = self.get_transport('quack')
488
referenced = self.make_branch('referenced')
489
expected = referenced.bzrdir.cloning_metadir()
490
client = FakeClient(transport.base)
491
client.add_expected_call(
492
'BzrDir.cloning_metadir', ('quack/', 'False'),
493
'success', ('unknown', 'unknown', ('branch', ''))),
494
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
496
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
499
class TestBzrDirCheckoutMetaDir(TestRemote):
501
def test__get_checkout_format(self):
502
transport = MemoryTransport()
503
client = FakeClient(transport.base)
504
reference_bzrdir_format = controldir.format_registry.get('default')()
505
control_name = reference_bzrdir_format.network_name()
506
client.add_expected_call(
507
'BzrDir.checkout_metadir', ('quack/', ),
508
'success', (control_name, '', ''))
509
transport.mkdir('quack')
510
transport = transport.clone('quack')
511
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
513
result = a_bzrdir.checkout_metadir()
514
# We should have got a reference control dir with default branch and
515
# repository formats.
516
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
517
self.assertEqual(None, result._repository_format)
518
self.assertEqual(None, result._branch_format)
519
self.assertFinished(client)
521
def test_unknown_format(self):
522
transport = MemoryTransport()
523
client = FakeClient(transport.base)
524
client.add_expected_call(
525
'BzrDir.checkout_metadir', ('quack/',),
526
'success', ('dontknow', '', ''))
527
transport.mkdir('quack')
528
transport = transport.clone('quack')
529
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
531
self.assertRaises(errors.UnknownFormatError,
532
a_bzrdir.checkout_metadir)
533
self.assertFinished(client)
536
class TestBzrDirGetBranches(TestRemote):
538
def test_get_branches(self):
539
transport = MemoryTransport()
540
client = FakeClient(transport.base)
541
reference_bzrdir_format = controldir.format_registry.get('default')()
542
branch_name = reference_bzrdir_format.get_branch_format().network_name()
543
client.add_success_response_with_body(
545
"foo": ("branch", branch_name),
546
"": ("branch", branch_name)}), "success")
547
client.add_success_response(
548
'ok', '', 'no', 'no', 'no',
549
reference_bzrdir_format.repository_format.network_name())
550
client.add_error_response('NotStacked')
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
transport.mkdir('quack')
556
transport = transport.clone('quack')
557
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
559
result = a_bzrdir.get_branches()
560
self.assertEqual({"", "foo"}, set(result.keys()))
562
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
563
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
564
('call', 'Branch.get_stacked_on_url', ('quack/', )),
565
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
566
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
570
class TestBzrDirDestroyBranch(TestRemote):
572
def test_destroy_default(self):
573
transport = self.get_transport('quack')
574
referenced = self.make_branch('referenced')
575
client = FakeClient(transport.base)
576
client.add_expected_call(
577
'BzrDir.destroy_branch', ('quack/', ),
579
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
581
a_bzrdir.destroy_branch()
582
self.assertFinished(client)
585
class TestBzrDirHasWorkingTree(TestRemote):
587
def test_has_workingtree(self):
588
transport = self.get_transport('quack')
589
client = FakeClient(transport.base)
590
client.add_expected_call(
591
'BzrDir.has_workingtree', ('quack/',),
592
'success', ('yes',)),
593
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
595
self.assertTrue(a_bzrdir.has_workingtree())
596
self.assertFinished(client)
598
def test_no_workingtree(self):
599
transport = self.get_transport('quack')
600
client = FakeClient(transport.base)
601
client.add_expected_call(
602
'BzrDir.has_workingtree', ('quack/',),
604
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
606
self.assertFalse(a_bzrdir.has_workingtree())
607
self.assertFinished(client)
610
class TestBzrDirDestroyRepository(TestRemote):
612
def test_destroy_repository(self):
613
transport = self.get_transport('quack')
614
client = FakeClient(transport.base)
615
client.add_expected_call(
616
'BzrDir.destroy_repository', ('quack/',),
618
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
620
a_bzrdir.destroy_repository()
621
self.assertFinished(client)
484
624
class TestBzrDirOpen(TestRemote):
967
1139
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1142
class TestBranchBreakLock(RemoteBranchTestCase):
1144
def test_break_lock(self):
1145
transport_path = 'quack'
1146
transport = MemoryTransport()
1147
client = FakeClient(transport.base)
1148
client.add_expected_call(
1149
'Branch.get_stacked_on_url', ('quack/',),
1150
'error', ('NotStacked',))
1151
client.add_expected_call(
1152
'Branch.break_lock', ('quack/',),
1154
transport.mkdir('quack')
1155
transport = transport.clone('quack')
1156
branch = self.make_remote_branch(transport, client)
1158
self.assertFinished(client)
1161
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1163
def test_get_physical_lock_status_yes(self):
1164
transport = MemoryTransport()
1165
client = FakeClient(transport.base)
1166
client.add_expected_call(
1167
'Branch.get_stacked_on_url', ('quack/',),
1168
'error', ('NotStacked',))
1169
client.add_expected_call(
1170
'Branch.get_physical_lock_status', ('quack/',),
1171
'success', ('yes',))
1172
transport.mkdir('quack')
1173
transport = transport.clone('quack')
1174
branch = self.make_remote_branch(transport, client)
1175
result = branch.get_physical_lock_status()
1176
self.assertFinished(client)
1177
self.assertEqual(True, result)
1179
def test_get_physical_lock_status_no(self):
1180
transport = MemoryTransport()
1181
client = FakeClient(transport.base)
1182
client.add_expected_call(
1183
'Branch.get_stacked_on_url', ('quack/',),
1184
'error', ('NotStacked',))
1185
client.add_expected_call(
1186
'Branch.get_physical_lock_status', ('quack/',),
1188
transport.mkdir('quack')
1189
transport = transport.clone('quack')
1190
branch = self.make_remote_branch(transport, client)
1191
result = branch.get_physical_lock_status()
1192
self.assertFinished(client)
1193
self.assertEqual(False, result)
970
1196
class TestBranchGetParent(RemoteBranchTestCase):
972
1198
def test_no_parent(self):
1143
1369
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1372
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1374
def test_uses_last_revision_info_and_tags_by_default(self):
1375
transport = MemoryTransport()
1376
client = FakeClient(transport.base)
1377
client.add_expected_call(
1378
'Branch.get_stacked_on_url', ('quack/',),
1379
'error', ('NotStacked',))
1380
client.add_expected_call(
1381
'Branch.last_revision_info', ('quack/',),
1382
'success', ('ok', '1', 'rev-tip'))
1383
client.add_expected_call(
1384
'Branch.get_config_file', ('quack/',),
1385
'success', ('ok',), '')
1386
transport.mkdir('quack')
1387
transport = transport.clone('quack')
1388
branch = self.make_remote_branch(transport, client)
1389
result = branch.heads_to_fetch()
1390
self.assertFinished(client)
1391
self.assertEqual(({'rev-tip'}, set()), result)
1393
def test_uses_last_revision_info_and_tags_when_set(self):
1394
transport = MemoryTransport()
1395
client = FakeClient(transport.base)
1396
client.add_expected_call(
1397
'Branch.get_stacked_on_url', ('quack/',),
1398
'error', ('NotStacked',))
1399
client.add_expected_call(
1400
'Branch.last_revision_info', ('quack/',),
1401
'success', ('ok', '1', 'rev-tip'))
1402
client.add_expected_call(
1403
'Branch.get_config_file', ('quack/',),
1404
'success', ('ok',), 'branch.fetch_tags = True')
1405
# XXX: this will break if the default format's serialization of tags
1406
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1407
client.add_expected_call(
1408
'Branch.get_tags_bytes', ('quack/',),
1409
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1410
transport.mkdir('quack')
1411
transport = transport.clone('quack')
1412
branch = self.make_remote_branch(transport, client)
1413
result = branch.heads_to_fetch()
1414
self.assertFinished(client)
1416
({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
1418
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1419
transport = MemoryTransport()
1420
client = FakeClient(transport.base)
1421
client.add_expected_call(
1422
'Branch.get_stacked_on_url', ('quack/',),
1423
'error', ('NotStacked',))
1424
client.add_expected_call(
1425
'Branch.heads_to_fetch', ('quack/',),
1426
'success', (['tip'], ['tagged-1', 'tagged-2']))
1427
transport.mkdir('quack')
1428
transport = transport.clone('quack')
1429
branch = self.make_remote_branch(transport, client)
1430
branch._format._use_default_local_heads_to_fetch = lambda: False
1431
result = branch.heads_to_fetch()
1432
self.assertFinished(client)
1433
self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
1435
def make_branch_with_tags(self):
1436
self.setup_smart_server_with_call_log()
1437
# Make a branch with a single revision.
1438
builder = self.make_branch_builder('foo')
1439
builder.start_series()
1440
builder.build_snapshot('tip', None, [
1441
('add', ('', 'root-id', 'directory', ''))])
1442
builder.finish_series()
1443
branch = builder.get_branch()
1444
# Add two tags to that branch
1445
branch.tags.set_tag('tag-1', 'rev-1')
1446
branch.tags.set_tag('tag-2', 'rev-2')
1449
def test_backwards_compatible(self):
1450
br = self.make_branch_with_tags()
1451
br.get_config_stack().set('branch.fetch_tags', True)
1452
self.addCleanup(br.lock_read().unlock)
1453
# Disable the heads_to_fetch verb
1454
verb = 'Branch.heads_to_fetch'
1455
self.disable_verb(verb)
1456
self.reset_smart_call_log()
1457
result = br.heads_to_fetch()
1458
self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
1460
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1461
[call.call.method for call in self.hpss_calls])
1463
def test_backwards_compatible_no_tags(self):
1464
br = self.make_branch_with_tags()
1465
br.get_config_stack().set('branch.fetch_tags', False)
1466
self.addCleanup(br.lock_read().unlock)
1467
# Disable the heads_to_fetch verb
1468
verb = 'Branch.heads_to_fetch'
1469
self.disable_verb(verb)
1470
self.reset_smart_call_log()
1471
result = br.heads_to_fetch()
1472
self.assertEqual(({'tip'}, set()), result)
1474
['Branch.last_revision_info'],
1475
[call.call.method for call in self.hpss_calls])
1146
1478
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1480
def test_empty_branch(self):
1661
2013
self.addCleanup(branch.unlock)
1662
2014
self.reset_smart_call_log()
1663
2015
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2016
self.assertLength(11, self.hpss_calls)
1665
2017
self.assertEqual('value', branch._get_config().get_option('name'))
2019
def test_backwards_compat_set_option_with_dict(self):
2020
self.setup_smart_server_with_call_log()
2021
branch = self.make_branch('.')
2022
verb = 'Branch.set_config_option_dict'
2023
self.disable_verb(verb)
2025
self.addCleanup(branch.unlock)
2026
self.reset_smart_call_log()
2027
config = branch._get_config()
2028
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2029
config.set_option(value_dict, 'name')
2030
self.assertLength(11, self.hpss_calls)
2031
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2034
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2036
def test_get_branch_conf(self):
2037
# in an empty branch we decode the response properly
2038
client = FakeClient()
2039
client.add_expected_call(
2040
'Branch.get_stacked_on_url', ('memory:///',),
2041
'error', ('NotStacked',),)
2042
client.add_success_response_with_body('# config file body', 'ok')
2043
transport = MemoryTransport()
2044
branch = self.make_remote_branch(transport, client)
2045
config = branch.get_config_stack()
2047
config.get("log_format")
2049
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2050
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2053
def test_set_branch_conf(self):
2054
client = FakeClient()
2055
client.add_expected_call(
2056
'Branch.get_stacked_on_url', ('memory:///',),
2057
'error', ('NotStacked',),)
2058
client.add_expected_call(
2059
'Branch.lock_write', ('memory:///', '', ''),
2060
'success', ('ok', 'branch token', 'repo token'))
2061
client.add_expected_call(
2062
'Branch.get_config_file', ('memory:///', ),
2063
'success', ('ok', ), "# line 1\n")
2064
client.add_expected_call(
2065
'Branch.get_config_file', ('memory:///', ),
2066
'success', ('ok', ), "# line 1\n")
2067
client.add_expected_call(
2068
'Branch.put_config_file', ('memory:///', 'branch token',
2071
client.add_expected_call(
2072
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2074
transport = MemoryTransport()
2075
branch = self.make_remote_branch(transport, client)
2077
config = branch.get_config_stack()
2078
config.set('email', 'The Dude <lebowski@example.com>')
2080
self.assertFinished(client)
2082
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2083
('call', 'Branch.lock_write', ('memory:///', '', '')),
2084
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2085
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2086
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2087
('memory:///', 'branch token', 'repo token'),
2088
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2089
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2093
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2108
self.assertFinished(client)
2111
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2113
def test_simple(self):
2114
transport = MemoryTransport()
2115
client = FakeClient(transport.base)
2116
client.add_expected_call(
2117
'Branch.get_stacked_on_url', ('quack/',),
2118
'error', ('NotStacked',),)
2119
client.add_expected_call(
2120
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2121
'success', ('ok', '0',),)
2122
client.add_expected_call(
2123
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2124
'error', ('NoSuchRevision', 'unknown',),)
2125
transport.mkdir('quack')
2126
transport = transport.clone('quack')
2127
branch = self.make_remote_branch(transport, client)
2128
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2129
self.assertRaises(errors.NoSuchRevision,
2130
branch.revision_id_to_revno, 'unknown')
2131
self.assertFinished(client)
2133
def test_dotted(self):
2134
transport = MemoryTransport()
2135
client = FakeClient(transport.base)
2136
client.add_expected_call(
2137
'Branch.get_stacked_on_url', ('quack/',),
2138
'error', ('NotStacked',),)
2139
client.add_expected_call(
2140
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2141
'success', ('ok', '0',),)
2142
client.add_expected_call(
2143
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2144
'error', ('NoSuchRevision', 'unknown',),)
2145
transport.mkdir('quack')
2146
transport = transport.clone('quack')
2147
branch = self.make_remote_branch(transport, client)
2148
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2149
self.assertRaises(errors.NoSuchRevision,
2150
branch.revision_id_to_dotted_revno, 'unknown')
2151
self.assertFinished(client)
2153
def test_dotted_no_smart_verb(self):
2154
self.setup_smart_server_with_call_log()
2155
branch = self.make_branch('.')
2156
self.disable_verb('Branch.revision_id_to_revno')
2157
self.reset_smart_call_log()
2158
self.assertEqual((0, ),
2159
branch.revision_id_to_dotted_revno('null:'))
2160
self.assertLength(8, self.hpss_calls)
1686
2163
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2165
def test__get_config(self):
2408
class TestRepositoryBreakLock(TestRemoteRepository):
2410
def test_break_lock(self):
2411
transport_path = 'quack'
2412
repo, client = self.setup_fake_client_and_repository(transport_path)
2413
client.add_success_response('ok')
2416
[('call', 'Repository.break_lock', ('quack/',))],
2420
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2422
def test_get_serializer_format(self):
2423
transport_path = 'hill'
2424
repo, client = self.setup_fake_client_and_repository(transport_path)
2425
client.add_success_response('ok', '7')
2426
self.assertEqual('7', repo.get_serializer_format())
2428
[('call', 'VersionedFileRepository.get_serializer_format',
2433
class TestRepositoryReconcile(TestRemoteRepository):
2435
def test_reconcile(self):
2436
transport_path = 'hill'
2437
repo, client = self.setup_fake_client_and_repository(transport_path)
2438
body = ("garbage_inventories: 2\n"
2439
"inconsistent_parents: 3\n")
2440
client.add_expected_call(
2441
'Repository.lock_write', ('hill/', ''),
2442
'success', ('ok', 'a token'))
2443
client.add_success_response_with_body(body, 'ok')
2444
reconciler = repo.reconcile()
2446
[('call', 'Repository.lock_write', ('hill/', '')),
2447
('call_expecting_body', 'Repository.reconcile',
2448
('hill/', 'a token'))],
2450
self.assertEqual(2, reconciler.garbage_inventories)
2451
self.assertEqual(3, reconciler.inconsistent_parents)
2454
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2456
def test_text(self):
2457
# ('ok',), body with signature text
2458
transport_path = 'quack'
2459
repo, client = self.setup_fake_client_and_repository(transport_path)
2460
client.add_success_response_with_body(
2462
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2464
[('call_expecting_body', 'Repository.get_revision_signature_text',
2465
('quack/', 'revid'))],
2468
def test_no_signature(self):
2469
transport_path = 'quick'
2470
repo, client = self.setup_fake_client_and_repository(transport_path)
2471
client.add_error_response('nosuchrevision', 'unknown')
2472
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2475
[('call_expecting_body', 'Repository.get_revision_signature_text',
2476
('quick/', 'unknown'))],
1906
2480
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2482
def test_get_graph(self):
3071
class TestRepositoryWriteGroups(TestRemoteRepository):
3073
def test_start_write_group(self):
3074
transport_path = 'quack'
3075
repo, client = self.setup_fake_client_and_repository(transport_path)
3076
client.add_expected_call(
3077
'Repository.lock_write', ('quack/', ''),
3078
'success', ('ok', 'a token'))
3079
client.add_expected_call(
3080
'Repository.start_write_group', ('quack/', 'a token'),
3081
'success', ('ok', ('token1', )))
3083
repo.start_write_group()
3085
def test_start_write_group_unsuspendable(self):
3086
# Some repositories do not support suspending write
3087
# groups. For those, fall back to the "real" repository.
3088
transport_path = 'quack'
3089
repo, client = self.setup_fake_client_and_repository(transport_path)
3090
def stub_ensure_real():
3091
client._calls.append(('_ensure_real',))
3092
repo._real_repository = _StubRealPackRepository(client._calls)
3093
repo._ensure_real = stub_ensure_real
3094
client.add_expected_call(
3095
'Repository.lock_write', ('quack/', ''),
3096
'success', ('ok', 'a token'))
3097
client.add_expected_call(
3098
'Repository.start_write_group', ('quack/', 'a token'),
3099
'error', ('UnsuspendableWriteGroup',))
3101
repo.start_write_group()
3102
self.assertEqual(client._calls[-2:], [
3104
('start_write_group',)])
3106
def test_commit_write_group(self):
3107
transport_path = 'quack'
3108
repo, client = self.setup_fake_client_and_repository(transport_path)
3109
client.add_expected_call(
3110
'Repository.lock_write', ('quack/', ''),
3111
'success', ('ok', 'a token'))
3112
client.add_expected_call(
3113
'Repository.start_write_group', ('quack/', 'a token'),
3114
'success', ('ok', ['token1']))
3115
client.add_expected_call(
3116
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3119
repo.start_write_group()
3120
repo.commit_write_group()
3122
def test_abort_write_group(self):
3123
transport_path = 'quack'
3124
repo, client = self.setup_fake_client_and_repository(transport_path)
3125
client.add_expected_call(
3126
'Repository.lock_write', ('quack/', ''),
3127
'success', ('ok', 'a token'))
3128
client.add_expected_call(
3129
'Repository.start_write_group', ('quack/', 'a token'),
3130
'success', ('ok', ['token1']))
3131
client.add_expected_call(
3132
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3135
repo.start_write_group()
3136
repo.abort_write_group(False)
3138
def test_suspend_write_group(self):
3139
transport_path = 'quack'
3140
repo, client = self.setup_fake_client_and_repository(transport_path)
3141
self.assertEqual([], repo.suspend_write_group())
3143
def test_resume_write_group(self):
3144
transport_path = 'quack'
3145
repo, client = self.setup_fake_client_and_repository(transport_path)
3146
client.add_expected_call(
3147
'Repository.lock_write', ('quack/', ''),
3148
'success', ('ok', 'a token'))
3149
client.add_expected_call(
3150
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3153
repo.resume_write_group(['token1'])
2329
3156
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3158
def test_backwards_compat(self):
2895
3776
expected_error = errors.PermissionDenied(path, extra)
2896
3777
self.assertEqual(expected_error, translated_error)
3779
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3781
def test_NoSuchFile_context_path(self):
3782
local_path = "local path"
3783
translated_error = self.translateTuple(('ReadError', "remote path"),
3785
expected_error = errors.ReadError(local_path)
3786
self.assertEqual(expected_error, translated_error)
3788
def test_NoSuchFile_without_context(self):
3789
remote_path = "remote path"
3790
translated_error = self.translateTuple(('ReadError', remote_path))
3791
expected_error = errors.ReadError(remote_path)
3792
self.assertEqual(expected_error, translated_error)
3794
def test_ReadOnlyError(self):
3795
translated_error = self.translateTuple(('ReadOnlyError',))
3796
expected_error = errors.TransportNotPossible("readonly transport")
3797
self.assertEqual(expected_error, translated_error)
3799
def test_MemoryError(self):
3800
translated_error = self.translateTuple(('MemoryError',))
3801
self.assertStartsWith(str(translated_error),
3802
"remote server out of memory")
3804
def test_generic_IndexError_no_classname(self):
3805
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3806
translated_error = self.translateErrorFromSmartServer(err)
3807
expected_error = errors.UnknownErrorFromSmartServer(err)
3808
self.assertEqual(expected_error, translated_error)
3810
# GZ 2011-03-02: TODO test generic non-ascii error string
3812
def test_generic_KeyError(self):
3813
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3814
translated_error = self.translateErrorFromSmartServer(err)
3815
expected_error = errors.UnknownErrorFromSmartServer(err)
3816
self.assertEqual(expected_error, translated_error)
2899
3819
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3820
"""Unit tests for breezy.remote._translate_error's robustness.
2902
3822
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3823
translate successfully. This class about how _translate_err behaves when
3143
4065
def test_copy_content_into_avoids_revision_history(self):
3144
4066
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4067
builder = self.make_branch_builder('remote')
4068
builder.build_commit(message="Commit.")
3147
4069
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4070
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4071
local.repository.fetch(remote_branch.repository)
3150
4072
self.hpss_calls = []
3151
4073
remote_branch.copy_content_into(local)
3152
4074
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4076
def test_fetch_everything_needs_just_one_call(self):
4077
local = self.make_branch('local')
4078
builder = self.make_branch_builder('remote')
4079
builder.build_commit(message="Commit.")
4080
remote_branch_url = self.smart_server.get_url() + 'remote'
4081
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4082
self.hpss_calls = []
4083
local.repository.fetch(
4084
remote_branch.repository,
4085
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4086
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4088
def override_verb(self, verb_name, verb):
4089
request_handlers = request.request_handlers
4090
orig_verb = request_handlers.get(verb_name)
4091
orig_info = request_handlers.get_info(verb_name)
4092
request_handlers.register(verb_name, verb, override_existing=True)
4093
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4094
override_existing=True, info=orig_info)
4096
def test_fetch_everything_backwards_compat(self):
4097
"""Can fetch with EverythingResult even with pre 2.4 servers.
4099
Pre-2.4 do not support 'everything' searches with the
4100
Repository.get_stream_1.19 verb.
4103
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4104
"""A version of the Repository.get_stream_1.19 verb patched to
4105
reject 'everything' searches the way 2.3 and earlier do.
4107
def recreate_search(self, repository, search_bytes,
4108
discard_excess=False):
4109
verb_log.append(search_bytes.split('\n', 1)[0])
4110
if search_bytes == 'everything':
4112
request.FailedSmartServerResponse(('BadSearch',)))
4113
return super(OldGetStreamVerb,
4114
self).recreate_search(repository, search_bytes,
4115
discard_excess=discard_excess)
4116
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4117
local = self.make_branch('local')
4118
builder = self.make_branch_builder('remote')
4119
builder.build_commit(message="Commit.")
4120
remote_branch_url = self.smart_server.get_url() + 'remote'
4121
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4122
self.hpss_calls = []
4123
local.repository.fetch(
4124
remote_branch.repository,
4125
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4126
# make sure the overridden verb was used
4127
self.assertLength(1, verb_log)
4128
# more than one HPSS call is needed, but because it's a VFS callback
4129
# its hard to predict exactly how many.
4130
self.assertTrue(len(self.hpss_calls) > 1)
4133
class TestUpdateBoundBranchWithModifiedBoundLocation(
4134
tests.TestCaseWithTransport):
4135
"""Ensure correct handling of bound_location modifications.
4137
This is tested against a smart server as http://pad.lv/786980 was about a
4138
ReadOnlyError (write attempt during a read-only transaction) which can only
4139
happen in this context.
4143
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4144
self.transport_server = test_server.SmartTCPServer_for_testing
4146
def make_master_and_checkout(self, master_name, checkout_name):
4147
# Create the master branch and its associated checkout
4148
self.master = self.make_branch_and_tree(master_name)
4149
self.checkout = self.master.branch.create_checkout(checkout_name)
4150
# Modify the master branch so there is something to update
4151
self.master.commit('add stuff')
4152
self.last_revid = self.master.commit('even more stuff')
4153
self.bound_location = self.checkout.branch.get_bound_location()
4155
def assertUpdateSucceeds(self, new_location):
4156
self.checkout.branch.set_bound_location(new_location)
4157
self.checkout.update()
4158
self.assertEqual(self.last_revid, self.checkout.last_revision())
4160
def test_without_final_slash(self):
4161
self.make_master_and_checkout('master', 'checkout')
4162
# For unclear reasons some users have a bound_location without a final
4163
# '/', simulate that by forcing such a value
4164
self.assertEndsWith(self.bound_location, '/')
4165
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4167
def test_plus_sign(self):
4168
self.make_master_and_checkout('+master', 'checkout')
4169
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4171
def test_tilda(self):
4172
# Embed ~ in the middle of the path just to avoid any $HOME
4174
self.make_master_and_checkout('mas~ter', 'checkout')
4175
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4178
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4180
def test_no_context(self):
4181
class OutOfCoffee(errors.BzrError):
4182
"""A dummy exception for testing."""
4184
def __init__(self, urgency):
4185
self.urgency = urgency
4186
remote.no_context_error_translators.register("OutOfCoffee",
4187
lambda err: OutOfCoffee(err.error_args[0]))
4188
transport = MemoryTransport()
4189
client = FakeClient(transport.base)
4190
client.add_expected_call(
4191
'Branch.get_stacked_on_url', ('quack/',),
4192
'error', ('NotStacked',))
4193
client.add_expected_call(
4194
'Branch.last_revision_info',
4196
'error', ('OutOfCoffee', 'low'))
4197
transport.mkdir('quack')
4198
transport = transport.clone('quack')
4199
branch = self.make_remote_branch(transport, client)
4200
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4201
self.assertFinished(client)
4203
def test_with_context(self):
4204
class OutOfTea(errors.BzrError):
4205
def __init__(self, branch, urgency):
4206
self.branch = branch
4207
self.urgency = urgency
4208
remote.error_translators.register("OutOfTea",
4209
lambda err, find, path: OutOfTea(err.error_args[0],
4211
transport = MemoryTransport()
4212
client = FakeClient(transport.base)
4213
client.add_expected_call(
4214
'Branch.get_stacked_on_url', ('quack/',),
4215
'error', ('NotStacked',))
4216
client.add_expected_call(
4217
'Branch.last_revision_info',
4219
'error', ('OutOfTea', 'low'))
4220
transport.mkdir('quack')
4221
transport = transport.clone('quack')
4222
branch = self.make_remote_branch(transport, client)
4223
self.assertRaises(OutOfTea, branch.last_revision_info)
4224
self.assertFinished(client)
4227
class TestRepositoryPack(TestRemoteRepository):
4229
def test_pack(self):
4230
transport_path = 'quack'
4231
repo, client = self.setup_fake_client_and_repository(transport_path)
4232
client.add_expected_call(
4233
'Repository.lock_write', ('quack/', ''),
4234
'success', ('ok', 'token'))
4235
client.add_expected_call(
4236
'Repository.pack', ('quack/', 'token', 'False'),
4237
'success', ('ok',), )
4238
client.add_expected_call(
4239
'Repository.unlock', ('quack/', 'token'),
4240
'success', ('ok', ))
4243
def test_pack_with_hint(self):
4244
transport_path = 'quack'
4245
repo, client = self.setup_fake_client_and_repository(transport_path)
4246
client.add_expected_call(
4247
'Repository.lock_write', ('quack/', ''),
4248
'success', ('ok', 'token'))
4249
client.add_expected_call(
4250
'Repository.pack', ('quack/', 'token', 'False'),
4251
'success', ('ok',), )
4252
client.add_expected_call(
4253
'Repository.unlock', ('quack/', 'token', 'False'),
4254
'success', ('ok', ))
4255
repo.pack(['hinta', 'hintb'])
4258
class TestRepositoryIterInventories(TestRemoteRepository):
4259
"""Test Repository.iter_inventories."""
4261
def _serialize_inv_delta(self, old_name, new_name, delta):
4262
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4263
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4265
def test_single_empty(self):
4266
transport_path = 'quack'
4267
repo, client = self.setup_fake_client_and_repository(transport_path)
4268
fmt = controldir.format_registry.get('2a')().repository_format
4270
stream = [('inventory-deltas', [
4271
versionedfile.FulltextContentFactory('somerevid', None, None,
4272
self._serialize_inv_delta('null:', 'somerevid', []))])]
4273
client.add_expected_call(
4274
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4275
'success', ('ok', ),
4276
_stream_to_byte_stream(stream, fmt))
4277
ret = list(repo.iter_inventories(["somerevid"]))
4278
self.assertLength(1, ret)
4280
self.assertEqual("somerevid", inv.revision_id)
4282
def test_empty(self):
4283
transport_path = 'quack'
4284
repo, client = self.setup_fake_client_and_repository(transport_path)
4285
ret = list(repo.iter_inventories([]))
4286
self.assertEqual(ret, [])
4288
def test_missing(self):
4289
transport_path = 'quack'
4290
repo, client = self.setup_fake_client_and_repository(transport_path)
4291
client.add_expected_call(
4292
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4293
'success', ('ok', ), iter([]))
4294
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(