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,
73
from bzrlib.symbol_versioning import deprecated_in
60
74
from bzrlib.tests import (
62
split_suite_by_condition,
66
from bzrlib.transport import get_transport
77
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
78
from bzrlib.transport.memory import MemoryTransport
68
79
from bzrlib.transport.remote import (
70
81
RemoteSSHTransport,
71
82
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 = [
86
load_tests = load_tests_apply_scenarios
89
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
93
{'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):
95
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
99
super(BasicRemoteObjectTests, self).setUp()
89
100
self.transport = self.get_transport()
90
101
# make a branch that can be opened over the smart transport
91
102
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
103
self.addCleanup(self.transport.disconnect)
97
105
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
106
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
107
self.assertIsInstance(b, BzrDir)
101
109
def test_open_remote_branch(self):
102
110
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
111
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
112
branch = b.open_branch()
105
113
self.assertIsInstance(branch, Branch)
480
490
self.assertEqual(None, result._branch_format)
481
491
self.assertFinished(client)
493
def test_unknown(self):
494
transport = self.get_transport('quack')
495
referenced = self.make_branch('referenced')
496
expected = referenced.bzrdir.cloning_metadir()
497
client = FakeClient(transport.base)
498
client.add_expected_call(
499
'BzrDir.cloning_metadir', ('quack/', 'False'),
500
'success', ('unknown', 'unknown', ('branch', ''))),
501
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
503
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
506
class TestBzrDirDestroyBranch(TestRemote):
508
def test_destroy_default(self):
509
transport = self.get_transport('quack')
510
referenced = self.make_branch('referenced')
511
client = FakeClient(transport.base)
512
client.add_expected_call(
513
'BzrDir.destroy_branch', ('quack/', ),
515
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
517
a_bzrdir.destroy_branch()
518
self.assertFinished(client)
520
def test_destroy_named(self):
521
transport = self.get_transport('quack')
522
referenced = self.make_branch('referenced')
523
client = FakeClient(transport.base)
524
client.add_expected_call(
525
'BzrDir.destroy_branch', ('quack/', "foo"),
527
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
529
a_bzrdir.destroy_branch("foo")
530
self.assertFinished(client)
533
class TestBzrDirHasWorkingTree(TestRemote):
535
def test_has_workingtree(self):
536
transport = self.get_transport('quack')
537
client = FakeClient(transport.base)
538
client.add_expected_call(
539
'BzrDir.has_workingtree', ('quack/',),
540
'success', ('yes',)),
541
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
543
self.assertTrue(a_bzrdir.has_workingtree())
544
self.assertFinished(client)
546
def test_no_workingtree(self):
547
transport = self.get_transport('quack')
548
client = FakeClient(transport.base)
549
client.add_expected_call(
550
'BzrDir.has_workingtree', ('quack/',),
552
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
554
self.assertFalse(a_bzrdir.has_workingtree())
555
self.assertFinished(client)
558
class TestBzrDirDestroyRepository(TestRemote):
560
def test_destroy_repository(self):
561
transport = self.get_transport('quack')
562
client = FakeClient(transport.base)
563
client.add_expected_call(
564
'BzrDir.destroy_repository', ('quack/',),
566
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
568
a_bzrdir.destroy_repository()
569
self.assertFinished(client)
484
572
class TestBzrDirOpen(TestRemote):
967
1083
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1086
class TestBranchBreakLock(RemoteBranchTestCase):
1088
def test_break_lock(self):
1089
transport_path = 'quack'
1090
transport = MemoryTransport()
1091
client = FakeClient(transport.base)
1092
client.add_expected_call(
1093
'Branch.get_stacked_on_url', ('quack/',),
1094
'error', ('NotStacked',))
1095
client.add_expected_call(
1096
'Branch.break_lock', ('quack/',),
1098
transport.mkdir('quack')
1099
transport = transport.clone('quack')
1100
branch = self.make_remote_branch(transport, client)
1102
self.assertFinished(client)
1105
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1107
def test_get_physical_lock_status_yes(self):
1108
transport = MemoryTransport()
1109
client = FakeClient(transport.base)
1110
client.add_expected_call(
1111
'Branch.get_stacked_on_url', ('quack/',),
1112
'error', ('NotStacked',))
1113
client.add_expected_call(
1114
'Branch.get_physical_lock_status', ('quack/',),
1115
'success', ('yes',))
1116
transport.mkdir('quack')
1117
transport = transport.clone('quack')
1118
branch = self.make_remote_branch(transport, client)
1119
result = branch.get_physical_lock_status()
1120
self.assertFinished(client)
1121
self.assertEqual(True, result)
1123
def test_get_physical_lock_status_no(self):
1124
transport = MemoryTransport()
1125
client = FakeClient(transport.base)
1126
client.add_expected_call(
1127
'Branch.get_stacked_on_url', ('quack/',),
1128
'error', ('NotStacked',))
1129
client.add_expected_call(
1130
'Branch.get_physical_lock_status', ('quack/',),
1132
transport.mkdir('quack')
1133
transport = transport.clone('quack')
1134
branch = self.make_remote_branch(transport, client)
1135
result = branch.get_physical_lock_status()
1136
self.assertFinished(client)
1137
self.assertEqual(False, result)
970
1140
class TestBranchGetParent(RemoteBranchTestCase):
972
1142
def test_no_parent(self):
1143
1313
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1316
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1318
def test_uses_last_revision_info_and_tags_by_default(self):
1319
transport = MemoryTransport()
1320
client = FakeClient(transport.base)
1321
client.add_expected_call(
1322
'Branch.get_stacked_on_url', ('quack/',),
1323
'error', ('NotStacked',))
1324
client.add_expected_call(
1325
'Branch.last_revision_info', ('quack/',),
1326
'success', ('ok', '1', 'rev-tip'))
1327
client.add_expected_call(
1328
'Branch.get_config_file', ('quack/',),
1329
'success', ('ok',), '')
1330
transport.mkdir('quack')
1331
transport = transport.clone('quack')
1332
branch = self.make_remote_branch(transport, client)
1333
result = branch.heads_to_fetch()
1334
self.assertFinished(client)
1335
self.assertEqual((set(['rev-tip']), set()), result)
1337
def test_uses_last_revision_info_and_tags_when_set(self):
1338
transport = MemoryTransport()
1339
client = FakeClient(transport.base)
1340
client.add_expected_call(
1341
'Branch.get_stacked_on_url', ('quack/',),
1342
'error', ('NotStacked',))
1343
client.add_expected_call(
1344
'Branch.last_revision_info', ('quack/',),
1345
'success', ('ok', '1', 'rev-tip'))
1346
client.add_expected_call(
1347
'Branch.get_config_file', ('quack/',),
1348
'success', ('ok',), 'branch.fetch_tags = True')
1349
# XXX: this will break if the default format's serialization of tags
1350
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1351
client.add_expected_call(
1352
'Branch.get_tags_bytes', ('quack/',),
1353
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1354
transport.mkdir('quack')
1355
transport = transport.clone('quack')
1356
branch = self.make_remote_branch(transport, client)
1357
result = branch.heads_to_fetch()
1358
self.assertFinished(client)
1360
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1362
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1363
transport = MemoryTransport()
1364
client = FakeClient(transport.base)
1365
client.add_expected_call(
1366
'Branch.get_stacked_on_url', ('quack/',),
1367
'error', ('NotStacked',))
1368
client.add_expected_call(
1369
'Branch.heads_to_fetch', ('quack/',),
1370
'success', (['tip'], ['tagged-1', 'tagged-2']))
1371
transport.mkdir('quack')
1372
transport = transport.clone('quack')
1373
branch = self.make_remote_branch(transport, client)
1374
branch._format._use_default_local_heads_to_fetch = lambda: False
1375
result = branch.heads_to_fetch()
1376
self.assertFinished(client)
1377
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1379
def make_branch_with_tags(self):
1380
self.setup_smart_server_with_call_log()
1381
# Make a branch with a single revision.
1382
builder = self.make_branch_builder('foo')
1383
builder.start_series()
1384
builder.build_snapshot('tip', None, [
1385
('add', ('', 'root-id', 'directory', ''))])
1386
builder.finish_series()
1387
branch = builder.get_branch()
1388
# Add two tags to that branch
1389
branch.tags.set_tag('tag-1', 'rev-1')
1390
branch.tags.set_tag('tag-2', 'rev-2')
1393
def test_backwards_compatible(self):
1394
branch = self.make_branch_with_tags()
1395
c = branch.get_config()
1396
c.set_user_option('branch.fetch_tags', 'True')
1397
self.addCleanup(branch.lock_read().unlock)
1398
# Disable the heads_to_fetch verb
1399
verb = 'Branch.heads_to_fetch'
1400
self.disable_verb(verb)
1401
self.reset_smart_call_log()
1402
result = branch.heads_to_fetch()
1403
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1405
['Branch.last_revision_info', 'Branch.get_config_file',
1406
'Branch.get_tags_bytes'],
1407
[call.call.method for call in self.hpss_calls])
1409
def test_backwards_compatible_no_tags(self):
1410
branch = self.make_branch_with_tags()
1411
c = branch.get_config()
1412
c.set_user_option('branch.fetch_tags', 'False')
1413
self.addCleanup(branch.lock_read().unlock)
1414
# Disable the heads_to_fetch verb
1415
verb = 'Branch.heads_to_fetch'
1416
self.disable_verb(verb)
1417
self.reset_smart_call_log()
1418
result = branch.heads_to_fetch()
1419
self.assertEqual((set(['tip']), set()), result)
1421
['Branch.last_revision_info', 'Branch.get_config_file'],
1422
[call.call.method for call in self.hpss_calls])
1146
1425
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1427
def test_empty_branch(self):
1652
1925
branch.unlock()
1653
1926
self.assertFinished(client)
1928
def test_set_option_with_dict(self):
1929
client = FakeClient()
1930
client.add_expected_call(
1931
'Branch.get_stacked_on_url', ('memory:///',),
1932
'error', ('NotStacked',),)
1933
client.add_expected_call(
1934
'Branch.lock_write', ('memory:///', '', ''),
1935
'success', ('ok', 'branch token', 'repo token'))
1936
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1937
client.add_expected_call(
1938
'Branch.set_config_option_dict', ('memory:///', 'branch token',
1939
'repo token', encoded_dict_value, 'foo', ''),
1941
client.add_expected_call(
1942
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1944
transport = MemoryTransport()
1945
branch = self.make_remote_branch(transport, client)
1947
config = branch._get_config()
1949
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1952
self.assertFinished(client)
1655
1954
def test_backwards_compat_set_option(self):
1656
1955
self.setup_smart_server_with_call_log()
1657
1956
branch = self.make_branch('.')
1664
1963
self.assertLength(10, self.hpss_calls)
1665
1964
self.assertEqual('value', branch._get_config().get_option('name'))
1966
def test_backwards_compat_set_option_with_dict(self):
1967
self.setup_smart_server_with_call_log()
1968
branch = self.make_branch('.')
1969
verb = 'Branch.set_config_option_dict'
1970
self.disable_verb(verb)
1972
self.addCleanup(branch.unlock)
1973
self.reset_smart_call_log()
1974
config = branch._get_config()
1975
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1976
config.set_option(value_dict, 'name')
1977
self.assertLength(10, self.hpss_calls)
1978
self.assertEqual(value_dict, branch._get_config().get_option('name'))
1981
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
1983
def test_get_branch_conf(self):
1984
# in an empty branch we decode the response properly
1985
client = FakeClient()
1986
client.add_expected_call(
1987
'Branch.get_stacked_on_url', ('memory:///',),
1988
'error', ('NotStacked',),)
1989
client.add_success_response_with_body('# config file body', 'ok')
1990
transport = MemoryTransport()
1991
branch = self.make_remote_branch(transport, client)
1992
config = branch.get_config_stack()
1994
config.get("log_format")
1996
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1997
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2000
def test_set_branch_conf(self):
2001
client = FakeClient()
2002
client.add_expected_call(
2003
'Branch.get_stacked_on_url', ('memory:///',),
2004
'error', ('NotStacked',),)
2005
client.add_expected_call(
2006
'Branch.lock_write', ('memory:///', '', ''),
2007
'success', ('ok', 'branch token', 'repo token'))
2008
client.add_expected_call(
2009
'Branch.get_config_file', ('memory:///', ),
2010
'success', ('ok', ), "# line 1\n")
2011
client.add_expected_call(
2012
'Branch.put_config_file', ('memory:///', 'branch token',
2015
client.add_expected_call(
2016
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2018
transport = MemoryTransport()
2019
branch = self.make_remote_branch(transport, client)
2021
config = branch.get_config_stack()
2022
config.set('email', 'The Dude <lebowski@example.com>')
2024
self.assertFinished(client)
2026
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2027
('call', 'Branch.lock_write', ('memory:///', '', '')),
2028
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2029
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2030
('memory:///', 'branch token', 'repo token'),
2031
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2032
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2036
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2051
self.assertFinished(client)
2054
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2056
def test_simple(self):
2057
transport = MemoryTransport()
2058
client = FakeClient(transport.base)
2059
client.add_expected_call(
2060
'Branch.get_stacked_on_url', ('quack/',),
2061
'error', ('NotStacked',),)
2062
client.add_expected_call(
2063
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2064
'success', ('ok', '0',),)
2065
client.add_expected_call(
2066
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2067
'error', ('NoSuchRevision', 'unknown',),)
2068
transport.mkdir('quack')
2069
transport = transport.clone('quack')
2070
branch = self.make_remote_branch(transport, client)
2071
self.assertEquals(0, branch.revision_id_to_revno('null:'))
2072
self.assertRaises(errors.NoSuchRevision,
2073
branch.revision_id_to_revno, 'unknown')
2074
self.assertFinished(client)
2076
def test_dotted(self):
2077
transport = MemoryTransport()
2078
client = FakeClient(transport.base)
2079
client.add_expected_call(
2080
'Branch.get_stacked_on_url', ('quack/',),
2081
'error', ('NotStacked',),)
2082
client.add_expected_call(
2083
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2084
'success', ('ok', '0',),)
2085
client.add_expected_call(
2086
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2087
'error', ('NoSuchRevision', 'unknown',),)
2088
transport.mkdir('quack')
2089
transport = transport.clone('quack')
2090
branch = self.make_remote_branch(transport, client)
2091
self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
2092
self.assertRaises(errors.NoSuchRevision,
2093
branch.revision_id_to_dotted_revno, 'unknown')
2094
self.assertFinished(client)
2096
def test_dotted_no_smart_verb(self):
2097
self.setup_smart_server_with_call_log()
2098
branch = self.make_branch('.')
2099
self.disable_verb('Branch.revision_id_to_revno')
2100
self.reset_smart_call_log()
2101
self.assertEquals((0, ),
2102
branch.revision_id_to_dotted_revno('null:'))
2103
self.assertLength(7, self.hpss_calls)
1686
2106
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2108
def test__get_config(self):
1828
2248
class TestRepositoryFormat(TestRemoteRepository):
1830
2250
def test_fast_delta(self):
1831
true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
2251
true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2252
true_format = RemoteRepositoryFormat()
1833
2253
true_format._network_name = true_name
1834
2254
self.assertEqual(True, true_format.fast_deltas)
1835
false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
2255
false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2256
false_format = RemoteRepositoryFormat()
1837
2257
false_format._network_name = false_name
1838
2258
self.assertEqual(False, false_format.fast_deltas)
1840
2260
def test_get_format_description(self):
1841
2261
remote_repo_format = RemoteRepositoryFormat()
1842
real_format = repository.RepositoryFormat.get_default_format()
2262
real_format = repository.format_registry.get_default()
1843
2263
remote_repo_format._network_name = real_format.network_name()
1844
2264
self.assertEqual(remoted_description(real_format),
1845
2265
remote_repo_format.get_format_description())
2268
class TestRepositoryAllRevisionIds(TestRemoteRepository):
2270
def test_empty(self):
2271
transport_path = 'quack'
2272
repo, client = self.setup_fake_client_and_repository(transport_path)
2273
client.add_success_response_with_body('', 'ok')
2274
self.assertEquals([], repo.all_revision_ids())
2276
[('call_expecting_body', 'Repository.all_revision_ids',
2280
def test_with_some_content(self):
2281
transport_path = 'quack'
2282
repo, client = self.setup_fake_client_and_repository(transport_path)
2283
client.add_success_response_with_body(
2284
'rev1\nrev2\nanotherrev\n', 'ok')
2285
self.assertEquals(["rev1", "rev2", "anotherrev"],
2286
repo.all_revision_ids())
2288
[('call_expecting_body', 'Repository.all_revision_ids',
1848
2293
class TestRepositoryGatherStats(TestRemoteRepository):
1850
2295
def test_revid_none(self):
2351
class TestRepositoryBreakLock(TestRemoteRepository):
2353
def test_break_lock(self):
2354
transport_path = 'quack'
2355
repo, client = self.setup_fake_client_and_repository(transport_path)
2356
client.add_success_response('ok')
2359
[('call', 'Repository.break_lock', ('quack/',))],
2363
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2365
def test_get_serializer_format(self):
2366
transport_path = 'hill'
2367
repo, client = self.setup_fake_client_and_repository(transport_path)
2368
client.add_success_response('ok', '7')
2369
self.assertEquals('7', repo.get_serializer_format())
2371
[('call', 'VersionedFileRepository.get_serializer_format',
2376
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2378
def test_text(self):
2379
# ('ok',), body with signature text
2380
transport_path = 'quack'
2381
repo, client = self.setup_fake_client_and_repository(transport_path)
2382
client.add_success_response_with_body(
2384
self.assertEquals("THETEXT", repo.get_signature_text("revid"))
2386
[('call_expecting_body', 'Repository.get_revision_signature_text',
2387
('quack/', 'revid'))],
2390
def test_no_signature(self):
2391
transport_path = 'quick'
2392
repo, client = self.setup_fake_client_and_repository(transport_path)
2393
client.add_error_response('nosuchrevision', 'unknown')
2394
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2397
[('call_expecting_body', 'Repository.get_revision_signature_text',
2398
('quick/', 'unknown'))],
1906
2402
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2404
def test_get_graph(self):
2115
2664
self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2667
class TestRepositoryGetRevisions(TestRemoteRepository):
2669
def test_hpss_missing_revision(self):
2670
transport_path = 'quack'
2671
repo, client = self.setup_fake_client_and_repository(transport_path)
2672
client.add_success_response_with_body(
2674
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2675
['somerev1', 'anotherrev2'])
2677
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2678
('quack/', ), "somerev1\nanotherrev2")],
2681
def test_hpss_get_single_revision(self):
2682
transport_path = 'quack'
2683
repo, client = self.setup_fake_client_and_repository(transport_path)
2684
somerev1 = Revision("somerev1")
2685
somerev1.committer = "Joe Committer <joe@example.com>"
2686
somerev1.timestamp = 1321828927
2687
somerev1.timezone = -60
2688
somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
2689
somerev1.message = "Message"
2690
body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
2692
# Split up body into two bits to make sure the zlib compression object
2693
# gets data fed twice.
2694
client.add_success_response_with_body(
2695
[body[:10], body[10:]], 'ok', '10')
2696
revs = repo.get_revisions(['somerev1'])
2697
self.assertEquals(revs, [somerev1])
2699
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2700
('quack/', ), "somerev1")],
2118
2704
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2120
2706
def test_null_revision(self):
2270
2857
call.call.method == verb])
2860
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2862
def test_has_signature_for_revision_id(self):
2863
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2864
transport_path = 'quack'
2865
repo, client = self.setup_fake_client_and_repository(transport_path)
2866
client.add_success_response('yes')
2867
result = repo.has_signature_for_revision_id('A')
2869
[('call', 'Repository.has_signature_for_revision_id',
2872
self.assertEqual(True, result)
2874
def test_is_not_shared(self):
2875
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2876
transport_path = 'qwack'
2877
repo, client = self.setup_fake_client_and_repository(transport_path)
2878
client.add_success_response('no')
2879
result = repo.has_signature_for_revision_id('A')
2881
[('call', 'Repository.has_signature_for_revision_id',
2884
self.assertEqual(False, result)
2887
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2889
def test_get_physical_lock_status_yes(self):
2890
transport_path = 'qwack'
2891
repo, client = self.setup_fake_client_and_repository(transport_path)
2892
client.add_success_response('yes')
2893
result = repo.get_physical_lock_status()
2895
[('call', 'Repository.get_physical_lock_status',
2898
self.assertEqual(True, result)
2900
def test_get_physical_lock_status_no(self):
2901
transport_path = 'qwack'
2902
repo, client = self.setup_fake_client_and_repository(transport_path)
2903
client.add_success_response('no')
2904
result = repo.get_physical_lock_status()
2906
[('call', 'Repository.get_physical_lock_status',
2909
self.assertEqual(False, result)
2273
2912
class TestRepositoryIsShared(TestRemoteRepository):
2275
2914
def test_is_shared(self):
2295
2934
self.assertEqual(False, result)
2937
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
2939
def test_make_working_trees(self):
2940
# ('yes', ) for Repository.make_working_trees -> 'True'.
2941
transport_path = 'quack'
2942
repo, client = self.setup_fake_client_and_repository(transport_path)
2943
client.add_success_response('yes')
2944
result = repo.make_working_trees()
2946
[('call', 'Repository.make_working_trees', ('quack/',))],
2948
self.assertEqual(True, result)
2950
def test_no_working_trees(self):
2951
# ('no', ) for Repository.make_working_trees -> 'False'.
2952
transport_path = 'qwack'
2953
repo, client = self.setup_fake_client_and_repository(transport_path)
2954
client.add_success_response('no')
2955
result = repo.make_working_trees()
2957
[('call', 'Repository.make_working_trees', ('qwack/',))],
2959
self.assertEqual(False, result)
2298
2962
class TestRepositoryLockWrite(TestRemoteRepository):
2300
2964
def test_lock_write(self):
2301
2965
transport_path = 'quack'
2302
2966
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
2967
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
2968
token = repo.lock_write().repository_token
2305
2969
self.assertEqual(
2306
2970
[('call', 'Repository.lock_write', ('quack/', ''))],
2308
self.assertEqual('a token', result)
2972
self.assertEqual('a token', token)
2310
2974
def test_lock_write_already_locked(self):
2311
2975
transport_path = 'quack'
2993
class TestRepositoryWriteGroups(TestRemoteRepository):
2995
def test_start_write_group(self):
2996
transport_path = 'quack'
2997
repo, client = self.setup_fake_client_and_repository(transport_path)
2998
client.add_expected_call(
2999
'Repository.lock_write', ('quack/', ''),
3000
'success', ('ok', 'a token'))
3001
client.add_expected_call(
3002
'Repository.start_write_group', ('quack/', 'a token'),
3003
'success', ('ok', ('token1', )))
3005
repo.start_write_group()
3007
def test_start_write_group_unsuspendable(self):
3008
# Some repositories do not support suspending write
3009
# groups. For those, fall back to the "real" repository.
3010
transport_path = 'quack'
3011
repo, client = self.setup_fake_client_and_repository(transport_path)
3012
def stub_ensure_real():
3013
client._calls.append(('_ensure_real',))
3014
repo._real_repository = _StubRealPackRepository(client._calls)
3015
repo._ensure_real = stub_ensure_real
3016
client.add_expected_call(
3017
'Repository.lock_write', ('quack/', ''),
3018
'success', ('ok', 'a token'))
3019
client.add_expected_call(
3020
'Repository.start_write_group', ('quack/', 'a token'),
3021
'error', ('UnsuspendableWriteGroup',))
3023
repo.start_write_group()
3024
self.assertEquals(client._calls[-2:], [
3026
('start_write_group',)])
3028
def test_commit_write_group(self):
3029
transport_path = 'quack'
3030
repo, client = self.setup_fake_client_and_repository(transport_path)
3031
client.add_expected_call(
3032
'Repository.lock_write', ('quack/', ''),
3033
'success', ('ok', 'a token'))
3034
client.add_expected_call(
3035
'Repository.start_write_group', ('quack/', 'a token'),
3036
'success', ('ok', ['token1']))
3037
client.add_expected_call(
3038
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3041
repo.start_write_group()
3042
repo.commit_write_group()
3044
def test_abort_write_group(self):
3045
transport_path = 'quack'
3046
repo, client = self.setup_fake_client_and_repository(transport_path)
3047
client.add_expected_call(
3048
'Repository.lock_write', ('quack/', ''),
3049
'success', ('ok', 'a token'))
3050
client.add_expected_call(
3051
'Repository.start_write_group', ('quack/', 'a token'),
3052
'success', ('ok', ['token1']))
3053
client.add_expected_call(
3054
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3057
repo.start_write_group()
3058
repo.abort_write_group(False)
3060
def test_suspend_write_group(self):
3061
transport_path = 'quack'
3062
repo, client = self.setup_fake_client_and_repository(transport_path)
3063
self.assertEquals([], repo.suspend_write_group())
3065
def test_resume_write_group(self):
3066
transport_path = 'quack'
3067
repo, client = self.setup_fake_client_and_repository(transport_path)
3068
client.add_expected_call(
3069
'Repository.lock_write', ('quack/', ''),
3070
'success', ('ok', 'a token'))
3071
client.add_expected_call(
3072
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3075
repo.resume_write_group(['token1'])
2329
3078
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3080
def test_backwards_compat(self):
2895
3698
expected_error = errors.PermissionDenied(path, extra)
2896
3699
self.assertEqual(expected_error, translated_error)
3701
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3703
def test_NoSuchFile_context_path(self):
3704
local_path = "local path"
3705
translated_error = self.translateTuple(('ReadError', "remote path"),
3707
expected_error = errors.ReadError(local_path)
3708
self.assertEqual(expected_error, translated_error)
3710
def test_NoSuchFile_without_context(self):
3711
remote_path = "remote path"
3712
translated_error = self.translateTuple(('ReadError', remote_path))
3713
expected_error = errors.ReadError(remote_path)
3714
self.assertEqual(expected_error, translated_error)
3716
def test_ReadOnlyError(self):
3717
translated_error = self.translateTuple(('ReadOnlyError',))
3718
expected_error = errors.TransportNotPossible("readonly transport")
3719
self.assertEqual(expected_error, translated_error)
3721
def test_MemoryError(self):
3722
translated_error = self.translateTuple(('MemoryError',))
3723
self.assertStartsWith(str(translated_error),
3724
"remote server out of memory")
3726
def test_generic_IndexError_no_classname(self):
3727
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3728
translated_error = self.translateErrorFromSmartServer(err)
3729
expected_error = errors.UnknownErrorFromSmartServer(err)
3730
self.assertEqual(expected_error, translated_error)
3732
# GZ 2011-03-02: TODO test generic non-ascii error string
3734
def test_generic_KeyError(self):
3735
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3736
translated_error = self.translateErrorFromSmartServer(err)
3737
expected_error = errors.UnknownErrorFromSmartServer(err)
3738
self.assertEqual(expected_error, translated_error)
2899
3741
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3742
"""Unit tests for bzrlib.remote._translate_error's robustness.
3143
3987
def test_copy_content_into_avoids_revision_history(self):
3144
3988
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
3989
builder = self.make_branch_builder('remote')
3990
builder.build_commit(message="Commit.")
3147
3991
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
3992
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
3993
local.repository.fetch(remote_branch.repository)
3150
3994
self.hpss_calls = []
3151
3995
remote_branch.copy_content_into(local)
3152
3996
self.assertFalse('Branch.revision_history' in self.hpss_calls)
3998
def test_fetch_everything_needs_just_one_call(self):
3999
local = self.make_branch('local')
4000
builder = self.make_branch_builder('remote')
4001
builder.build_commit(message="Commit.")
4002
remote_branch_url = self.smart_server.get_url() + 'remote'
4003
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4004
self.hpss_calls = []
4005
local.repository.fetch(
4006
remote_branch.repository,
4007
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4008
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4010
def override_verb(self, verb_name, verb):
4011
request_handlers = request.request_handlers
4012
orig_verb = request_handlers.get(verb_name)
4013
orig_info = request_handlers.get_info(verb_name)
4014
request_handlers.register(verb_name, verb, override_existing=True)
4015
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4016
override_existing=True, info=orig_info)
4018
def test_fetch_everything_backwards_compat(self):
4019
"""Can fetch with EverythingResult even with pre 2.4 servers.
4021
Pre-2.4 do not support 'everything' searches with the
4022
Repository.get_stream_1.19 verb.
4025
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4026
"""A version of the Repository.get_stream_1.19 verb patched to
4027
reject 'everything' searches the way 2.3 and earlier do.
4029
def recreate_search(self, repository, search_bytes,
4030
discard_excess=False):
4031
verb_log.append(search_bytes.split('\n', 1)[0])
4032
if search_bytes == 'everything':
4034
request.FailedSmartServerResponse(('BadSearch',)))
4035
return super(OldGetStreamVerb,
4036
self).recreate_search(repository, search_bytes,
4037
discard_excess=discard_excess)
4038
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4039
local = self.make_branch('local')
4040
builder = self.make_branch_builder('remote')
4041
builder.build_commit(message="Commit.")
4042
remote_branch_url = self.smart_server.get_url() + 'remote'
4043
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4044
self.hpss_calls = []
4045
local.repository.fetch(
4046
remote_branch.repository,
4047
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4048
# make sure the overridden verb was used
4049
self.assertLength(1, verb_log)
4050
# more than one HPSS call is needed, but because it's a VFS callback
4051
# its hard to predict exactly how many.
4052
self.assertTrue(len(self.hpss_calls) > 1)
4055
class TestUpdateBoundBranchWithModifiedBoundLocation(
4056
tests.TestCaseWithTransport):
4057
"""Ensure correct handling of bound_location modifications.
4059
This is tested against a smart server as http://pad.lv/786980 was about a
4060
ReadOnlyError (write attempt during a read-only transaction) which can only
4061
happen in this context.
4065
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4066
self.transport_server = test_server.SmartTCPServer_for_testing
4068
def make_master_and_checkout(self, master_name, checkout_name):
4069
# Create the master branch and its associated checkout
4070
self.master = self.make_branch_and_tree(master_name)
4071
self.checkout = self.master.branch.create_checkout(checkout_name)
4072
# Modify the master branch so there is something to update
4073
self.master.commit('add stuff')
4074
self.last_revid = self.master.commit('even more stuff')
4075
self.bound_location = self.checkout.branch.get_bound_location()
4077
def assertUpdateSucceeds(self, new_location):
4078
self.checkout.branch.set_bound_location(new_location)
4079
self.checkout.update()
4080
self.assertEquals(self.last_revid, self.checkout.last_revision())
4082
def test_without_final_slash(self):
4083
self.make_master_and_checkout('master', 'checkout')
4084
# For unclear reasons some users have a bound_location without a final
4085
# '/', simulate that by forcing such a value
4086
self.assertEndsWith(self.bound_location, '/')
4087
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4089
def test_plus_sign(self):
4090
self.make_master_and_checkout('+master', 'checkout')
4091
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4093
def test_tilda(self):
4094
# Embed ~ in the middle of the path just to avoid any $HOME
4096
self.make_master_and_checkout('mas~ter', 'checkout')
4097
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4100
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4102
def test_no_context(self):
4103
class OutOfCoffee(errors.BzrError):
4104
"""A dummy exception for testing."""
4106
def __init__(self, urgency):
4107
self.urgency = urgency
4108
remote.no_context_error_translators.register("OutOfCoffee",
4109
lambda err: OutOfCoffee(err.error_args[0]))
4110
transport = MemoryTransport()
4111
client = FakeClient(transport.base)
4112
client.add_expected_call(
4113
'Branch.get_stacked_on_url', ('quack/',),
4114
'error', ('NotStacked',))
4115
client.add_expected_call(
4116
'Branch.last_revision_info',
4118
'error', ('OutOfCoffee', 'low'))
4119
transport.mkdir('quack')
4120
transport = transport.clone('quack')
4121
branch = self.make_remote_branch(transport, client)
4122
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4123
self.assertFinished(client)
4125
def test_with_context(self):
4126
class OutOfTea(errors.BzrError):
4127
def __init__(self, branch, urgency):
4128
self.branch = branch
4129
self.urgency = urgency
4130
remote.error_translators.register("OutOfTea",
4131
lambda err, find, path: OutOfTea(err.error_args[0],
4133
transport = MemoryTransport()
4134
client = FakeClient(transport.base)
4135
client.add_expected_call(
4136
'Branch.get_stacked_on_url', ('quack/',),
4137
'error', ('NotStacked',))
4138
client.add_expected_call(
4139
'Branch.last_revision_info',
4141
'error', ('OutOfTea', 'low'))
4142
transport.mkdir('quack')
4143
transport = transport.clone('quack')
4144
branch = self.make_remote_branch(transport, client)
4145
self.assertRaises(OutOfTea, branch.last_revision_info)
4146
self.assertFinished(client)
4149
class TestRepositoryPack(TestRemoteRepository):
4151
def test_pack(self):
4152
transport_path = 'quack'
4153
repo, client = self.setup_fake_client_and_repository(transport_path)
4154
client.add_expected_call(
4155
'Repository.lock_write', ('quack/', ''),
4156
'success', ('ok', 'token'))
4157
client.add_expected_call(
4158
'Repository.pack', ('quack/', 'token', 'False'),
4159
'success', ('ok',), )
4160
client.add_expected_call(
4161
'Repository.unlock', ('quack/', 'token'),
4162
'success', ('ok', ))
4165
def test_pack_with_hint(self):
4166
transport_path = 'quack'
4167
repo, client = self.setup_fake_client_and_repository(transport_path)
4168
client.add_expected_call(
4169
'Repository.lock_write', ('quack/', ''),
4170
'success', ('ok', 'token'))
4171
client.add_expected_call(
4172
'Repository.pack', ('quack/', 'token', 'False'),
4173
'success', ('ok',), )
4174
client.add_expected_call(
4175
'Repository.unlock', ('quack/', 'token', 'False'),
4176
'success', ('ok', ))
4177
repo.pack(['hinta', 'hintb'])