53
60
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
62
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
63
from bzrlib.revision import (
67
from bzrlib.smart import medium, request
58
68
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
69
from bzrlib.smart.repository import (
70
SmartServerRepositoryGetParentMap,
71
SmartServerRepositoryGetStream_1_19,
72
_stream_to_byte_stream,
74
from bzrlib.symbol_versioning import deprecated_in
60
75
from bzrlib.tests import (
62
split_suite_by_condition,
66
from bzrlib.transport import get_transport
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
79
from bzrlib.transport.memory import MemoryTransport
68
80
from bzrlib.transport.remote import (
70
82
RemoteSSHTransport,
71
83
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 = [
87
load_tests = load_tests_apply_scenarios
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
94
{'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):
96
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
100
super(BasicRemoteObjectTests, self).setUp()
89
101
self.transport = self.get_transport()
90
102
# make a branch that can be opened over the smart transport
91
103
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
104
self.addCleanup(self.transport.disconnect)
97
106
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
107
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
108
self.assertIsInstance(b, BzrDir)
101
110
def test_open_remote_branch(self):
102
111
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
112
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
113
branch = b.open_branch()
105
114
self.assertIsInstance(branch, Branch)
480
491
self.assertEqual(None, result._branch_format)
481
492
self.assertFinished(client)
494
def test_unknown(self):
495
transport = self.get_transport('quack')
496
referenced = self.make_branch('referenced')
497
expected = referenced.bzrdir.cloning_metadir()
498
client = FakeClient(transport.base)
499
client.add_expected_call(
500
'BzrDir.cloning_metadir', ('quack/', 'False'),
501
'success', ('unknown', 'unknown', ('branch', ''))),
502
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
504
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
507
class TestBzrDirCheckoutMetaDir(TestRemote):
509
def test__get_checkout_format(self):
510
transport = MemoryTransport()
511
client = FakeClient(transport.base)
512
reference_bzrdir_format = bzrdir.format_registry.get('default')()
513
control_name = reference_bzrdir_format.network_name()
514
client.add_expected_call(
515
'BzrDir.checkout_metadir', ('quack/', ),
516
'success', (control_name, '', ''))
517
transport.mkdir('quack')
518
transport = transport.clone('quack')
519
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
521
result = a_bzrdir.checkout_metadir()
522
# We should have got a reference control dir with default branch and
523
# repository formats.
524
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
525
self.assertEqual(None, result._repository_format)
526
self.assertEqual(None, result._branch_format)
527
self.assertFinished(client)
529
def test_unknown_format(self):
530
transport = MemoryTransport()
531
client = FakeClient(transport.base)
532
client.add_expected_call(
533
'BzrDir.checkout_metadir', ('quack/',),
534
'success', ('dontknow', '', ''))
535
transport.mkdir('quack')
536
transport = transport.clone('quack')
537
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
539
self.assertRaises(errors.UnknownFormatError,
540
a_bzrdir.checkout_metadir)
541
self.assertFinished(client)
544
class TestBzrDirDestroyBranch(TestRemote):
546
def test_destroy_default(self):
547
transport = self.get_transport('quack')
548
referenced = self.make_branch('referenced')
549
client = FakeClient(transport.base)
550
client.add_expected_call(
551
'BzrDir.destroy_branch', ('quack/', ),
553
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
555
a_bzrdir.destroy_branch()
556
self.assertFinished(client)
558
def test_destroy_named(self):
559
transport = self.get_transport('quack')
560
referenced = self.make_branch('referenced')
561
client = FakeClient(transport.base)
562
client.add_expected_call(
563
'BzrDir.destroy_branch', ('quack/', "foo"),
565
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
567
a_bzrdir.destroy_branch("foo")
568
self.assertFinished(client)
571
class TestBzrDirHasWorkingTree(TestRemote):
573
def test_has_workingtree(self):
574
transport = self.get_transport('quack')
575
client = FakeClient(transport.base)
576
client.add_expected_call(
577
'BzrDir.has_workingtree', ('quack/',),
578
'success', ('yes',)),
579
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
581
self.assertTrue(a_bzrdir.has_workingtree())
582
self.assertFinished(client)
584
def test_no_workingtree(self):
585
transport = self.get_transport('quack')
586
client = FakeClient(transport.base)
587
client.add_expected_call(
588
'BzrDir.has_workingtree', ('quack/',),
590
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
592
self.assertFalse(a_bzrdir.has_workingtree())
593
self.assertFinished(client)
596
class TestBzrDirDestroyRepository(TestRemote):
598
def test_destroy_repository(self):
599
transport = self.get_transport('quack')
600
client = FakeClient(transport.base)
601
client.add_expected_call(
602
'BzrDir.destroy_repository', ('quack/',),
604
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
606
a_bzrdir.destroy_repository()
607
self.assertFinished(client)
484
610
class TestBzrDirOpen(TestRemote):
967
1125
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1128
class TestBranchBreakLock(RemoteBranchTestCase):
1130
def test_break_lock(self):
1131
transport_path = 'quack'
1132
transport = MemoryTransport()
1133
client = FakeClient(transport.base)
1134
client.add_expected_call(
1135
'Branch.get_stacked_on_url', ('quack/',),
1136
'error', ('NotStacked',))
1137
client.add_expected_call(
1138
'Branch.break_lock', ('quack/',),
1140
transport.mkdir('quack')
1141
transport = transport.clone('quack')
1142
branch = self.make_remote_branch(transport, client)
1144
self.assertFinished(client)
1147
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1149
def test_get_physical_lock_status_yes(self):
1150
transport = MemoryTransport()
1151
client = FakeClient(transport.base)
1152
client.add_expected_call(
1153
'Branch.get_stacked_on_url', ('quack/',),
1154
'error', ('NotStacked',))
1155
client.add_expected_call(
1156
'Branch.get_physical_lock_status', ('quack/',),
1157
'success', ('yes',))
1158
transport.mkdir('quack')
1159
transport = transport.clone('quack')
1160
branch = self.make_remote_branch(transport, client)
1161
result = branch.get_physical_lock_status()
1162
self.assertFinished(client)
1163
self.assertEqual(True, result)
1165
def test_get_physical_lock_status_no(self):
1166
transport = MemoryTransport()
1167
client = FakeClient(transport.base)
1168
client.add_expected_call(
1169
'Branch.get_stacked_on_url', ('quack/',),
1170
'error', ('NotStacked',))
1171
client.add_expected_call(
1172
'Branch.get_physical_lock_status', ('quack/',),
1174
transport.mkdir('quack')
1175
transport = transport.clone('quack')
1176
branch = self.make_remote_branch(transport, client)
1177
result = branch.get_physical_lock_status()
1178
self.assertFinished(client)
1179
self.assertEqual(False, result)
970
1182
class TestBranchGetParent(RemoteBranchTestCase):
972
1184
def test_no_parent(self):
1143
1359
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1362
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1364
def test_uses_last_revision_info_and_tags_by_default(self):
1365
transport = MemoryTransport()
1366
client = FakeClient(transport.base)
1367
client.add_expected_call(
1368
'Branch.get_stacked_on_url', ('quack/',),
1369
'error', ('NotStacked',))
1370
client.add_expected_call(
1371
'Branch.last_revision_info', ('quack/',),
1372
'success', ('ok', '1', 'rev-tip'))
1373
client.add_expected_call(
1374
'Branch.get_config_file', ('quack/',),
1375
'success', ('ok',), '')
1376
transport.mkdir('quack')
1377
transport = transport.clone('quack')
1378
branch = self.make_remote_branch(transport, client)
1379
result = branch.heads_to_fetch()
1380
self.assertFinished(client)
1381
self.assertEqual((set(['rev-tip']), set()), result)
1383
def test_uses_last_revision_info_and_tags_when_set(self):
1384
transport = MemoryTransport()
1385
client = FakeClient(transport.base)
1386
client.add_expected_call(
1387
'Branch.get_stacked_on_url', ('quack/',),
1388
'error', ('NotStacked',))
1389
client.add_expected_call(
1390
'Branch.last_revision_info', ('quack/',),
1391
'success', ('ok', '1', 'rev-tip'))
1392
client.add_expected_call(
1393
'Branch.get_config_file', ('quack/',),
1394
'success', ('ok',), 'branch.fetch_tags = True')
1395
# XXX: this will break if the default format's serialization of tags
1396
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1397
client.add_expected_call(
1398
'Branch.get_tags_bytes', ('quack/',),
1399
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1400
transport.mkdir('quack')
1401
transport = transport.clone('quack')
1402
branch = self.make_remote_branch(transport, client)
1403
result = branch.heads_to_fetch()
1404
self.assertFinished(client)
1406
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1408
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1409
transport = MemoryTransport()
1410
client = FakeClient(transport.base)
1411
client.add_expected_call(
1412
'Branch.get_stacked_on_url', ('quack/',),
1413
'error', ('NotStacked',))
1414
client.add_expected_call(
1415
'Branch.heads_to_fetch', ('quack/',),
1416
'success', (['tip'], ['tagged-1', 'tagged-2']))
1417
transport.mkdir('quack')
1418
transport = transport.clone('quack')
1419
branch = self.make_remote_branch(transport, client)
1420
branch._format._use_default_local_heads_to_fetch = lambda: False
1421
result = branch.heads_to_fetch()
1422
self.assertFinished(client)
1423
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1425
def make_branch_with_tags(self):
1426
self.setup_smart_server_with_call_log()
1427
# Make a branch with a single revision.
1428
builder = self.make_branch_builder('foo')
1429
builder.start_series()
1430
builder.build_snapshot('tip', None, [
1431
('add', ('', 'root-id', 'directory', ''))])
1432
builder.finish_series()
1433
branch = builder.get_branch()
1434
# Add two tags to that branch
1435
branch.tags.set_tag('tag-1', 'rev-1')
1436
branch.tags.set_tag('tag-2', 'rev-2')
1439
def test_backwards_compatible(self):
1440
br = self.make_branch_with_tags()
1443
br.get_config_stack().set('branch.fetch_tags', True)
1446
self.addCleanup(br.lock_read().unlock)
1447
# Disable the heads_to_fetch verb
1448
verb = 'Branch.heads_to_fetch'
1449
self.disable_verb(verb)
1450
self.reset_smart_call_log()
1451
result = br.heads_to_fetch()
1452
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1454
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1455
[call.call.method for call in self.hpss_calls])
1457
def test_backwards_compatible_no_tags(self):
1458
br = self.make_branch_with_tags()
1461
br.get_config_stack().set('branch.fetch_tags', False)
1464
self.addCleanup(br.lock_read().unlock)
1465
# Disable the heads_to_fetch verb
1466
verb = 'Branch.heads_to_fetch'
1467
self.disable_verb(verb)
1468
self.reset_smart_call_log()
1469
result = br.heads_to_fetch()
1470
self.assertEqual((set(['tip']), set()), result)
1472
['Branch.last_revision_info'],
1473
[call.call.method for call in self.hpss_calls])
1146
1476
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1478
def test_empty_branch(self):
1661
2011
self.addCleanup(branch.unlock)
1662
2012
self.reset_smart_call_log()
1663
2013
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2014
self.assertLength(11, self.hpss_calls)
1665
2015
self.assertEqual('value', branch._get_config().get_option('name'))
2017
def test_backwards_compat_set_option_with_dict(self):
2018
self.setup_smart_server_with_call_log()
2019
branch = self.make_branch('.')
2020
verb = 'Branch.set_config_option_dict'
2021
self.disable_verb(verb)
2023
self.addCleanup(branch.unlock)
2024
self.reset_smart_call_log()
2025
config = branch._get_config()
2026
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2027
config.set_option(value_dict, 'name')
2028
self.assertLength(11, self.hpss_calls)
2029
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2032
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2034
def test_get_branch_conf(self):
2035
# in an empty branch we decode the response properly
2036
client = FakeClient()
2037
client.add_expected_call(
2038
'Branch.get_stacked_on_url', ('memory:///',),
2039
'error', ('NotStacked',),)
2040
client.add_success_response_with_body('# config file body', 'ok')
2041
transport = MemoryTransport()
2042
branch = self.make_remote_branch(transport, client)
2043
config = branch.get_config_stack()
2045
config.get("log_format")
2047
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2048
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2051
def test_set_branch_conf(self):
2052
client = FakeClient()
2053
client.add_expected_call(
2054
'Branch.get_stacked_on_url', ('memory:///',),
2055
'error', ('NotStacked',),)
2056
client.add_expected_call(
2057
'Branch.lock_write', ('memory:///', '', ''),
2058
'success', ('ok', 'branch token', 'repo token'))
2059
client.add_expected_call(
2060
'Branch.get_config_file', ('memory:///', ),
2061
'success', ('ok', ), "# line 1\n")
2062
client.add_expected_call(
2063
'Branch.get_config_file', ('memory:///', ),
2064
'success', ('ok', ), "# line 1\n")
2065
client.add_expected_call(
2066
'Branch.put_config_file', ('memory:///', 'branch token',
2069
client.add_expected_call(
2070
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2072
transport = MemoryTransport()
2073
branch = self.make_remote_branch(transport, client)
2075
config = branch.get_config_stack()
2076
config.set('email', 'The Dude <lebowski@example.com>')
2078
self.assertFinished(client)
2080
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2081
('call', 'Branch.lock_write', ('memory:///', '', '')),
2082
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2083
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2084
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2085
('memory:///', 'branch token', 'repo token'),
2086
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2087
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2091
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2106
self.assertFinished(client)
2109
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2111
def test_simple(self):
2112
transport = MemoryTransport()
2113
client = FakeClient(transport.base)
2114
client.add_expected_call(
2115
'Branch.get_stacked_on_url', ('quack/',),
2116
'error', ('NotStacked',),)
2117
client.add_expected_call(
2118
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2119
'success', ('ok', '0',),)
2120
client.add_expected_call(
2121
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2122
'error', ('NoSuchRevision', 'unknown',),)
2123
transport.mkdir('quack')
2124
transport = transport.clone('quack')
2125
branch = self.make_remote_branch(transport, client)
2126
self.assertEquals(0, branch.revision_id_to_revno('null:'))
2127
self.assertRaises(errors.NoSuchRevision,
2128
branch.revision_id_to_revno, 'unknown')
2129
self.assertFinished(client)
2131
def test_dotted(self):
2132
transport = MemoryTransport()
2133
client = FakeClient(transport.base)
2134
client.add_expected_call(
2135
'Branch.get_stacked_on_url', ('quack/',),
2136
'error', ('NotStacked',),)
2137
client.add_expected_call(
2138
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2139
'success', ('ok', '0',),)
2140
client.add_expected_call(
2141
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2142
'error', ('NoSuchRevision', 'unknown',),)
2143
transport.mkdir('quack')
2144
transport = transport.clone('quack')
2145
branch = self.make_remote_branch(transport, client)
2146
self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
2147
self.assertRaises(errors.NoSuchRevision,
2148
branch.revision_id_to_dotted_revno, 'unknown')
2149
self.assertFinished(client)
2151
def test_dotted_no_smart_verb(self):
2152
self.setup_smart_server_with_call_log()
2153
branch = self.make_branch('.')
2154
self.disable_verb('Branch.revision_id_to_revno')
2155
self.reset_smart_call_log()
2156
self.assertEquals((0, ),
2157
branch.revision_id_to_dotted_revno('null:'))
2158
self.assertLength(8, self.hpss_calls)
1686
2161
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2163
def test__get_config(self):
2406
class TestRepositoryBreakLock(TestRemoteRepository):
2408
def test_break_lock(self):
2409
transport_path = 'quack'
2410
repo, client = self.setup_fake_client_and_repository(transport_path)
2411
client.add_success_response('ok')
2414
[('call', 'Repository.break_lock', ('quack/',))],
2418
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2420
def test_get_serializer_format(self):
2421
transport_path = 'hill'
2422
repo, client = self.setup_fake_client_and_repository(transport_path)
2423
client.add_success_response('ok', '7')
2424
self.assertEquals('7', repo.get_serializer_format())
2426
[('call', 'VersionedFileRepository.get_serializer_format',
2431
class TestRepositoryReconcile(TestRemoteRepository):
2433
def test_reconcile(self):
2434
transport_path = 'hill'
2435
repo, client = self.setup_fake_client_and_repository(transport_path)
2436
body = ("garbage_inventories: 2\n"
2437
"inconsistent_parents: 3\n")
2438
client.add_expected_call(
2439
'Repository.lock_write', ('hill/', ''),
2440
'success', ('ok', 'a token'))
2441
client.add_success_response_with_body(body, 'ok')
2442
reconciler = repo.reconcile()
2444
[('call', 'Repository.lock_write', ('hill/', '')),
2445
('call_expecting_body', 'Repository.reconcile',
2446
('hill/', 'a token'))],
2448
self.assertEquals(2, reconciler.garbage_inventories)
2449
self.assertEquals(3, reconciler.inconsistent_parents)
2452
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2454
def test_text(self):
2455
# ('ok',), body with signature text
2456
transport_path = 'quack'
2457
repo, client = self.setup_fake_client_and_repository(transport_path)
2458
client.add_success_response_with_body(
2460
self.assertEquals("THETEXT", repo.get_signature_text("revid"))
2462
[('call_expecting_body', 'Repository.get_revision_signature_text',
2463
('quack/', 'revid'))],
2466
def test_no_signature(self):
2467
transport_path = 'quick'
2468
repo, client = self.setup_fake_client_and_repository(transport_path)
2469
client.add_error_response('nosuchrevision', 'unknown')
2470
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2473
[('call_expecting_body', 'Repository.get_revision_signature_text',
2474
('quick/', 'unknown'))],
1906
2478
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2480
def test_get_graph(self):
3069
class TestRepositoryWriteGroups(TestRemoteRepository):
3071
def test_start_write_group(self):
3072
transport_path = 'quack'
3073
repo, client = self.setup_fake_client_and_repository(transport_path)
3074
client.add_expected_call(
3075
'Repository.lock_write', ('quack/', ''),
3076
'success', ('ok', 'a token'))
3077
client.add_expected_call(
3078
'Repository.start_write_group', ('quack/', 'a token'),
3079
'success', ('ok', ('token1', )))
3081
repo.start_write_group()
3083
def test_start_write_group_unsuspendable(self):
3084
# Some repositories do not support suspending write
3085
# groups. For those, fall back to the "real" repository.
3086
transport_path = 'quack'
3087
repo, client = self.setup_fake_client_and_repository(transport_path)
3088
def stub_ensure_real():
3089
client._calls.append(('_ensure_real',))
3090
repo._real_repository = _StubRealPackRepository(client._calls)
3091
repo._ensure_real = stub_ensure_real
3092
client.add_expected_call(
3093
'Repository.lock_write', ('quack/', ''),
3094
'success', ('ok', 'a token'))
3095
client.add_expected_call(
3096
'Repository.start_write_group', ('quack/', 'a token'),
3097
'error', ('UnsuspendableWriteGroup',))
3099
repo.start_write_group()
3100
self.assertEquals(client._calls[-2:], [
3102
('start_write_group',)])
3104
def test_commit_write_group(self):
3105
transport_path = 'quack'
3106
repo, client = self.setup_fake_client_and_repository(transport_path)
3107
client.add_expected_call(
3108
'Repository.lock_write', ('quack/', ''),
3109
'success', ('ok', 'a token'))
3110
client.add_expected_call(
3111
'Repository.start_write_group', ('quack/', 'a token'),
3112
'success', ('ok', ['token1']))
3113
client.add_expected_call(
3114
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3117
repo.start_write_group()
3118
repo.commit_write_group()
3120
def test_abort_write_group(self):
3121
transport_path = 'quack'
3122
repo, client = self.setup_fake_client_and_repository(transport_path)
3123
client.add_expected_call(
3124
'Repository.lock_write', ('quack/', ''),
3125
'success', ('ok', 'a token'))
3126
client.add_expected_call(
3127
'Repository.start_write_group', ('quack/', 'a token'),
3128
'success', ('ok', ['token1']))
3129
client.add_expected_call(
3130
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3133
repo.start_write_group()
3134
repo.abort_write_group(False)
3136
def test_suspend_write_group(self):
3137
transport_path = 'quack'
3138
repo, client = self.setup_fake_client_and_repository(transport_path)
3139
self.assertEquals([], repo.suspend_write_group())
3141
def test_resume_write_group(self):
3142
transport_path = 'quack'
3143
repo, client = self.setup_fake_client_and_repository(transport_path)
3144
client.add_expected_call(
3145
'Repository.lock_write', ('quack/', ''),
3146
'success', ('ok', 'a token'))
3147
client.add_expected_call(
3148
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3151
repo.resume_write_group(['token1'])
2329
3154
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3156
def test_backwards_compat(self):
2895
3774
expected_error = errors.PermissionDenied(path, extra)
2896
3775
self.assertEqual(expected_error, translated_error)
3777
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3779
def test_NoSuchFile_context_path(self):
3780
local_path = "local path"
3781
translated_error = self.translateTuple(('ReadError', "remote path"),
3783
expected_error = errors.ReadError(local_path)
3784
self.assertEqual(expected_error, translated_error)
3786
def test_NoSuchFile_without_context(self):
3787
remote_path = "remote path"
3788
translated_error = self.translateTuple(('ReadError', remote_path))
3789
expected_error = errors.ReadError(remote_path)
3790
self.assertEqual(expected_error, translated_error)
3792
def test_ReadOnlyError(self):
3793
translated_error = self.translateTuple(('ReadOnlyError',))
3794
expected_error = errors.TransportNotPossible("readonly transport")
3795
self.assertEqual(expected_error, translated_error)
3797
def test_MemoryError(self):
3798
translated_error = self.translateTuple(('MemoryError',))
3799
self.assertStartsWith(str(translated_error),
3800
"remote server out of memory")
3802
def test_generic_IndexError_no_classname(self):
3803
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3804
translated_error = self.translateErrorFromSmartServer(err)
3805
expected_error = errors.UnknownErrorFromSmartServer(err)
3806
self.assertEqual(expected_error, translated_error)
3808
# GZ 2011-03-02: TODO test generic non-ascii error string
3810
def test_generic_KeyError(self):
3811
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3812
translated_error = self.translateErrorFromSmartServer(err)
3813
expected_error = errors.UnknownErrorFromSmartServer(err)
3814
self.assertEqual(expected_error, translated_error)
2899
3817
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3818
"""Unit tests for bzrlib.remote._translate_error's robustness.
3143
4063
def test_copy_content_into_avoids_revision_history(self):
3144
4064
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4065
builder = self.make_branch_builder('remote')
4066
builder.build_commit(message="Commit.")
3147
4067
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4068
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4069
local.repository.fetch(remote_branch.repository)
3150
4070
self.hpss_calls = []
3151
4071
remote_branch.copy_content_into(local)
3152
4072
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4074
def test_fetch_everything_needs_just_one_call(self):
4075
local = self.make_branch('local')
4076
builder = self.make_branch_builder('remote')
4077
builder.build_commit(message="Commit.")
4078
remote_branch_url = self.smart_server.get_url() + 'remote'
4079
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4080
self.hpss_calls = []
4081
local.repository.fetch(
4082
remote_branch.repository,
4083
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4084
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4086
def override_verb(self, verb_name, verb):
4087
request_handlers = request.request_handlers
4088
orig_verb = request_handlers.get(verb_name)
4089
orig_info = request_handlers.get_info(verb_name)
4090
request_handlers.register(verb_name, verb, override_existing=True)
4091
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4092
override_existing=True, info=orig_info)
4094
def test_fetch_everything_backwards_compat(self):
4095
"""Can fetch with EverythingResult even with pre 2.4 servers.
4097
Pre-2.4 do not support 'everything' searches with the
4098
Repository.get_stream_1.19 verb.
4101
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4102
"""A version of the Repository.get_stream_1.19 verb patched to
4103
reject 'everything' searches the way 2.3 and earlier do.
4105
def recreate_search(self, repository, search_bytes,
4106
discard_excess=False):
4107
verb_log.append(search_bytes.split('\n', 1)[0])
4108
if search_bytes == 'everything':
4110
request.FailedSmartServerResponse(('BadSearch',)))
4111
return super(OldGetStreamVerb,
4112
self).recreate_search(repository, search_bytes,
4113
discard_excess=discard_excess)
4114
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4115
local = self.make_branch('local')
4116
builder = self.make_branch_builder('remote')
4117
builder.build_commit(message="Commit.")
4118
remote_branch_url = self.smart_server.get_url() + 'remote'
4119
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4120
self.hpss_calls = []
4121
local.repository.fetch(
4122
remote_branch.repository,
4123
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4124
# make sure the overridden verb was used
4125
self.assertLength(1, verb_log)
4126
# more than one HPSS call is needed, but because it's a VFS callback
4127
# its hard to predict exactly how many.
4128
self.assertTrue(len(self.hpss_calls) > 1)
4131
class TestUpdateBoundBranchWithModifiedBoundLocation(
4132
tests.TestCaseWithTransport):
4133
"""Ensure correct handling of bound_location modifications.
4135
This is tested against a smart server as http://pad.lv/786980 was about a
4136
ReadOnlyError (write attempt during a read-only transaction) which can only
4137
happen in this context.
4141
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4142
self.transport_server = test_server.SmartTCPServer_for_testing
4144
def make_master_and_checkout(self, master_name, checkout_name):
4145
# Create the master branch and its associated checkout
4146
self.master = self.make_branch_and_tree(master_name)
4147
self.checkout = self.master.branch.create_checkout(checkout_name)
4148
# Modify the master branch so there is something to update
4149
self.master.commit('add stuff')
4150
self.last_revid = self.master.commit('even more stuff')
4151
self.bound_location = self.checkout.branch.get_bound_location()
4153
def assertUpdateSucceeds(self, new_location):
4154
self.checkout.lock_write()
4156
self.checkout.branch.set_bound_location(new_location)
4157
self.checkout.update()
4159
self.checkout.unlock()
4160
self.assertEquals(self.last_revid, self.checkout.last_revision())
4162
def test_without_final_slash(self):
4163
self.make_master_and_checkout('master', 'checkout')
4164
# For unclear reasons some users have a bound_location without a final
4165
# '/', simulate that by forcing such a value
4166
self.assertEndsWith(self.bound_location, '/')
4167
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4169
def test_plus_sign(self):
4170
self.make_master_and_checkout('+master', 'checkout')
4171
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4173
def test_tilda(self):
4174
# Embed ~ in the middle of the path just to avoid any $HOME
4176
self.make_master_and_checkout('mas~ter', 'checkout')
4177
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4180
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4182
def test_no_context(self):
4183
class OutOfCoffee(errors.BzrError):
4184
"""A dummy exception for testing."""
4186
def __init__(self, urgency):
4187
self.urgency = urgency
4188
remote.no_context_error_translators.register("OutOfCoffee",
4189
lambda err: OutOfCoffee(err.error_args[0]))
4190
transport = MemoryTransport()
4191
client = FakeClient(transport.base)
4192
client.add_expected_call(
4193
'Branch.get_stacked_on_url', ('quack/',),
4194
'error', ('NotStacked',))
4195
client.add_expected_call(
4196
'Branch.last_revision_info',
4198
'error', ('OutOfCoffee', 'low'))
4199
transport.mkdir('quack')
4200
transport = transport.clone('quack')
4201
branch = self.make_remote_branch(transport, client)
4202
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4203
self.assertFinished(client)
4205
def test_with_context(self):
4206
class OutOfTea(errors.BzrError):
4207
def __init__(self, branch, urgency):
4208
self.branch = branch
4209
self.urgency = urgency
4210
remote.error_translators.register("OutOfTea",
4211
lambda err, find, path: OutOfTea(err.error_args[0],
4213
transport = MemoryTransport()
4214
client = FakeClient(transport.base)
4215
client.add_expected_call(
4216
'Branch.get_stacked_on_url', ('quack/',),
4217
'error', ('NotStacked',))
4218
client.add_expected_call(
4219
'Branch.last_revision_info',
4221
'error', ('OutOfTea', 'low'))
4222
transport.mkdir('quack')
4223
transport = transport.clone('quack')
4224
branch = self.make_remote_branch(transport, client)
4225
self.assertRaises(OutOfTea, branch.last_revision_info)
4226
self.assertFinished(client)
4229
class TestRepositoryPack(TestRemoteRepository):
4231
def test_pack(self):
4232
transport_path = 'quack'
4233
repo, client = self.setup_fake_client_and_repository(transport_path)
4234
client.add_expected_call(
4235
'Repository.lock_write', ('quack/', ''),
4236
'success', ('ok', 'token'))
4237
client.add_expected_call(
4238
'Repository.pack', ('quack/', 'token', 'False'),
4239
'success', ('ok',), )
4240
client.add_expected_call(
4241
'Repository.unlock', ('quack/', 'token'),
4242
'success', ('ok', ))
4245
def test_pack_with_hint(self):
4246
transport_path = 'quack'
4247
repo, client = self.setup_fake_client_and_repository(transport_path)
4248
client.add_expected_call(
4249
'Repository.lock_write', ('quack/', ''),
4250
'success', ('ok', 'token'))
4251
client.add_expected_call(
4252
'Repository.pack', ('quack/', 'token', 'False'),
4253
'success', ('ok',), )
4254
client.add_expected_call(
4255
'Repository.unlock', ('quack/', 'token', 'False'),
4256
'success', ('ok', ))
4257
repo.pack(['hinta', 'hintb'])
4260
class TestRepositoryIterInventories(TestRemoteRepository):
4261
"""Test Repository.iter_inventories."""
4263
def _serialize_inv_delta(self, old_name, new_name, delta):
4264
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4265
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4267
def test_single_empty(self):
4268
transport_path = 'quack'
4269
repo, client = self.setup_fake_client_and_repository(transport_path)
4270
fmt = bzrdir.format_registry.get('2a')().repository_format
4272
stream = [('inventory-deltas', [
4273
versionedfile.FulltextContentFactory('somerevid', None, None,
4274
self._serialize_inv_delta('null:', 'somerevid', []))])]
4275
client.add_expected_call(
4276
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4277
'success', ('ok', ),
4278
_stream_to_byte_stream(stream, fmt))
4279
ret = list(repo.iter_inventories(["somerevid"]))
4280
self.assertLength(1, ret)
4282
self.assertEquals("somerevid", inv.revision_id)
4284
def test_empty(self):
4285
transport_path = 'quack'
4286
repo, client = self.setup_fake_client_and_repository(transport_path)
4287
ret = list(repo.iter_inventories([]))
4288
self.assertEquals(ret, [])
4290
def test_missing(self):
4291
transport_path = 'quack'
4292
repo, client = self.setup_fake_client_and_repository(transport_path)
4293
client.add_expected_call(
4294
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4295
'success', ('ok', ), iter([]))
4296
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(