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)
477
491
self.assertEqual(None, result._branch_format)
478
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 TestBzrDirGetBranches(TestRemote):
546
def test_get_branches(self):
547
transport = MemoryTransport()
548
client = FakeClient(transport.base)
549
reference_bzrdir_format = bzrdir.format_registry.get('default')()
550
branch_name = reference_bzrdir_format.get_branch_format().network_name()
551
client.add_success_response_with_body(
553
"foo": ("branch", branch_name),
554
"": ("branch", branch_name)}), "success")
555
client.add_success_response(
556
'ok', '', 'no', 'no', 'no',
557
reference_bzrdir_format.repository_format.network_name())
558
client.add_error_response('NotStacked')
559
client.add_success_response(
560
'ok', '', 'no', 'no', 'no',
561
reference_bzrdir_format.repository_format.network_name())
562
client.add_error_response('NotStacked')
563
transport.mkdir('quack')
564
transport = transport.clone('quack')
565
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
567
result = a_bzrdir.get_branches()
568
self.assertEquals(["", "foo"], result.keys())
570
[('call_expecting_body', 'BzrDir.get_branches', ('quack/',)),
571
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
572
('call', 'Branch.get_stacked_on_url', ('quack/', )),
573
('call', 'BzrDir.find_repositoryV3', ('quack/', )),
574
('call', 'Branch.get_stacked_on_url', ('quack/', ))],
578
class TestBzrDirDestroyBranch(TestRemote):
580
def test_destroy_default(self):
581
transport = self.get_transport('quack')
582
referenced = self.make_branch('referenced')
583
client = FakeClient(transport.base)
584
client.add_expected_call(
585
'BzrDir.destroy_branch', ('quack/', ),
587
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
589
a_bzrdir.destroy_branch()
590
self.assertFinished(client)
592
def test_destroy_named(self):
593
transport = self.get_transport('quack')
594
referenced = self.make_branch('referenced')
595
client = FakeClient(transport.base)
596
client.add_expected_call(
597
'BzrDir.destroy_branch', ('quack/', "foo"),
599
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
601
a_bzrdir.destroy_branch("foo")
602
self.assertFinished(client)
605
class TestBzrDirHasWorkingTree(TestRemote):
607
def test_has_workingtree(self):
608
transport = self.get_transport('quack')
609
client = FakeClient(transport.base)
610
client.add_expected_call(
611
'BzrDir.has_workingtree', ('quack/',),
612
'success', ('yes',)),
613
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
615
self.assertTrue(a_bzrdir.has_workingtree())
616
self.assertFinished(client)
618
def test_no_workingtree(self):
619
transport = self.get_transport('quack')
620
client = FakeClient(transport.base)
621
client.add_expected_call(
622
'BzrDir.has_workingtree', ('quack/',),
624
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
626
self.assertFalse(a_bzrdir.has_workingtree())
627
self.assertFinished(client)
630
class TestBzrDirDestroyRepository(TestRemote):
632
def test_destroy_repository(self):
633
transport = self.get_transport('quack')
634
client = FakeClient(transport.base)
635
client.add_expected_call(
636
'BzrDir.destroy_repository', ('quack/',),
638
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
640
a_bzrdir.destroy_repository()
641
self.assertFinished(client)
481
644
class TestBzrDirOpen(TestRemote):
523
686
'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
524
687
client.add_expected_call(
525
688
'BzrDir.open', ('quack/',), 'success', ('yes',))
526
bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
689
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
690
_client=client, _force_probe=True)
691
self.assertIsInstance(bd, RemoteBzrDir)
692
self.assertFinished(client)
694
def test_backwards_compat_hpss_v2(self):
695
client, transport = self.make_fake_client_and_transport()
696
# Monkey-patch fake client to simulate real-world behaviour with v2
697
# server: upon first RPC call detect the protocol version, and because
698
# the version is 2 also do _remember_remote_is_before((1, 6)) before
699
# continuing with the RPC.
700
orig_check_call = client._check_call
701
def check_call(method, args):
702
client._medium._protocol_version = 2
703
client._medium._remember_remote_is_before((1, 6))
704
client._check_call = orig_check_call
705
client._check_call(method, args)
706
client._check_call = check_call
707
client.add_expected_call(
708
'BzrDir.open_2.1', ('quack/',), 'unknown', ('BzrDir.open_2.1',))
709
client.add_expected_call(
710
'BzrDir.open', ('quack/',), 'success', ('yes',))
711
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
527
712
_client=client, _force_probe=True)
528
713
self.assertIsInstance(bd, RemoteBzrDir)
529
714
self.assertFinished(client)
942
1159
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1162
class TestBranchBreakLock(RemoteBranchTestCase):
1164
def test_break_lock(self):
1165
transport_path = 'quack'
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.break_lock', ('quack/',),
1174
transport.mkdir('quack')
1175
transport = transport.clone('quack')
1176
branch = self.make_remote_branch(transport, client)
1178
self.assertFinished(client)
1181
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1183
def test_get_physical_lock_status_yes(self):
1184
transport = MemoryTransport()
1185
client = FakeClient(transport.base)
1186
client.add_expected_call(
1187
'Branch.get_stacked_on_url', ('quack/',),
1188
'error', ('NotStacked',))
1189
client.add_expected_call(
1190
'Branch.get_physical_lock_status', ('quack/',),
1191
'success', ('yes',))
1192
transport.mkdir('quack')
1193
transport = transport.clone('quack')
1194
branch = self.make_remote_branch(transport, client)
1195
result = branch.get_physical_lock_status()
1196
self.assertFinished(client)
1197
self.assertEqual(True, result)
1199
def test_get_physical_lock_status_no(self):
1200
transport = MemoryTransport()
1201
client = FakeClient(transport.base)
1202
client.add_expected_call(
1203
'Branch.get_stacked_on_url', ('quack/',),
1204
'error', ('NotStacked',))
1205
client.add_expected_call(
1206
'Branch.get_physical_lock_status', ('quack/',),
1208
transport.mkdir('quack')
1209
transport = transport.clone('quack')
1210
branch = self.make_remote_branch(transport, client)
1211
result = branch.get_physical_lock_status()
1212
self.assertFinished(client)
1213
self.assertEqual(False, result)
945
1216
class TestBranchGetParent(RemoteBranchTestCase):
947
1218
def test_no_parent(self):
1118
1389
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1392
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1394
def test_uses_last_revision_info_and_tags_by_default(self):
1395
transport = MemoryTransport()
1396
client = FakeClient(transport.base)
1397
client.add_expected_call(
1398
'Branch.get_stacked_on_url', ('quack/',),
1399
'error', ('NotStacked',))
1400
client.add_expected_call(
1401
'Branch.last_revision_info', ('quack/',),
1402
'success', ('ok', '1', 'rev-tip'))
1403
client.add_expected_call(
1404
'Branch.get_config_file', ('quack/',),
1405
'success', ('ok',), '')
1406
transport.mkdir('quack')
1407
transport = transport.clone('quack')
1408
branch = self.make_remote_branch(transport, client)
1409
result = branch.heads_to_fetch()
1410
self.assertFinished(client)
1411
self.assertEqual((set(['rev-tip']), set()), result)
1413
def test_uses_last_revision_info_and_tags_when_set(self):
1414
transport = MemoryTransport()
1415
client = FakeClient(transport.base)
1416
client.add_expected_call(
1417
'Branch.get_stacked_on_url', ('quack/',),
1418
'error', ('NotStacked',))
1419
client.add_expected_call(
1420
'Branch.last_revision_info', ('quack/',),
1421
'success', ('ok', '1', 'rev-tip'))
1422
client.add_expected_call(
1423
'Branch.get_config_file', ('quack/',),
1424
'success', ('ok',), 'branch.fetch_tags = True')
1425
# XXX: this will break if the default format's serialization of tags
1426
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1427
client.add_expected_call(
1428
'Branch.get_tags_bytes', ('quack/',),
1429
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1430
transport.mkdir('quack')
1431
transport = transport.clone('quack')
1432
branch = self.make_remote_branch(transport, client)
1433
result = branch.heads_to_fetch()
1434
self.assertFinished(client)
1436
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1438
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1439
transport = MemoryTransport()
1440
client = FakeClient(transport.base)
1441
client.add_expected_call(
1442
'Branch.get_stacked_on_url', ('quack/',),
1443
'error', ('NotStacked',))
1444
client.add_expected_call(
1445
'Branch.heads_to_fetch', ('quack/',),
1446
'success', (['tip'], ['tagged-1', 'tagged-2']))
1447
transport.mkdir('quack')
1448
transport = transport.clone('quack')
1449
branch = self.make_remote_branch(transport, client)
1450
branch._format._use_default_local_heads_to_fetch = lambda: False
1451
result = branch.heads_to_fetch()
1452
self.assertFinished(client)
1453
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1455
def make_branch_with_tags(self):
1456
self.setup_smart_server_with_call_log()
1457
# Make a branch with a single revision.
1458
builder = self.make_branch_builder('foo')
1459
builder.start_series()
1460
builder.build_snapshot('tip', None, [
1461
('add', ('', 'root-id', 'directory', ''))])
1462
builder.finish_series()
1463
branch = builder.get_branch()
1464
# Add two tags to that branch
1465
branch.tags.set_tag('tag-1', 'rev-1')
1466
branch.tags.set_tag('tag-2', 'rev-2')
1469
def test_backwards_compatible(self):
1470
branch = self.make_branch_with_tags()
1471
c = branch.get_config_stack()
1472
c.set('branch.fetch_tags', True)
1473
self.addCleanup(branch.lock_read().unlock)
1474
# Disable the heads_to_fetch verb
1475
verb = 'Branch.heads_to_fetch'
1476
self.disable_verb(verb)
1477
self.reset_smart_call_log()
1478
result = branch.heads_to_fetch()
1479
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1481
['Branch.last_revision_info', 'Branch.get_config_file',
1482
'Branch.get_tags_bytes'],
1483
[call.call.method for call in self.hpss_calls])
1485
def test_backwards_compatible_no_tags(self):
1486
branch = self.make_branch_with_tags()
1487
c = branch.get_config_stack()
1488
c.set('branch.fetch_tags', False)
1489
self.addCleanup(branch.lock_read().unlock)
1490
# Disable the heads_to_fetch verb
1491
verb = 'Branch.heads_to_fetch'
1492
self.disable_verb(verb)
1493
self.reset_smart_call_log()
1494
result = branch.heads_to_fetch()
1495
self.assertEqual((set(['tip']), set()), result)
1497
['Branch.last_revision_info', 'Branch.get_config_file'],
1498
[call.call.method for call in self.hpss_calls])
1121
1501
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1123
1503
def test_empty_branch(self):
1636
2036
self.addCleanup(branch.unlock)
1637
2037
self.reset_smart_call_log()
1638
2038
branch._get_config().set_option('value', 'name')
1639
self.assertLength(10, self.hpss_calls)
2039
self.assertLength(11, self.hpss_calls)
1640
2040
self.assertEqual('value', branch._get_config().get_option('name'))
2042
def test_backwards_compat_set_option_with_dict(self):
2043
self.setup_smart_server_with_call_log()
2044
branch = self.make_branch('.')
2045
verb = 'Branch.set_config_option_dict'
2046
self.disable_verb(verb)
2048
self.addCleanup(branch.unlock)
2049
self.reset_smart_call_log()
2050
config = branch._get_config()
2051
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2052
config.set_option(value_dict, 'name')
2053
self.assertLength(11, self.hpss_calls)
2054
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2057
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2059
def test_get_branch_conf(self):
2060
# in an empty branch we decode the response properly
2061
client = FakeClient()
2062
client.add_expected_call(
2063
'Branch.get_stacked_on_url', ('memory:///',),
2064
'error', ('NotStacked',),)
2065
client.add_success_response_with_body('# config file body', 'ok')
2066
transport = MemoryTransport()
2067
branch = self.make_remote_branch(transport, client)
2068
config = branch.get_config_stack()
2070
config.get("log_format")
2072
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2073
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2076
def test_set_branch_conf(self):
2077
client = FakeClient()
2078
client.add_expected_call(
2079
'Branch.get_stacked_on_url', ('memory:///',),
2080
'error', ('NotStacked',),)
2081
client.add_expected_call(
2082
'Branch.lock_write', ('memory:///', '', ''),
2083
'success', ('ok', 'branch token', 'repo token'))
2084
client.add_expected_call(
2085
'Branch.get_config_file', ('memory:///', ),
2086
'success', ('ok', ), "# line 1\n")
2087
client.add_expected_call(
2088
'Branch.put_config_file', ('memory:///', 'branch token',
2091
client.add_expected_call(
2092
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2094
transport = MemoryTransport()
2095
branch = self.make_remote_branch(transport, client)
2097
config = branch.get_config_stack()
2098
config.set('email', 'The Dude <lebowski@example.com>')
2100
self.assertFinished(client)
2102
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2103
('call', 'Branch.lock_write', ('memory:///', '', '')),
2104
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2105
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2106
('memory:///', 'branch token', 'repo token'),
2107
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2108
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1643
2112
class TestBranchLockWrite(RemoteBranchTestCase):
1658
2127
self.assertFinished(client)
2130
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2132
def test_simple(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.assertEquals(0, branch.revision_id_to_revno('null:'))
2148
self.assertRaises(errors.NoSuchRevision,
2149
branch.revision_id_to_revno, 'unknown')
2150
self.assertFinished(client)
2152
def test_dotted(self):
2153
transport = MemoryTransport()
2154
client = FakeClient(transport.base)
2155
client.add_expected_call(
2156
'Branch.get_stacked_on_url', ('quack/',),
2157
'error', ('NotStacked',),)
2158
client.add_expected_call(
2159
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2160
'success', ('ok', '0',),)
2161
client.add_expected_call(
2162
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2163
'error', ('NoSuchRevision', 'unknown',),)
2164
transport.mkdir('quack')
2165
transport = transport.clone('quack')
2166
branch = self.make_remote_branch(transport, client)
2167
self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
2168
self.assertRaises(errors.NoSuchRevision,
2169
branch.revision_id_to_dotted_revno, 'unknown')
2170
self.assertFinished(client)
2172
def test_dotted_no_smart_verb(self):
2173
self.setup_smart_server_with_call_log()
2174
branch = self.make_branch('.')
2175
self.disable_verb('Branch.revision_id_to_revno')
2176
self.reset_smart_call_log()
2177
self.assertEquals((0, ),
2178
branch.revision_id_to_dotted_revno('null:'))
2179
self.assertLength(8, self.hpss_calls)
1661
2182
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1663
2184
def test__get_config(self):
2427
class TestRepositoryBreakLock(TestRemoteRepository):
2429
def test_break_lock(self):
2430
transport_path = 'quack'
2431
repo, client = self.setup_fake_client_and_repository(transport_path)
2432
client.add_success_response('ok')
2435
[('call', 'Repository.break_lock', ('quack/',))],
2439
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2441
def test_get_serializer_format(self):
2442
transport_path = 'hill'
2443
repo, client = self.setup_fake_client_and_repository(transport_path)
2444
client.add_success_response('ok', '7')
2445
self.assertEquals('7', repo.get_serializer_format())
2447
[('call', 'VersionedFileRepository.get_serializer_format',
2452
class TestRepositoryReconcile(TestRemoteRepository):
2454
def test_reconcile(self):
2455
transport_path = 'hill'
2456
repo, client = self.setup_fake_client_and_repository(transport_path)
2457
body = ("garbage_inventories: 2\n"
2458
"inconsistent_parents: 3\n")
2459
client.add_expected_call(
2460
'Repository.lock_write', ('hill/', ''),
2461
'success', ('ok', 'a token'))
2462
client.add_success_response_with_body(body, 'ok')
2463
reconciler = repo.reconcile()
2465
[('call', 'Repository.lock_write', ('hill/', '')),
2466
('call_expecting_body', 'Repository.reconcile',
2467
('hill/', 'a token'))],
2469
self.assertEquals(2, reconciler.garbage_inventories)
2470
self.assertEquals(3, reconciler.inconsistent_parents)
2473
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2475
def test_text(self):
2476
# ('ok',), body with signature text
2477
transport_path = 'quack'
2478
repo, client = self.setup_fake_client_and_repository(transport_path)
2479
client.add_success_response_with_body(
2481
self.assertEquals("THETEXT", repo.get_signature_text("revid"))
2483
[('call_expecting_body', 'Repository.get_revision_signature_text',
2484
('quack/', 'revid'))],
2487
def test_no_signature(self):
2488
transport_path = 'quick'
2489
repo, client = self.setup_fake_client_and_repository(transport_path)
2490
client.add_error_response('nosuchrevision', 'unknown')
2491
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2494
[('call_expecting_body', 'Repository.get_revision_signature_text',
2495
('quick/', 'unknown'))],
1881
2499
class TestRepositoryGetGraph(TestRemoteRepository):
1883
2501
def test_get_graph(self):
3090
class TestRepositoryWriteGroups(TestRemoteRepository):
3092
def test_start_write_group(self):
3093
transport_path = 'quack'
3094
repo, client = self.setup_fake_client_and_repository(transport_path)
3095
client.add_expected_call(
3096
'Repository.lock_write', ('quack/', ''),
3097
'success', ('ok', 'a token'))
3098
client.add_expected_call(
3099
'Repository.start_write_group', ('quack/', 'a token'),
3100
'success', ('ok', ('token1', )))
3102
repo.start_write_group()
3104
def test_start_write_group_unsuspendable(self):
3105
# Some repositories do not support suspending write
3106
# groups. For those, fall back to the "real" repository.
3107
transport_path = 'quack'
3108
repo, client = self.setup_fake_client_and_repository(transport_path)
3109
def stub_ensure_real():
3110
client._calls.append(('_ensure_real',))
3111
repo._real_repository = _StubRealPackRepository(client._calls)
3112
repo._ensure_real = stub_ensure_real
3113
client.add_expected_call(
3114
'Repository.lock_write', ('quack/', ''),
3115
'success', ('ok', 'a token'))
3116
client.add_expected_call(
3117
'Repository.start_write_group', ('quack/', 'a token'),
3118
'error', ('UnsuspendableWriteGroup',))
3120
repo.start_write_group()
3121
self.assertEquals(client._calls[-2:], [
3123
('start_write_group',)])
3125
def test_commit_write_group(self):
3126
transport_path = 'quack'
3127
repo, client = self.setup_fake_client_and_repository(transport_path)
3128
client.add_expected_call(
3129
'Repository.lock_write', ('quack/', ''),
3130
'success', ('ok', 'a token'))
3131
client.add_expected_call(
3132
'Repository.start_write_group', ('quack/', 'a token'),
3133
'success', ('ok', ['token1']))
3134
client.add_expected_call(
3135
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3138
repo.start_write_group()
3139
repo.commit_write_group()
3141
def test_abort_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.start_write_group', ('quack/', 'a token'),
3149
'success', ('ok', ['token1']))
3150
client.add_expected_call(
3151
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3154
repo.start_write_group()
3155
repo.abort_write_group(False)
3157
def test_suspend_write_group(self):
3158
transport_path = 'quack'
3159
repo, client = self.setup_fake_client_and_repository(transport_path)
3160
self.assertEquals([], repo.suspend_write_group())
3162
def test_resume_write_group(self):
3163
transport_path = 'quack'
3164
repo, client = self.setup_fake_client_and_repository(transport_path)
3165
client.add_expected_call(
3166
'Repository.lock_write', ('quack/', ''),
3167
'success', ('ok', 'a token'))
3168
client.add_expected_call(
3169
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3172
repo.resume_write_group(['token1'])
2303
3175
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2305
3177
def test_backwards_compat(self):
2869
3795
expected_error = errors.PermissionDenied(path, extra)
2870
3796
self.assertEqual(expected_error, translated_error)
3798
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3800
def test_NoSuchFile_context_path(self):
3801
local_path = "local path"
3802
translated_error = self.translateTuple(('ReadError', "remote path"),
3804
expected_error = errors.ReadError(local_path)
3805
self.assertEqual(expected_error, translated_error)
3807
def test_NoSuchFile_without_context(self):
3808
remote_path = "remote path"
3809
translated_error = self.translateTuple(('ReadError', remote_path))
3810
expected_error = errors.ReadError(remote_path)
3811
self.assertEqual(expected_error, translated_error)
3813
def test_ReadOnlyError(self):
3814
translated_error = self.translateTuple(('ReadOnlyError',))
3815
expected_error = errors.TransportNotPossible("readonly transport")
3816
self.assertEqual(expected_error, translated_error)
3818
def test_MemoryError(self):
3819
translated_error = self.translateTuple(('MemoryError',))
3820
self.assertStartsWith(str(translated_error),
3821
"remote server out of memory")
3823
def test_generic_IndexError_no_classname(self):
3824
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3825
translated_error = self.translateErrorFromSmartServer(err)
3826
expected_error = errors.UnknownErrorFromSmartServer(err)
3827
self.assertEqual(expected_error, translated_error)
3829
# GZ 2011-03-02: TODO test generic non-ascii error string
3831
def test_generic_KeyError(self):
3832
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3833
translated_error = self.translateErrorFromSmartServer(err)
3834
expected_error = errors.UnknownErrorFromSmartServer(err)
3835
self.assertEqual(expected_error, translated_error)
2873
3838
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2874
3839
"""Unit tests for bzrlib.remote._translate_error's robustness.
3117
4084
def test_copy_content_into_avoids_revision_history(self):
3118
4085
local = self.make_branch('local')
3119
remote_backing_tree = self.make_branch_and_tree('remote')
3120
remote_backing_tree.commit("Commit.")
4086
builder = self.make_branch_builder('remote')
4087
builder.build_commit(message="Commit.")
3121
4088
remote_branch_url = self.smart_server.get_url() + 'remote'
3122
4089
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3123
4090
local.repository.fetch(remote_branch.repository)
3124
4091
self.hpss_calls = []
3125
4092
remote_branch.copy_content_into(local)
3126
4093
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4095
def test_fetch_everything_needs_just_one_call(self):
4096
local = self.make_branch('local')
4097
builder = self.make_branch_builder('remote')
4098
builder.build_commit(message="Commit.")
4099
remote_branch_url = self.smart_server.get_url() + 'remote'
4100
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4101
self.hpss_calls = []
4102
local.repository.fetch(
4103
remote_branch.repository,
4104
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4105
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4107
def override_verb(self, verb_name, verb):
4108
request_handlers = request.request_handlers
4109
orig_verb = request_handlers.get(verb_name)
4110
orig_info = request_handlers.get_info(verb_name)
4111
request_handlers.register(verb_name, verb, override_existing=True)
4112
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4113
override_existing=True, info=orig_info)
4115
def test_fetch_everything_backwards_compat(self):
4116
"""Can fetch with EverythingResult even with pre 2.4 servers.
4118
Pre-2.4 do not support 'everything' searches with the
4119
Repository.get_stream_1.19 verb.
4122
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4123
"""A version of the Repository.get_stream_1.19 verb patched to
4124
reject 'everything' searches the way 2.3 and earlier do.
4126
def recreate_search(self, repository, search_bytes,
4127
discard_excess=False):
4128
verb_log.append(search_bytes.split('\n', 1)[0])
4129
if search_bytes == 'everything':
4131
request.FailedSmartServerResponse(('BadSearch',)))
4132
return super(OldGetStreamVerb,
4133
self).recreate_search(repository, search_bytes,
4134
discard_excess=discard_excess)
4135
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4136
local = self.make_branch('local')
4137
builder = self.make_branch_builder('remote')
4138
builder.build_commit(message="Commit.")
4139
remote_branch_url = self.smart_server.get_url() + 'remote'
4140
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4141
self.hpss_calls = []
4142
local.repository.fetch(
4143
remote_branch.repository,
4144
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4145
# make sure the overridden verb was used
4146
self.assertLength(1, verb_log)
4147
# more than one HPSS call is needed, but because it's a VFS callback
4148
# its hard to predict exactly how many.
4149
self.assertTrue(len(self.hpss_calls) > 1)
4152
class TestUpdateBoundBranchWithModifiedBoundLocation(
4153
tests.TestCaseWithTransport):
4154
"""Ensure correct handling of bound_location modifications.
4156
This is tested against a smart server as http://pad.lv/786980 was about a
4157
ReadOnlyError (write attempt during a read-only transaction) which can only
4158
happen in this context.
4162
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4163
self.transport_server = test_server.SmartTCPServer_for_testing
4165
def make_master_and_checkout(self, master_name, checkout_name):
4166
# Create the master branch and its associated checkout
4167
self.master = self.make_branch_and_tree(master_name)
4168
self.checkout = self.master.branch.create_checkout(checkout_name)
4169
# Modify the master branch so there is something to update
4170
self.master.commit('add stuff')
4171
self.last_revid = self.master.commit('even more stuff')
4172
self.bound_location = self.checkout.branch.get_bound_location()
4174
def assertUpdateSucceeds(self, new_location):
4175
self.checkout.branch.set_bound_location(new_location)
4176
self.checkout.update()
4177
self.assertEquals(self.last_revid, self.checkout.last_revision())
4179
def test_without_final_slash(self):
4180
self.make_master_and_checkout('master', 'checkout')
4181
# For unclear reasons some users have a bound_location without a final
4182
# '/', simulate that by forcing such a value
4183
self.assertEndsWith(self.bound_location, '/')
4184
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4186
def test_plus_sign(self):
4187
self.make_master_and_checkout('+master', 'checkout')
4188
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4190
def test_tilda(self):
4191
# Embed ~ in the middle of the path just to avoid any $HOME
4193
self.make_master_and_checkout('mas~ter', 'checkout')
4194
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4197
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4199
def test_no_context(self):
4200
class OutOfCoffee(errors.BzrError):
4201
"""A dummy exception for testing."""
4203
def __init__(self, urgency):
4204
self.urgency = urgency
4205
remote.no_context_error_translators.register("OutOfCoffee",
4206
lambda err: OutOfCoffee(err.error_args[0]))
4207
transport = MemoryTransport()
4208
client = FakeClient(transport.base)
4209
client.add_expected_call(
4210
'Branch.get_stacked_on_url', ('quack/',),
4211
'error', ('NotStacked',))
4212
client.add_expected_call(
4213
'Branch.last_revision_info',
4215
'error', ('OutOfCoffee', 'low'))
4216
transport.mkdir('quack')
4217
transport = transport.clone('quack')
4218
branch = self.make_remote_branch(transport, client)
4219
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4220
self.assertFinished(client)
4222
def test_with_context(self):
4223
class OutOfTea(errors.BzrError):
4224
def __init__(self, branch, urgency):
4225
self.branch = branch
4226
self.urgency = urgency
4227
remote.error_translators.register("OutOfTea",
4228
lambda err, find, path: OutOfTea(err.error_args[0],
4230
transport = MemoryTransport()
4231
client = FakeClient(transport.base)
4232
client.add_expected_call(
4233
'Branch.get_stacked_on_url', ('quack/',),
4234
'error', ('NotStacked',))
4235
client.add_expected_call(
4236
'Branch.last_revision_info',
4238
'error', ('OutOfTea', 'low'))
4239
transport.mkdir('quack')
4240
transport = transport.clone('quack')
4241
branch = self.make_remote_branch(transport, client)
4242
self.assertRaises(OutOfTea, branch.last_revision_info)
4243
self.assertFinished(client)
4246
class TestRepositoryPack(TestRemoteRepository):
4248
def test_pack(self):
4249
transport_path = 'quack'
4250
repo, client = self.setup_fake_client_and_repository(transport_path)
4251
client.add_expected_call(
4252
'Repository.lock_write', ('quack/', ''),
4253
'success', ('ok', 'token'))
4254
client.add_expected_call(
4255
'Repository.pack', ('quack/', 'token', 'False'),
4256
'success', ('ok',), )
4257
client.add_expected_call(
4258
'Repository.unlock', ('quack/', 'token'),
4259
'success', ('ok', ))
4262
def test_pack_with_hint(self):
4263
transport_path = 'quack'
4264
repo, client = self.setup_fake_client_and_repository(transport_path)
4265
client.add_expected_call(
4266
'Repository.lock_write', ('quack/', ''),
4267
'success', ('ok', 'token'))
4268
client.add_expected_call(
4269
'Repository.pack', ('quack/', 'token', 'False'),
4270
'success', ('ok',), )
4271
client.add_expected_call(
4272
'Repository.unlock', ('quack/', 'token', 'False'),
4273
'success', ('ok', ))
4274
repo.pack(['hinta', 'hintb'])
4277
class TestRepositoryIterInventories(TestRemoteRepository):
4278
"""Test Repository.iter_inventories."""
4280
def _serialize_inv_delta(self, old_name, new_name, delta):
4281
serializer = inventory_delta.InventoryDeltaSerializer(True, False)
4282
return "".join(serializer.delta_to_lines(old_name, new_name, delta))
4284
def test_single_empty(self):
4285
transport_path = 'quack'
4286
repo, client = self.setup_fake_client_and_repository(transport_path)
4287
fmt = bzrdir.format_registry.get('2a')().repository_format
4289
stream = [('inventory-deltas', [
4290
versionedfile.FulltextContentFactory('somerevid', None, None,
4291
self._serialize_inv_delta('null:', 'somerevid', []))])]
4292
client.add_expected_call(
4293
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4294
'success', ('ok', ),
4295
_stream_to_byte_stream(stream, fmt))
4296
ret = list(repo.iter_inventories(["somerevid"]))
4297
self.assertLength(1, ret)
4299
self.assertEquals("somerevid", inv.revision_id)
4301
def test_empty(self):
4302
transport_path = 'quack'
4303
repo, client = self.setup_fake_client_and_repository(transport_path)
4304
ret = list(repo.iter_inventories([]))
4305
self.assertEquals(ret, [])
4307
def test_missing(self):
4308
transport_path = 'quack'
4309
repo, client = self.setup_fake_client_and_repository(transport_path)
4310
client.add_expected_call(
4311
'VersionedFileRepository.get_inventories', ('quack/', 'unordered'),
4312
'success', ('ok', ), iter([]))
4313
self.assertRaises(errors.NoSuchRevision, list, repo.iter_inventories(