53
61
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,
63
from ..bzr import groupcompress_repo, knitpack_repo
64
from ..revision import (
68
from ..sixish import (
71
from ..smart import medium, request
72
from ..smart.client import _SmartClient
73
from ..smart.repository import (
74
SmartServerRepositoryGetParentMap,
75
SmartServerRepositoryGetStream_1_19,
76
_stream_to_byte_stream,
66
from bzrlib.transport import get_transport
67
from bzrlib.transport.memory import MemoryTransport
68
from bzrlib.transport.remote import (
81
from .scenarios import load_tests_apply_scenarios
82
from ..transport.memory import MemoryTransport
83
from ..transport.remote import (
70
85
RemoteSSHTransport,
71
86
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 = [
90
load_tests = load_tests_apply_scenarios
93
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
97
{'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):
99
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
103
super(BasicRemoteObjectTests, self).setUp()
89
104
self.transport = self.get_transport()
90
105
# make a branch that can be opened over the smart transport
91
106
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
107
self.addCleanup(self.transport.disconnect)
97
109
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
110
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
111
self.assertIsInstance(b, BzrDir)
101
113
def test_open_remote_branch(self):
102
114
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
115
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
116
branch = b.open_branch()
105
117
self.assertIsInstance(branch, Branch)
480
485
self.assertEqual(None, result._branch_format)
481
486
self.assertFinished(client)
488
def test_unknown(self):
489
transport = self.get_transport('quack')
490
referenced = self.make_branch('referenced')
491
expected = referenced.controldir.cloning_metadir()
492
client = FakeClient(transport.base)
493
client.add_expected_call(
494
'BzrDir.cloning_metadir', ('quack/', 'False'),
495
'success', ('unknown', 'unknown', ('branch', ''))),
496
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
498
self.assertRaises(errors.UnknownFormatError, a_controldir.cloning_metadir)
501
class TestBzrDirCheckoutMetaDir(TestRemote):
503
def test__get_checkout_format(self):
504
transport = MemoryTransport()
505
client = FakeClient(transport.base)
506
reference_bzrdir_format = controldir.format_registry.get('default')()
507
control_name = reference_bzrdir_format.network_name()
508
client.add_expected_call(
509
'BzrDir.checkout_metadir', ('quack/', ),
510
'success', (control_name, '', ''))
511
transport.mkdir('quack')
512
transport = transport.clone('quack')
513
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
515
result = a_controldir.checkout_metadir()
516
# We should have got a reference control dir with default branch and
517
# repository formats.
518
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
519
self.assertEqual(None, result._repository_format)
520
self.assertEqual(None, result._branch_format)
521
self.assertFinished(client)
523
def test_unknown_format(self):
524
transport = MemoryTransport()
525
client = FakeClient(transport.base)
526
client.add_expected_call(
527
'BzrDir.checkout_metadir', ('quack/',),
528
'success', ('dontknow', '', ''))
529
transport.mkdir('quack')
530
transport = transport.clone('quack')
531
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
533
self.assertRaises(errors.UnknownFormatError,
534
a_controldir.checkout_metadir)
535
self.assertFinished(client)
538
class TestBzrDirGetBranches(TestRemote):
540
def test_get_branches(self):
541
transport = MemoryTransport()
542
client = FakeClient(transport.base)
543
reference_bzrdir_format = controldir.format_registry.get('default')()
544
branch_name = reference_bzrdir_format.get_branch_format().network_name()
545
client.add_success_response_with_body(
547
"foo": ("branch", branch_name),
548
"": ("branch", branch_name)}), "success")
549
client.add_success_response(
550
'ok', '', 'no', 'no', 'no',
551
reference_bzrdir_format.repository_format.network_name())
552
client.add_error_response('NotStacked')
553
client.add_success_response(
554
'ok', '', 'no', 'no', 'no',
555
reference_bzrdir_format.repository_format.network_name())
556
client.add_error_response('NotStacked')
557
transport.mkdir('quack')
558
transport = transport.clone('quack')
559
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
561
result = a_controldir.get_branches()
562
self.assertEqual({"", "foo"}, set(result.keys()))
564
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
565
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
566
('call', 'Branch.get_stacked_on_url', ('quack/', )),
567
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
568
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
572
class TestBzrDirDestroyBranch(TestRemote):
574
def test_destroy_default(self):
575
transport = self.get_transport('quack')
576
referenced = self.make_branch('referenced')
577
client = FakeClient(transport.base)
578
client.add_expected_call(
579
'BzrDir.destroy_branch', ('quack/', ),
581
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
583
a_controldir.destroy_branch()
584
self.assertFinished(client)
587
class TestBzrDirHasWorkingTree(TestRemote):
589
def test_has_workingtree(self):
590
transport = self.get_transport('quack')
591
client = FakeClient(transport.base)
592
client.add_expected_call(
593
'BzrDir.has_workingtree', ('quack/',),
594
'success', ('yes',)),
595
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
597
self.assertTrue(a_controldir.has_workingtree())
598
self.assertFinished(client)
600
def test_no_workingtree(self):
601
transport = self.get_transport('quack')
602
client = FakeClient(transport.base)
603
client.add_expected_call(
604
'BzrDir.has_workingtree', ('quack/',),
606
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
608
self.assertFalse(a_controldir.has_workingtree())
609
self.assertFinished(client)
612
class TestBzrDirDestroyRepository(TestRemote):
614
def test_destroy_repository(self):
615
transport = self.get_transport('quack')
616
client = FakeClient(transport.base)
617
client.add_expected_call(
618
'BzrDir.destroy_repository', ('quack/',),
620
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
622
a_controldir.destroy_repository()
623
self.assertFinished(client)
484
626
class TestBzrDirOpen(TestRemote):
715
857
'BzrDir.create_branch', ('quack/', network_name),
716
858
'success', ('ok', network_name, '', 'no', 'no', 'yes',
717
859
reference_repo_name))
718
a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
720
branch = a_bzrdir.create_branch()
860
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
862
branch = a_controldir.create_branch()
863
# We should have got a remote branch
864
self.assertIsInstance(branch, remote.RemoteBranch)
865
# its format should have the settings from the response
866
format = branch._format
867
self.assertEqual(network_name, format.network_name())
869
def test_already_open_repo_and_reused_medium(self):
870
"""Bug 726584: create_branch(..., repository=repo) should work
871
regardless of what the smart medium's base URL is.
873
self.transport_server = test_server.SmartTCPServer_for_testing
874
transport = self.get_transport('.')
875
repo = self.make_repository('quack')
876
# Client's medium rooted a transport root (not at the bzrdir)
877
client = FakeClient(transport.base)
878
transport = transport.clone('quack')
879
reference_bzrdir_format = controldir.format_registry.get('default')()
880
reference_format = reference_bzrdir_format.get_branch_format()
881
network_name = reference_format.network_name()
882
reference_repo_fmt = reference_bzrdir_format.repository_format
883
reference_repo_name = reference_repo_fmt.network_name()
884
client.add_expected_call(
885
'BzrDir.create_branch', ('extra/quack/', network_name),
886
'success', ('ok', network_name, '', 'no', 'no', 'yes',
887
reference_repo_name))
888
a_controldir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
890
branch = a_controldir.create_branch(repository=repo)
721
891
# We should have got a remote branch
722
892
self.assertIsInstance(branch, remote.RemoteBranch)
723
893
# its format should have the settings from the response
967
1141
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1144
class TestBranchBreakLock(RemoteBranchTestCase):
1146
def test_break_lock(self):
1147
transport_path = 'quack'
1148
transport = MemoryTransport()
1149
client = FakeClient(transport.base)
1150
client.add_expected_call(
1151
'Branch.get_stacked_on_url', ('quack/',),
1152
'error', ('NotStacked',))
1153
client.add_expected_call(
1154
'Branch.break_lock', ('quack/',),
1156
transport.mkdir('quack')
1157
transport = transport.clone('quack')
1158
branch = self.make_remote_branch(transport, client)
1160
self.assertFinished(client)
1163
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1165
def test_get_physical_lock_status_yes(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/',),
1173
'success', ('yes',))
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(True, result)
1181
def test_get_physical_lock_status_no(self):
1182
transport = MemoryTransport()
1183
client = FakeClient(transport.base)
1184
client.add_expected_call(
1185
'Branch.get_stacked_on_url', ('quack/',),
1186
'error', ('NotStacked',))
1187
client.add_expected_call(
1188
'Branch.get_physical_lock_status', ('quack/',),
1190
transport.mkdir('quack')
1191
transport = transport.clone('quack')
1192
branch = self.make_remote_branch(transport, client)
1193
result = branch.get_physical_lock_status()
1194
self.assertFinished(client)
1195
self.assertEqual(False, result)
970
1198
class TestBranchGetParent(RemoteBranchTestCase):
972
1200
def test_no_parent(self):
1143
1371
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1374
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1376
def test_uses_last_revision_info_and_tags_by_default(self):
1377
transport = MemoryTransport()
1378
client = FakeClient(transport.base)
1379
client.add_expected_call(
1380
'Branch.get_stacked_on_url', ('quack/',),
1381
'error', ('NotStacked',))
1382
client.add_expected_call(
1383
'Branch.last_revision_info', ('quack/',),
1384
'success', ('ok', '1', 'rev-tip'))
1385
client.add_expected_call(
1386
'Branch.get_config_file', ('quack/',),
1387
'success', ('ok',), '')
1388
transport.mkdir('quack')
1389
transport = transport.clone('quack')
1390
branch = self.make_remote_branch(transport, client)
1391
result = branch.heads_to_fetch()
1392
self.assertFinished(client)
1393
self.assertEqual(({'rev-tip'}, set()), result)
1395
def test_uses_last_revision_info_and_tags_when_set(self):
1396
transport = MemoryTransport()
1397
client = FakeClient(transport.base)
1398
client.add_expected_call(
1399
'Branch.get_stacked_on_url', ('quack/',),
1400
'error', ('NotStacked',))
1401
client.add_expected_call(
1402
'Branch.last_revision_info', ('quack/',),
1403
'success', ('ok', '1', 'rev-tip'))
1404
client.add_expected_call(
1405
'Branch.get_config_file', ('quack/',),
1406
'success', ('ok',), 'branch.fetch_tags = True')
1407
# XXX: this will break if the default format's serialization of tags
1408
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1409
client.add_expected_call(
1410
'Branch.get_tags_bytes', ('quack/',),
1411
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1412
transport.mkdir('quack')
1413
transport = transport.clone('quack')
1414
branch = self.make_remote_branch(transport, client)
1415
result = branch.heads_to_fetch()
1416
self.assertFinished(client)
1418
({'rev-tip'}, {'rev-foo', 'rev-bar'}), result)
1420
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1421
transport = MemoryTransport()
1422
client = FakeClient(transport.base)
1423
client.add_expected_call(
1424
'Branch.get_stacked_on_url', ('quack/',),
1425
'error', ('NotStacked',))
1426
client.add_expected_call(
1427
'Branch.heads_to_fetch', ('quack/',),
1428
'success', (['tip'], ['tagged-1', 'tagged-2']))
1429
transport.mkdir('quack')
1430
transport = transport.clone('quack')
1431
branch = self.make_remote_branch(transport, client)
1432
branch._format._use_default_local_heads_to_fetch = lambda: False
1433
result = branch.heads_to_fetch()
1434
self.assertFinished(client)
1435
self.assertEqual(({'tip'}, {'tagged-1', 'tagged-2'}), result)
1437
def make_branch_with_tags(self):
1438
self.setup_smart_server_with_call_log()
1439
# Make a branch with a single revision.
1440
builder = self.make_branch_builder('foo')
1441
builder.start_series()
1442
builder.build_snapshot('tip', None, [
1443
('add', ('', 'root-id', 'directory', ''))])
1444
builder.finish_series()
1445
branch = builder.get_branch()
1446
# Add two tags to that branch
1447
branch.tags.set_tag('tag-1', 'rev-1')
1448
branch.tags.set_tag('tag-2', 'rev-2')
1451
def test_backwards_compatible(self):
1452
br = self.make_branch_with_tags()
1453
br.get_config_stack().set('branch.fetch_tags', True)
1454
self.addCleanup(br.lock_read().unlock)
1455
# Disable the heads_to_fetch verb
1456
verb = 'Branch.heads_to_fetch'
1457
self.disable_verb(verb)
1458
self.reset_smart_call_log()
1459
result = br.heads_to_fetch()
1460
self.assertEqual(({'tip'}, {'rev-1', 'rev-2'}), result)
1462
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1463
[call.call.method for call in self.hpss_calls])
1465
def test_backwards_compatible_no_tags(self):
1466
br = self.make_branch_with_tags()
1467
br.get_config_stack().set('branch.fetch_tags', False)
1468
self.addCleanup(br.lock_read().unlock)
1469
# Disable the heads_to_fetch verb
1470
verb = 'Branch.heads_to_fetch'
1471
self.disable_verb(verb)
1472
self.reset_smart_call_log()
1473
result = br.heads_to_fetch()
1474
self.assertEqual(({'tip'}, set()), result)
1476
['Branch.last_revision_info'],
1477
[call.call.method for call in self.hpss_calls])
1146
1480
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1482
def test_empty_branch(self):
1661
2015
self.addCleanup(branch.unlock)
1662
2016
self.reset_smart_call_log()
1663
2017
branch._get_config().set_option('value', 'name')
1664
self.assertLength(10, self.hpss_calls)
2018
self.assertLength(11, self.hpss_calls)
1665
2019
self.assertEqual('value', branch._get_config().get_option('name'))
2021
def test_backwards_compat_set_option_with_dict(self):
2022
self.setup_smart_server_with_call_log()
2023
branch = self.make_branch('.')
2024
verb = 'Branch.set_config_option_dict'
2025
self.disable_verb(verb)
2027
self.addCleanup(branch.unlock)
2028
self.reset_smart_call_log()
2029
config = branch._get_config()
2030
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2031
config.set_option(value_dict, 'name')
2032
self.assertLength(11, self.hpss_calls)
2033
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2036
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2038
def test_get_branch_conf(self):
2039
# in an empty branch we decode the response properly
2040
client = FakeClient()
2041
client.add_expected_call(
2042
'Branch.get_stacked_on_url', ('memory:///',),
2043
'error', ('NotStacked',),)
2044
client.add_success_response_with_body('# config file body', 'ok')
2045
transport = MemoryTransport()
2046
branch = self.make_remote_branch(transport, client)
2047
config = branch.get_config_stack()
2049
config.get("log_format")
2051
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2052
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2055
def test_set_branch_conf(self):
2056
client = FakeClient()
2057
client.add_expected_call(
2058
'Branch.get_stacked_on_url', ('memory:///',),
2059
'error', ('NotStacked',),)
2060
client.add_expected_call(
2061
'Branch.lock_write', ('memory:///', '', ''),
2062
'success', ('ok', 'branch token', 'repo token'))
2063
client.add_expected_call(
2064
'Branch.get_config_file', ('memory:///', ),
2065
'success', ('ok', ), "# line 1\n")
2066
client.add_expected_call(
2067
'Branch.get_config_file', ('memory:///', ),
2068
'success', ('ok', ), "# line 1\n")
2069
client.add_expected_call(
2070
'Branch.put_config_file', ('memory:///', 'branch token',
2073
client.add_expected_call(
2074
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2076
transport = MemoryTransport()
2077
branch = self.make_remote_branch(transport, client)
2079
config = branch.get_config_stack()
2080
config.set('email', 'The Dude <lebowski@example.com>')
2082
self.assertFinished(client)
2084
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2085
('call', 'Branch.lock_write', ('memory:///', '', '')),
2086
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2087
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2088
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2089
('memory:///', 'branch token', 'repo token'),
2090
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2091
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2095
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2110
self.assertFinished(client)
2113
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2115
def test_simple(self):
2116
transport = MemoryTransport()
2117
client = FakeClient(transport.base)
2118
client.add_expected_call(
2119
'Branch.get_stacked_on_url', ('quack/',),
2120
'error', ('NotStacked',),)
2121
client.add_expected_call(
2122
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2123
'success', ('ok', '0',),)
2124
client.add_expected_call(
2125
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2126
'error', ('NoSuchRevision', 'unknown',),)
2127
transport.mkdir('quack')
2128
transport = transport.clone('quack')
2129
branch = self.make_remote_branch(transport, client)
2130
self.assertEqual(0, branch.revision_id_to_revno('null:'))
2131
self.assertRaises(errors.NoSuchRevision,
2132
branch.revision_id_to_revno, 'unknown')
2133
self.assertFinished(client)
2135
def test_dotted(self):
2136
transport = MemoryTransport()
2137
client = FakeClient(transport.base)
2138
client.add_expected_call(
2139
'Branch.get_stacked_on_url', ('quack/',),
2140
'error', ('NotStacked',),)
2141
client.add_expected_call(
2142
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2143
'success', ('ok', '0',),)
2144
client.add_expected_call(
2145
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2146
'error', ('NoSuchRevision', 'unknown',),)
2147
transport.mkdir('quack')
2148
transport = transport.clone('quack')
2149
branch = self.make_remote_branch(transport, client)
2150
self.assertEqual((0, ), branch.revision_id_to_dotted_revno('null:'))
2151
self.assertRaises(errors.NoSuchRevision,
2152
branch.revision_id_to_dotted_revno, 'unknown')
2153
self.assertFinished(client)
2155
def test_dotted_no_smart_verb(self):
2156
self.setup_smart_server_with_call_log()
2157
branch = self.make_branch('.')
2158
self.disable_verb('Branch.revision_id_to_revno')
2159
self.reset_smart_call_log()
2160
self.assertEqual((0, ),
2161
branch.revision_id_to_dotted_revno('null:'))
2162
self.assertLength(8, self.hpss_calls)
1686
2165
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2167
def test__get_config(self):
2410
class TestRepositoryBreakLock(TestRemoteRepository):
2412
def test_break_lock(self):
2413
transport_path = 'quack'
2414
repo, client = self.setup_fake_client_and_repository(transport_path)
2415
client.add_success_response('ok')
2418
[('call', 'Repository.break_lock', ('quack/',))],
2422
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2424
def test_get_serializer_format(self):
2425
transport_path = 'hill'
2426
repo, client = self.setup_fake_client_and_repository(transport_path)
2427
client.add_success_response('ok', '7')
2428
self.assertEqual('7', repo.get_serializer_format())
2430
[('call', 'VersionedFileRepository.get_serializer_format',
2435
class TestRepositoryReconcile(TestRemoteRepository):
2437
def test_reconcile(self):
2438
transport_path = 'hill'
2439
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
body = ("garbage_inventories: 2\n"
2441
"inconsistent_parents: 3\n")
2442
client.add_expected_call(
2443
'Repository.lock_write', ('hill/', ''),
2444
'success', ('ok', 'a token'))
2445
client.add_success_response_with_body(body, 'ok')
2446
reconciler = repo.reconcile()
2448
[('call', 'Repository.lock_write', ('hill/', '')),
2449
('call_expecting_body', 'Repository.reconcile',
2450
('hill/', 'a token'))],
2452
self.assertEqual(2, reconciler.garbage_inventories)
2453
self.assertEqual(3, reconciler.inconsistent_parents)
2456
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2458
def test_text(self):
2459
# ('ok',), body with signature text
2460
transport_path = 'quack'
2461
repo, client = self.setup_fake_client_and_repository(transport_path)
2462
client.add_success_response_with_body(
2464
self.assertEqual("THETEXT", repo.get_signature_text("revid"))
2466
[('call_expecting_body', 'Repository.get_revision_signature_text',
2467
('quack/', 'revid'))],
2470
def test_no_signature(self):
2471
transport_path = 'quick'
2472
repo, client = self.setup_fake_client_and_repository(transport_path)
2473
client.add_error_response('nosuchrevision', 'unknown')
2474
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2477
[('call_expecting_body', 'Repository.get_revision_signature_text',
2478
('quick/', 'unknown'))],
1906
2482
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2484
def test_get_graph(self):
3073
class TestRepositoryWriteGroups(TestRemoteRepository):
3075
def test_start_write_group(self):
3076
transport_path = 'quack'
3077
repo, client = self.setup_fake_client_and_repository(transport_path)
3078
client.add_expected_call(
3079
'Repository.lock_write', ('quack/', ''),
3080
'success', ('ok', 'a token'))
3081
client.add_expected_call(
3082
'Repository.start_write_group', ('quack/', 'a token'),
3083
'success', ('ok', ('token1', )))
3085
repo.start_write_group()
3087
def test_start_write_group_unsuspendable(self):
3088
# Some repositories do not support suspending write
3089
# groups. For those, fall back to the "real" repository.
3090
transport_path = 'quack'
3091
repo, client = self.setup_fake_client_and_repository(transport_path)
3092
def stub_ensure_real():
3093
client._calls.append(('_ensure_real',))
3094
repo._real_repository = _StubRealPackRepository(client._calls)
3095
repo._ensure_real = stub_ensure_real
3096
client.add_expected_call(
3097
'Repository.lock_write', ('quack/', ''),
3098
'success', ('ok', 'a token'))
3099
client.add_expected_call(
3100
'Repository.start_write_group', ('quack/', 'a token'),
3101
'error', ('UnsuspendableWriteGroup',))
3103
repo.start_write_group()
3104
self.assertEqual(client._calls[-2:], [
3106
('start_write_group',)])
3108
def test_commit_write_group(self):
3109
transport_path = 'quack'
3110
repo, client = self.setup_fake_client_and_repository(transport_path)
3111
client.add_expected_call(
3112
'Repository.lock_write', ('quack/', ''),
3113
'success', ('ok', 'a token'))
3114
client.add_expected_call(
3115
'Repository.start_write_group', ('quack/', 'a token'),
3116
'success', ('ok', ['token1']))
3117
client.add_expected_call(
3118
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3121
repo.start_write_group()
3122
repo.commit_write_group()
3124
def test_abort_write_group(self):
3125
transport_path = 'quack'
3126
repo, client = self.setup_fake_client_and_repository(transport_path)
3127
client.add_expected_call(
3128
'Repository.lock_write', ('quack/', ''),
3129
'success', ('ok', 'a token'))
3130
client.add_expected_call(
3131
'Repository.start_write_group', ('quack/', 'a token'),
3132
'success', ('ok', ['token1']))
3133
client.add_expected_call(
3134
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3137
repo.start_write_group()
3138
repo.abort_write_group(False)
3140
def test_suspend_write_group(self):
3141
transport_path = 'quack'
3142
repo, client = self.setup_fake_client_and_repository(transport_path)
3143
self.assertEqual([], repo.suspend_write_group())
3145
def test_resume_write_group(self):
3146
transport_path = 'quack'
3147
repo, client = self.setup_fake_client_and_repository(transport_path)
3148
client.add_expected_call(
3149
'Repository.lock_write', ('quack/', ''),
3150
'success', ('ok', 'a token'))
3151
client.add_expected_call(
3152
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3155
repo.resume_write_group(['token1'])
2329
3158
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3160
def test_backwards_compat(self):
2895
3778
expected_error = errors.PermissionDenied(path, extra)
2896
3779
self.assertEqual(expected_error, translated_error)
3781
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3783
def test_NoSuchFile_context_path(self):
3784
local_path = "local path"
3785
translated_error = self.translateTuple(('ReadError', "remote path"),
3787
expected_error = errors.ReadError(local_path)
3788
self.assertEqual(expected_error, translated_error)
3790
def test_NoSuchFile_without_context(self):
3791
remote_path = "remote path"
3792
translated_error = self.translateTuple(('ReadError', remote_path))
3793
expected_error = errors.ReadError(remote_path)
3794
self.assertEqual(expected_error, translated_error)
3796
def test_ReadOnlyError(self):
3797
translated_error = self.translateTuple(('ReadOnlyError',))
3798
expected_error = errors.TransportNotPossible("readonly transport")
3799
self.assertEqual(expected_error, translated_error)
3801
def test_MemoryError(self):
3802
translated_error = self.translateTuple(('MemoryError',))
3803
self.assertStartsWith(str(translated_error),
3804
"remote server out of memory")
3806
def test_generic_IndexError_no_classname(self):
3807
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3808
translated_error = self.translateErrorFromSmartServer(err)
3809
expected_error = errors.UnknownErrorFromSmartServer(err)
3810
self.assertEqual(expected_error, translated_error)
3812
# GZ 2011-03-02: TODO test generic non-ascii error string
3814
def test_generic_KeyError(self):
3815
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3816
translated_error = self.translateErrorFromSmartServer(err)
3817
expected_error = errors.UnknownErrorFromSmartServer(err)
3818
self.assertEqual(expected_error, translated_error)
2899
3821
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
"""Unit tests for bzrlib.remote._translate_error's robustness.
3822
"""Unit tests for breezy.remote._translate_error's robustness.
2902
3824
TestErrorTranslationSuccess is for cases where _translate_error can
2903
3825
translate successfully. This class about how _translate_err behaves when
3143
4067
def test_copy_content_into_avoids_revision_history(self):
3144
4068
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4069
builder = self.make_branch_builder('remote')
4070
builder.build_commit(message="Commit.")
3147
4071
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4072
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4073
local.repository.fetch(remote_branch.repository)
3150
4074
self.hpss_calls = []
3151
4075
remote_branch.copy_content_into(local)
3152
4076
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4078
def test_fetch_everything_needs_just_one_call(self):
4079
local = self.make_branch('local')
4080
builder = self.make_branch_builder('remote')
4081
builder.build_commit(message="Commit.")
4082
remote_branch_url = self.smart_server.get_url() + 'remote'
4083
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4084
self.hpss_calls = []
4085
local.repository.fetch(
4086
remote_branch.repository,
4087
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4088
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4090
def override_verb(self, verb_name, verb):
4091
request_handlers = request.request_handlers
4092
orig_verb = request_handlers.get(verb_name)
4093
orig_info = request_handlers.get_info(verb_name)
4094
request_handlers.register(verb_name, verb, override_existing=True)
4095
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4096
override_existing=True, info=orig_info)
4098
def test_fetch_everything_backwards_compat(self):
4099
"""Can fetch with EverythingResult even with pre 2.4 servers.
4101
Pre-2.4 do not support 'everything' searches with the
4102
Repository.get_stream_1.19 verb.
4105
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4106
"""A version of the Repository.get_stream_1.19 verb patched to
4107
reject 'everything' searches the way 2.3 and earlier do.
4109
def recreate_search(self, repository, search_bytes,
4110
discard_excess=False):
4111
verb_log.append(search_bytes.split('\n', 1)[0])
4112
if search_bytes == 'everything':
4114
request.FailedSmartServerResponse(('BadSearch',)))
4115
return super(OldGetStreamVerb,
4116
self).recreate_search(repository, search_bytes,
4117
discard_excess=discard_excess)
4118
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4119
local = self.make_branch('local')
4120
builder = self.make_branch_builder('remote')
4121
builder.build_commit(message="Commit.")
4122
remote_branch_url = self.smart_server.get_url() + 'remote'
4123
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4124
self.hpss_calls = []
4125
local.repository.fetch(
4126
remote_branch.repository,
4127
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4128
# make sure the overridden verb was used
4129
self.assertLength(1, verb_log)
4130
# more than one HPSS call is needed, but because it's a VFS callback
4131
# its hard to predict exactly how many.
4132
self.assertTrue(len(self.hpss_calls) > 1)
4135
class TestUpdateBoundBranchWithModifiedBoundLocation(
4136
tests.TestCaseWithTransport):
4137
"""Ensure correct handling of bound_location modifications.
4139
This is tested against a smart server as http://pad.lv/786980 was about a
4140
ReadOnlyError (write attempt during a read-only transaction) which can only
4141
happen in this context.
4145
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4146
self.transport_server = test_server.SmartTCPServer_for_testing
4148
def make_master_and_checkout(self, master_name, checkout_name):
4149
# Create the master branch and its associated checkout
4150
self.master = self.make_branch_and_tree(master_name)
4151
self.checkout = self.master.branch.create_checkout(checkout_name)
4152
# Modify the master branch so there is something to update
4153
self.master.commit('add stuff')
4154
self.last_revid = self.master.commit('even more stuff')
4155
self.bound_location = self.checkout.branch.get_bound_location()
4157
def assertUpdateSucceeds(self, new_location):
4158
self.checkout.branch.set_bound_location(new_location)
4159
self.checkout.update()
4160
self.assertEqual(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 = controldir.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.assertEqual("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.assertEqual(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(