60
53
RemoteRepositoryFormat,
62
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
63
from bzrlib.revision import (
67
from bzrlib.smart import medium, request
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
68
58
from bzrlib.smart.client import _SmartClient
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
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
75
60
from bzrlib.tests import (
62
split_suite_by_condition,
78
from bzrlib.tests.scenarios import load_tests_apply_scenarios
66
from bzrlib.transport import get_transport
79
67
from bzrlib.transport.memory import MemoryTransport
80
68
from bzrlib.transport.remote import (
82
70
RemoteSSHTransport,
83
71
RemoteTCPTransport,
87
load_tests = load_tests_apply_scenarios
90
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
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 = [
94
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
96
{'transport_server': test_server.SmartTCPServer_for_testing})]
81
{'transport_server': test_server.SmartTCPServer_for_testing})]
82
return multiply_tests(to_adapt, smart_server_version_scenarios, result)
85
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
100
88
super(BasicRemoteObjectTests, self).setUp()
101
89
self.transport = self.get_transport()
102
90
# make a branch that can be opened over the smart transport
103
91
self.local_wt = BzrDir.create_standalone_workingtree('.')
104
self.addCleanup(self.transport.disconnect)
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
106
97
def test_create_remote_bzrdir(self):
107
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
108
99
self.assertIsInstance(b, BzrDir)
110
101
def test_open_remote_branch(self):
111
102
# open a standalone branch in the working directory
112
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
113
104
branch = b.open_branch()
114
105
self.assertIsInstance(branch, Branch)
482
477
self.assertEqual(None, result._branch_format)
483
478
self.assertFinished(client)
485
def test_unknown(self):
486
transport = self.get_transport('quack')
487
referenced = self.make_branch('referenced')
488
expected = referenced.bzrdir.cloning_metadir()
489
client = FakeClient(transport.base)
490
client.add_expected_call(
491
'BzrDir.cloning_metadir', ('quack/', 'False'),
492
'success', ('unknown', 'unknown', ('branch', ''))),
493
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
495
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
498
class TestBzrDirCheckoutMetaDir(TestRemote):
500
def test__get_checkout_format(self):
501
transport = MemoryTransport()
502
client = FakeClient(transport.base)
503
reference_bzrdir_format = controldir.format_registry.get('default')()
504
control_name = reference_bzrdir_format.network_name()
505
client.add_expected_call(
506
'BzrDir.checkout_metadir', ('quack/', ),
507
'success', (control_name, '', ''))
508
transport.mkdir('quack')
509
transport = transport.clone('quack')
510
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
512
result = a_bzrdir.checkout_metadir()
513
# We should have got a reference control dir with default branch and
514
# repository formats.
515
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
516
self.assertEqual(None, result._repository_format)
517
self.assertEqual(None, result._branch_format)
518
self.assertFinished(client)
520
def test_unknown_format(self):
521
transport = MemoryTransport()
522
client = FakeClient(transport.base)
523
client.add_expected_call(
524
'BzrDir.checkout_metadir', ('quack/',),
525
'success', ('dontknow', '', ''))
526
transport.mkdir('quack')
527
transport = transport.clone('quack')
528
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
530
self.assertRaises(errors.UnknownFormatError,
531
a_bzrdir.checkout_metadir)
532
self.assertFinished(client)
535
class TestBzrDirGetBranches(TestRemote):
537
def test_get_branches(self):
538
transport = MemoryTransport()
539
client = FakeClient(transport.base)
540
reference_bzrdir_format = controldir.format_registry.get('default')()
541
branch_name = reference_bzrdir_format.get_branch_format().network_name()
542
client.add_success_response_with_body(
544
"foo": ("branch", branch_name),
545
"": ("branch", branch_name)}), "success")
546
client.add_success_response(
547
'ok', '', 'no', 'no', 'no',
548
reference_bzrdir_format.repository_format.network_name())
549
client.add_error_response('NotStacked')
550
client.add_success_response(
551
'ok', '', 'no', 'no', 'no',
552
reference_bzrdir_format.repository_format.network_name())
553
client.add_error_response('NotStacked')
554
transport.mkdir('quack')
555
transport = transport.clone('quack')
556
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
558
result = a_bzrdir.get_branches()
559
self.assertEqual(set(["", "foo"]), set(result.keys()))
561
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
562
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
563
('call', 'Branch.get_stacked_on_url', ('quack/', )),
564
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
565
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
569
class TestBzrDirDestroyBranch(TestRemote):
571
def test_destroy_default(self):
572
transport = self.get_transport('quack')
573
referenced = self.make_branch('referenced')
574
client = FakeClient(transport.base)
575
client.add_expected_call(
576
'BzrDir.destroy_branch', ('quack/', ),
578
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
580
a_bzrdir.destroy_branch()
581
self.assertFinished(client)
584
class TestBzrDirHasWorkingTree(TestRemote):
586
def test_has_workingtree(self):
587
transport = self.get_transport('quack')
588
client = FakeClient(transport.base)
589
client.add_expected_call(
590
'BzrDir.has_workingtree', ('quack/',),
591
'success', ('yes',)),
592
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
594
self.assertTrue(a_bzrdir.has_workingtree())
595
self.assertFinished(client)
597
def test_no_workingtree(self):
598
transport = self.get_transport('quack')
599
client = FakeClient(transport.base)
600
client.add_expected_call(
601
'BzrDir.has_workingtree', ('quack/',),
603
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
605
self.assertFalse(a_bzrdir.has_workingtree())
606
self.assertFinished(client)
609
class TestBzrDirDestroyRepository(TestRemote):
611
def test_destroy_repository(self):
612
transport = self.get_transport('quack')
613
client = FakeClient(transport.base)
614
client.add_expected_call(
615
'BzrDir.destroy_repository', ('quack/',),
617
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
619
a_bzrdir.destroy_repository()
620
self.assertFinished(client)
623
481
class TestBzrDirOpen(TestRemote):
665
523
'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
666
524
client.add_expected_call(
667
525
'BzrDir.open', ('quack/',), 'success', ('yes',))
668
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
669
_client=client, _force_probe=True)
670
self.assertIsInstance(bd, RemoteBzrDir)
671
self.assertFinished(client)
673
def test_backwards_compat_hpss_v2(self):
674
client, transport = self.make_fake_client_and_transport()
675
# Monkey-patch fake client to simulate real-world behaviour with v2
676
# server: upon first RPC call detect the protocol version, and because
677
# the version is 2 also do _remember_remote_is_before((1, 6)) before
678
# continuing with the RPC.
679
orig_check_call = client._check_call
680
def check_call(method, args):
681
client._medium._protocol_version = 2
682
client._medium._remember_remote_is_before((1, 6))
683
client._check_call = orig_check_call
684
client._check_call(method, args)
685
client._check_call = check_call
686
client.add_expected_call(
687
'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
688
client.add_expected_call(
689
'BzrDir.open', ('quack/',), 'success', ('yes',))
690
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
526
bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
691
527
_client=client, _force_probe=True)
692
528
self.assertIsInstance(bd, RemoteBzrDir)
693
529
self.assertFinished(client)
1138
942
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1141
class TestBranchBreakLock(RemoteBranchTestCase):
1143
def test_break_lock(self):
1144
transport_path = 'quack'
1145
transport = MemoryTransport()
1146
client = FakeClient(transport.base)
1147
client.add_expected_call(
1148
'Branch.get_stacked_on_url', ('quack/',),
1149
'error', ('NotStacked',))
1150
client.add_expected_call(
1151
'Branch.break_lock', ('quack/',),
1153
transport.mkdir('quack')
1154
transport = transport.clone('quack')
1155
branch = self.make_remote_branch(transport, client)
1157
self.assertFinished(client)
1160
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1162
def test_get_physical_lock_status_yes(self):
1163
transport = MemoryTransport()
1164
client = FakeClient(transport.base)
1165
client.add_expected_call(
1166
'Branch.get_stacked_on_url', ('quack/',),
1167
'error', ('NotStacked',))
1168
client.add_expected_call(
1169
'Branch.get_physical_lock_status', ('quack/',),
1170
'success', ('yes',))
1171
transport.mkdir('quack')
1172
transport = transport.clone('quack')
1173
branch = self.make_remote_branch(transport, client)
1174
result = branch.get_physical_lock_status()
1175
self.assertFinished(client)
1176
self.assertEqual(True, result)
1178
def test_get_physical_lock_status_no(self):
1179
transport = MemoryTransport()
1180
client = FakeClient(transport.base)
1181
client.add_expected_call(
1182
'Branch.get_stacked_on_url', ('quack/',),
1183
'error', ('NotStacked',))
1184
client.add_expected_call(
1185
'Branch.get_physical_lock_status', ('quack/',),
1187
transport.mkdir('quack')
1188
transport = transport.clone('quack')
1189
branch = self.make_remote_branch(transport, client)
1190
result = branch.get_physical_lock_status()
1191
self.assertFinished(client)
1192
self.assertEqual(False, result)
1195
945
class TestBranchGetParent(RemoteBranchTestCase):
1197
947
def test_no_parent(self):
1368
1118
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1371
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1373
def test_uses_last_revision_info_and_tags_by_default(self):
1374
transport = MemoryTransport()
1375
client = FakeClient(transport.base)
1376
client.add_expected_call(
1377
'Branch.get_stacked_on_url', ('quack/',),
1378
'error', ('NotStacked',))
1379
client.add_expected_call(
1380
'Branch.last_revision_info', ('quack/',),
1381
'success', ('ok', '1', 'rev-tip'))
1382
client.add_expected_call(
1383
'Branch.get_config_file', ('quack/',),
1384
'success', ('ok',), '')
1385
transport.mkdir('quack')
1386
transport = transport.clone('quack')
1387
branch = self.make_remote_branch(transport, client)
1388
result = branch.heads_to_fetch()
1389
self.assertFinished(client)
1390
self.assertEqual((set(['rev-tip']), set()), result)
1392
def test_uses_last_revision_info_and_tags_when_set(self):
1393
transport = MemoryTransport()
1394
client = FakeClient(transport.base)
1395
client.add_expected_call(
1396
'Branch.get_stacked_on_url', ('quack/',),
1397
'error', ('NotStacked',))
1398
client.add_expected_call(
1399
'Branch.last_revision_info', ('quack/',),
1400
'success', ('ok', '1', 'rev-tip'))
1401
client.add_expected_call(
1402
'Branch.get_config_file', ('quack/',),
1403
'success', ('ok',), 'branch.fetch_tags = True')
1404
# XXX: this will break if the default format's serialization of tags
1405
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1406
client.add_expected_call(
1407
'Branch.get_tags_bytes', ('quack/',),
1408
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1409
transport.mkdir('quack')
1410
transport = transport.clone('quack')
1411
branch = self.make_remote_branch(transport, client)
1412
result = branch.heads_to_fetch()
1413
self.assertFinished(client)
1415
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1417
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1418
transport = MemoryTransport()
1419
client = FakeClient(transport.base)
1420
client.add_expected_call(
1421
'Branch.get_stacked_on_url', ('quack/',),
1422
'error', ('NotStacked',))
1423
client.add_expected_call(
1424
'Branch.heads_to_fetch', ('quack/',),
1425
'success', (['tip'], ['tagged-1', 'tagged-2']))
1426
transport.mkdir('quack')
1427
transport = transport.clone('quack')
1428
branch = self.make_remote_branch(transport, client)
1429
branch._format._use_default_local_heads_to_fetch = lambda: False
1430
result = branch.heads_to_fetch()
1431
self.assertFinished(client)
1432
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1434
def make_branch_with_tags(self):
1435
self.setup_smart_server_with_call_log()
1436
# Make a branch with a single revision.
1437
builder = self.make_branch_builder('foo')
1438
builder.start_series()
1439
builder.build_snapshot('tip', None, [
1440
('add', ('', 'root-id', 'directory', ''))])
1441
builder.finish_series()
1442
branch = builder.get_branch()
1443
# Add two tags to that branch
1444
branch.tags.set_tag('tag-1', 'rev-1')
1445
branch.tags.set_tag('tag-2', 'rev-2')
1448
def test_backwards_compatible(self):
1449
br = self.make_branch_with_tags()
1450
br.get_config_stack().set('branch.fetch_tags', True)
1451
self.addCleanup(br.lock_read().unlock)
1452
# Disable the heads_to_fetch verb
1453
verb = 'Branch.heads_to_fetch'
1454
self.disable_verb(verb)
1455
self.reset_smart_call_log()
1456
result = br.heads_to_fetch()
1457
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1459
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1460
[call.call.method for call in self.hpss_calls])
1462
def test_backwards_compatible_no_tags(self):
1463
br = self.make_branch_with_tags()
1464
br.get_config_stack().set('branch.fetch_tags', False)
1465
self.addCleanup(br.lock_read().unlock)
1466
# Disable the heads_to_fetch verb
1467
verb = 'Branch.heads_to_fetch'
1468
self.disable_verb(verb)
1469
self.reset_smart_call_log()
1470
result = br.heads_to_fetch()
1471
self.assertEqual((set(['tip']), set()), result)
1473
['Branch.last_revision_info'],
1474
[call.call.method for call in self.hpss_calls])
1477
1121
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1479
1123
def test_empty_branch(self):
2012
1636
self.addCleanup(branch.unlock)
2013
1637
self.reset_smart_call_log()
2014
1638
branch._get_config().set_option('value', 'name')
2015
self.assertLength(11, self.hpss_calls)
1639
self.assertLength(10, self.hpss_calls)
2016
1640
self.assertEqual('value', branch._get_config().get_option('name'))
2018
def test_backwards_compat_set_option_with_dict(self):
2019
self.setup_smart_server_with_call_log()
2020
branch = self.make_branch('.')
2021
verb = 'Branch.set_config_option_dict'
2022
self.disable_verb(verb)
2024
self.addCleanup(branch.unlock)
2025
self.reset_smart_call_log()
2026
config = branch._get_config()
2027
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2028
config.set_option(value_dict, 'name')
2029
self.assertLength(11, self.hpss_calls)
2030
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2033
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2035
def test_get_branch_conf(self):
2036
# in an empty branch we decode the response properly
2037
client = FakeClient()
2038
client.add_expected_call(
2039
'Branch.get_stacked_on_url', ('memory:///',),
2040
'error', ('NotStacked',),)
2041
client.add_success_response_with_body('# config file body', 'ok')
2042
transport = MemoryTransport()
2043
branch = self.make_remote_branch(transport, client)
2044
config = branch.get_config_stack()
2046
config.get("log_format")
2048
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2049
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2052
def test_set_branch_conf(self):
2053
client = FakeClient()
2054
client.add_expected_call(
2055
'Branch.get_stacked_on_url', ('memory:///',),
2056
'error', ('NotStacked',),)
2057
client.add_expected_call(
2058
'Branch.lock_write', ('memory:///', '', ''),
2059
'success', ('ok', 'branch token', 'repo token'))
2060
client.add_expected_call(
2061
'Branch.get_config_file', ('memory:///', ),
2062
'success', ('ok', ), "# line 1\n")
2063
client.add_expected_call(
2064
'Branch.get_config_file', ('memory:///', ),
2065
'success', ('ok', ), "# line 1\n")
2066
client.add_expected_call(
2067
'Branch.put_config_file', ('memory:///', 'branch token',
2070
client.add_expected_call(
2071
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2073
transport = MemoryTransport()
2074
branch = self.make_remote_branch(transport, client)
2076
config = branch.get_config_stack()
2077
config.set('email', 'The Dude <lebowski@example.com>')
2079
self.assertFinished(client)
2081
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2082
('call', 'Branch.lock_write', ('memory:///', '', '')),
2083
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2084
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2085
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2086
('memory:///', 'branch token', 'repo token'),
2087
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2088
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
2092
1643
class TestBranchLockWrite(RemoteBranchTestCase):
2107
1658
self.assertFinished(client)
2110
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2112
def test_simple(self):
2113
transport = MemoryTransport()
2114
client = FakeClient(transport.base)
2115
client.add_expected_call(
2116
'Branch.get_stacked_on_url', ('quack/',),
2117
'error', ('NotStacked',),)
2118
client.add_expected_call(
2119
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2120
'success', ('ok', '0',),)
2121
client.add_expected_call(
2122
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2123
'error', ('NoSuchRevision', 'unknown',),)
2124
transport.mkdir('quack')
2125
transport = transport.clone('quack')
2126
branch = self.make_remote_branch(transport, client)
2127
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2128
self.assertRaises(errors.NoSuchRevision,
2129
branch.revision_id_to_revno, 'unknown')
2130
self.assertFinished(client)
2132
def test_dotted(self):
2133
transport = MemoryTransport()
2134
client = FakeClient(transport.base)
2135
client.add_expected_call(
2136
'Branch.get_stacked_on_url', ('quack/',),
2137
'error', ('NotStacked',),)
2138
client.add_expected_call(
2139
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2140
'success', ('ok', '0',),)
2141
client.add_expected_call(
2142
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2143
'error', ('NoSuchRevision', 'unknown',),)
2144
transport.mkdir('quack')
2145
transport = transport.clone('quack')
2146
branch = self.make_remote_branch(transport, client)
2147
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2148
self.assertRaises(errors.NoSuchRevision,
2149
branch.revision_id_to_dotted_revno, 'unknown')
2150
self.assertFinished(client)
2152
def test_dotted_no_smart_verb(self):
2153
self.setup_smart_server_with_call_log()
2154
branch = self.make_branch('.')
2155
self.disable_verb('Branch.revision_id_to_revno')
2156
self.reset_smart_call_log()
2157
self.assertEqual((0, ),
2158
branch.revision_id_to_dotted_revno('null:'))
2159
self.assertLength(8, self.hpss_calls)
2162
1661
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
2164
1663
def test__get_config(self):
2407
class TestRepositoryBreakLock(TestRemoteRepository):
2409
def test_break_lock(self):
2410
transport_path = 'quack'
2411
repo, client = self.setup_fake_client_and_repository(transport_path)
2412
client.add_success_response('ok')
2415
[('call', 'Repository.break_lock', ('quack/',))],
2419
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2421
def test_get_serializer_format(self):
2422
transport_path = 'hill'
2423
repo, client = self.setup_fake_client_and_repository(transport_path)
2424
client.add_success_response('ok', '7')
2425
self.assertEqual('7', repo.get_serializer_format())
2427
[('call', 'VersionedFileRepository.get_serializer_format',
2432
class TestRepositoryReconcile(TestRemoteRepository):
2434
def test_reconcile(self):
2435
transport_path = 'hill'
2436
repo, client = self.setup_fake_client_and_repository(transport_path)
2437
body = ("garbage_inventories: 2\n"
2438
"inconsistent_parents: 3\n")
2439
client.add_expected_call(
2440
'Repository.lock_write', ('hill/', ''),
2441
'success', ('ok', 'a token'))
2442
client.add_success_response_with_body(body, 'ok')
2443
reconciler = repo.reconcile()
2445
[('call', 'Repository.lock_write', ('hill/', '')),
2446
('call_expecting_body', 'Repository.reconcile',
2447
('hill/', 'a token'))],
2449
self.assertEqual(2, reconciler.garbage_inventories)
2450
self.assertEqual(3, reconciler.inconsistent_parents)
2453
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2455
def test_text(self):
2456
# ('ok',), body with signature text
2457
transport_path = 'quack'
2458
repo, client = self.setup_fake_client_and_repository(transport_path)
2459
client.add_success_response_with_body(
2461
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2463
[('call_expecting_body', 'Repository.get_revision_signature_text',
2464
('quack/', 'revid'))],
2467
def test_no_signature(self):
2468
transport_path = 'quick'
2469
repo, client = self.setup_fake_client_and_repository(transport_path)
2470
client.add_error_response('nosuchrevision', 'unknown')
2471
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2474
[('call_expecting_body', 'Repository.get_revision_signature_text',
2475
('quick/', 'unknown'))],
2479
1881
class TestRepositoryGetGraph(TestRemoteRepository):
2481
1883
def test_get_graph(self):
3070
class TestRepositoryWriteGroups(TestRemoteRepository):
3072
def test_start_write_group(self):
3073
transport_path = 'quack'
3074
repo, client = self.setup_fake_client_and_repository(transport_path)
3075
client.add_expected_call(
3076
'Repository.lock_write', ('quack/', ''),
3077
'success', ('ok', 'a token'))
3078
client.add_expected_call(
3079
'Repository.start_write_group', ('quack/', 'a token'),
3080
'success', ('ok', ('token1', )))
3082
repo.start_write_group()
3084
def test_start_write_group_unsuspendable(self):
3085
# Some repositories do not support suspending write
3086
# groups. For those, fall back to the "real" repository.
3087
transport_path = 'quack'
3088
repo, client = self.setup_fake_client_and_repository(transport_path)
3089
def stub_ensure_real():
3090
client._calls.append(('_ensure_real',))
3091
repo._real_repository = _StubRealPackRepository(client._calls)
3092
repo._ensure_real = stub_ensure_real
3093
client.add_expected_call(
3094
'Repository.lock_write', ('quack/', ''),
3095
'success', ('ok', 'a token'))
3096
client.add_expected_call(
3097
'Repository.start_write_group', ('quack/', 'a token'),
3098
'error', ('UnsuspendableWriteGroup',))
3100
repo.start_write_group()
3101
self.assertEqual(client._calls[-2:], [
3103
('start_write_group',)])
3105
def test_commit_write_group(self):
3106
transport_path = 'quack'
3107
repo, client = self.setup_fake_client_and_repository(transport_path)
3108
client.add_expected_call(
3109
'Repository.lock_write', ('quack/', ''),
3110
'success', ('ok', 'a token'))
3111
client.add_expected_call(
3112
'Repository.start_write_group', ('quack/', 'a token'),
3113
'success', ('ok', ['token1']))
3114
client.add_expected_call(
3115
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3118
repo.start_write_group()
3119
repo.commit_write_group()
3121
def test_abort_write_group(self):
3122
transport_path = 'quack'
3123
repo, client = self.setup_fake_client_and_repository(transport_path)
3124
client.add_expected_call(
3125
'Repository.lock_write', ('quack/', ''),
3126
'success', ('ok', 'a token'))
3127
client.add_expected_call(
3128
'Repository.start_write_group', ('quack/', 'a token'),
3129
'success', ('ok', ['token1']))
3130
client.add_expected_call(
3131
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3134
repo.start_write_group()
3135
repo.abort_write_group(False)
3137
def test_suspend_write_group(self):
3138
transport_path = 'quack'
3139
repo, client = self.setup_fake_client_and_repository(transport_path)
3140
self.assertEqual([], repo.suspend_write_group())
3142
def test_resume_write_group(self):
3143
transport_path = 'quack'
3144
repo, client = self.setup_fake_client_and_repository(transport_path)
3145
client.add_expected_call(
3146
'Repository.lock_write', ('quack/', ''),
3147
'success', ('ok', 'a token'))
3148
client.add_expected_call(
3149
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3152
repo.resume_write_group(['token1'])
3155
2303
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
3157
2305
def test_backwards_compat(self):
3775
2869
expected_error = errors.PermissionDenied(path, extra)
3776
2870
self.assertEqual(expected_error, translated_error)
3778
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3780
def test_NoSuchFile_context_path(self):
3781
local_path = "local path"
3782
translated_error = self.translateTuple(('ReadError', "remote path"),
3784
expected_error = errors.ReadError(local_path)
3785
self.assertEqual(expected_error, translated_error)
3787
def test_NoSuchFile_without_context(self):
3788
remote_path = "remote path"
3789
translated_error = self.translateTuple(('ReadError', remote_path))
3790
expected_error = errors.ReadError(remote_path)
3791
self.assertEqual(expected_error, translated_error)
3793
def test_ReadOnlyError(self):
3794
translated_error = self.translateTuple(('ReadOnlyError',))
3795
expected_error = errors.TransportNotPossible("readonly transport")
3796
self.assertEqual(expected_error, translated_error)
3798
def test_MemoryError(self):
3799
translated_error = self.translateTuple(('MemoryError',))
3800
self.assertStartsWith(str(translated_error),
3801
"remote server out of memory")
3803
def test_generic_IndexError_no_classname(self):
3804
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3805
translated_error = self.translateErrorFromSmartServer(err)
3806
expected_error = errors.UnknownErrorFromSmartServer(err)
3807
self.assertEqual(expected_error, translated_error)
3809
# GZ 2011-03-02: TODO test generic non-ascii error string
3811
def test_generic_KeyError(self):
3812
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3813
translated_error = self.translateErrorFromSmartServer(err)
3814
expected_error = errors.UnknownErrorFromSmartServer(err)
3815
self.assertEqual(expected_error, translated_error)
3818
2873
class TestErrorTranslationRobustness(TestErrorTranslationBase):
3819
2874
"""Unit tests for bzrlib.remote._translate_error's robustness.
4064
3117
def test_copy_content_into_avoids_revision_history(self):
4065
3118
local = self.make_branch('local')
4066
builder = self.make_branch_builder('remote')
4067
builder.build_commit(message="Commit.")
3119
remote_backing_tree = self.make_branch_and_tree('remote')
3120
remote_backing_tree.commit("Commit.")
4068
3121
remote_branch_url = self.smart_server.get_url() + 'remote'
4069
3122
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4070
3123
local.repository.fetch(remote_branch.repository)
4071
3124
self.hpss_calls = []
4072
3125
remote_branch.copy_content_into(local)
4073
3126
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4075
def test_fetch_everything_needs_just_one_call(self):
4076
local = self.make_branch('local')
4077
builder = self.make_branch_builder('remote')
4078
builder.build_commit(message="Commit.")
4079
remote_branch_url = self.smart_server.get_url() + 'remote'
4080
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4081
self.hpss_calls = []
4082
local.repository.fetch(
4083
remote_branch.repository,
4084
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4085
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4087
def override_verb(self, verb_name, verb):
4088
request_handlers = request.request_handlers
4089
orig_verb = request_handlers.get(verb_name)
4090
orig_info = request_handlers.get_info(verb_name)
4091
request_handlers.register(verb_name, verb, override_existing=True)
4092
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4093
override_existing=True, info=orig_info)
4095
def test_fetch_everything_backwards_compat(self):
4096
"""Can fetch with EverythingResult even with pre 2.4 servers.
4098
Pre-2.4 do not support 'everything' searches with the
4099
Repository.get_stream_1.19 verb.
4102
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4103
"""A version of the Repository.get_stream_1.19 verb patched to
4104
reject 'everything' searches the way 2.3 and earlier do.
4106
def recreate_search(self, repository, search_bytes,
4107
discard_excess=False):
4108
verb_log.append(search_bytes.split('\n', 1)[0])
4109
if search_bytes == 'everything':
4111
request.FailedSmartServerResponse(('BadSearch',)))
4112
return super(OldGetStreamVerb,
4113
self).recreate_search(repository, search_bytes,
4114
discard_excess=discard_excess)
4115
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4116
local = self.make_branch('local')
4117
builder = self.make_branch_builder('remote')
4118
builder.build_commit(message="Commit.")
4119
remote_branch_url = self.smart_server.get_url() + 'remote'
4120
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4121
self.hpss_calls = []
4122
local.repository.fetch(
4123
remote_branch.repository,
4124
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4125
# make sure the overridden verb was used
4126
self.assertLength(1, verb_log)
4127
# more than one HPSS call is needed, but because it's a VFS callback
4128
# its hard to predict exactly how many.
4129
self.assertTrue(len(self.hpss_calls) > 1)
4132
class TestUpdateBoundBranchWithModifiedBoundLocation(
4133
tests.TestCaseWithTransport):
4134
"""Ensure correct handling of bound_location modifications.
4136
This is tested against a smart server as http://pad.lv/786980 was about a
4137
ReadOnlyError (write attempt during a read-only transaction) which can only
4138
happen in this context.
4142
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4143
self.transport_server = test_server.SmartTCPServer_for_testing
4145
def make_master_and_checkout(self, master_name, checkout_name):
4146
# Create the master branch and its associated checkout
4147
self.master = self.make_branch_and_tree(master_name)
4148
self.checkout = self.master.branch.create_checkout(checkout_name)
4149
# Modify the master branch so there is something to update
4150
self.master.commit('add stuff')
4151
self.last_revid = self.master.commit('even more stuff')
4152
self.bound_location = self.checkout.branch.get_bound_location()
4154
def assertUpdateSucceeds(self, new_location):
4155
self.checkout.branch.set_bound_location(new_location)
4156
self.checkout.update()
4157
self.assertEqual(self.last_revid, self.checkout.last_revision())
4159
def test_without_final_slash(self):
4160
self.make_master_and_checkout('master', 'checkout')
4161
# For unclear reasons some users have a bound_location without a final
4162
# '/', simulate that by forcing such a value
4163
self.assertEndsWith(self.bound_location, '/')
4164
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4166
def test_plus_sign(self):
4167
self.make_master_and_checkout('+master', 'checkout')
4168
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4170
def test_tilda(self):
4171
# Embed ~ in the middle of the path just to avoid any $HOME
4173
self.make_master_and_checkout('mas~ter', 'checkout')
4174
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4177
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4179
def test_no_context(self):
4180
class OutOfCoffee(errors.BzrError):
4181
"""A dummy exception for testing."""
4183
def __init__(self, urgency):
4184
self.urgency = urgency
4185
remote.no_context_error_translators.register("OutOfCoffee",
4186
lambda err: OutOfCoffee(err.error_args[0]))
4187
transport = MemoryTransport()
4188
client = FakeClient(transport.base)
4189
client.add_expected_call(
4190
'Branch.get_stacked_on_url', ('quack/',),
4191
'error', ('NotStacked',))
4192
client.add_expected_call(
4193
'Branch.last_revision_info',
4195
'error', ('OutOfCoffee', 'low'))
4196
transport.mkdir('quack')
4197
transport = transport.clone('quack')
4198
branch = self.make_remote_branch(transport, client)
4199
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4200
self.assertFinished(client)
4202
def test_with_context(self):
4203
class OutOfTea(errors.BzrError):
4204
def __init__(self, branch, urgency):
4205
self.branch = branch
4206
self.urgency = urgency
4207
remote.error_translators.register("OutOfTea",
4208
lambda err, find, path: OutOfTea(err.error_args[0],
4210
transport = MemoryTransport()
4211
client = FakeClient(transport.base)
4212
client.add_expected_call(
4213
'Branch.get_stacked_on_url', ('quack/',),
4214
'error', ('NotStacked',))
4215
client.add_expected_call(
4216
'Branch.last_revision_info',
4218
'error', ('OutOfTea', 'low'))
4219
transport.mkdir('quack')
4220
transport = transport.clone('quack')
4221
branch = self.make_remote_branch(transport, client)
4222
self.assertRaises(OutOfTea, branch.last_revision_info)
4223
self.assertFinished(client)
4226
class TestRepositoryPack(TestRemoteRepository):
4228
def test_pack(self):
4229
transport_path = 'quack'
4230
repo, client = self.setup_fake_client_and_repository(transport_path)
4231
client.add_expected_call(
4232
'Repository.lock_write', ('quack/', ''),
4233
'success', ('ok', 'token'))
4234
client.add_expected_call(
4235
'Repository.pack', ('quack/', 'token', 'False'),
4236
'success', ('ok',), )
4237
client.add_expected_call(
4238
'Repository.unlock', ('quack/', 'token'),
4239
'success', ('ok', ))
4242
def test_pack_with_hint(self):
4243
transport_path = 'quack'
4244
repo, client = self.setup_fake_client_and_repository(transport_path)
4245
client.add_expected_call(
4246
'Repository.lock_write', ('quack/', ''),
4247
'success', ('ok', 'token'))
4248
client.add_expected_call(
4249
'Repository.pack', ('quack/', 'token', 'False'),
4250
'success', ('ok',), )
4251
client.add_expected_call(
4252
'Repository.unlock', ('quack/', 'token', 'False'),
4253
'success', ('ok', ))
4254
repo.pack(['hinta', 'hintb'])
4257
class TestRepositoryIterInventories(TestRemoteRepository):
4258
"""Test Repository.iter_inventories."""
4260
def _serialize_inv_delta(self, old_name, new_name, delta):
4261
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4262
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4264
def test_single_empty(self):
4265
transport_path = 'quack'
4266
repo, client = self.setup_fake_client_and_repository(transport_path)
4267
fmt = controldir.format_registry.get('2a')().repository_format
4269
stream = [('inventory-deltas', [
4270
versionedfile.FulltextContentFactory('somerevid', None, None,
4271
self._serialize_inv_delta('null:', 'somerevid', []))])]
4272
client.add_expected_call(
4273
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4274
'success', ('ok', ),
4275
_stream_to_byte_stream(stream, fmt))
4276
ret = list(repo.iter_inventories(["somerevid"]))
4277
self.assertLength(1, ret)
4279
self.assertEqual("somerevid", inv.revision_id)
4281
def test_empty(self):
4282
transport_path = 'quack'
4283
repo, client = self.setup_fake_client_and_repository(transport_path)
4284
ret = list(repo.iter_inventories([]))
4285
self.assertEqual(ret, [])
4287
def test_missing(self):
4288
transport_path = 'quack'
4289
repo, client = self.setup_fake_client_and_repository(transport_path)
4290
client.add_expected_call(
4291
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4292
'success', ('ok', ), iter([]))
4293
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(