53
59
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
56
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
61
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
62
from bzrlib.revision import (
66
from bzrlib.smart import medium, request
58
67
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
68
from bzrlib.smart.repository import (
69
SmartServerRepositoryGetParentMap,
70
SmartServerRepositoryGetStream_1_19,
72
from bzrlib.symbol_versioning import deprecated_in
60
73
from bzrlib.tests import (
62
split_suite_by_condition,
66
from bzrlib.transport import get_transport
76
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
77
from bzrlib.transport.memory import MemoryTransport
68
78
from bzrlib.transport.remote import (
70
80
RemoteSSHTransport,
71
81
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 = [
85
load_tests = load_tests_apply_scenarios
88
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
92
{'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):
94
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
98
super(BasicRemoteObjectTests, self).setUp()
89
99
self.transport = self.get_transport()
90
100
# make a branch that can be opened over the smart transport
91
101
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
102
self.addCleanup(self.transport.disconnect)
97
104
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
105
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
106
self.assertIsInstance(b, BzrDir)
101
108
def test_open_remote_branch(self):
102
109
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
110
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
111
branch = b.open_branch()
105
112
self.assertIsInstance(branch, Branch)
480
489
self.assertEqual(None, result._branch_format)
481
490
self.assertFinished(client)
492
def test_unknown(self):
493
transport = self.get_transport('quack')
494
referenced = self.make_branch('referenced')
495
expected = referenced.bzrdir.cloning_metadir()
496
client = FakeClient(transport.base)
497
client.add_expected_call(
498
'BzrDir.cloning_metadir', ('quack/', 'False'),
499
'success', ('unknown', 'unknown', ('branch', ''))),
500
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
502
self.assertRaises(errors.UnknownFormatError, a_bzrdir.cloning_metadir)
505
class TestBzrDirDestroyBranch(TestRemote):
507
def test_destroy_default(self):
508
transport = self.get_transport('quack')
509
referenced = self.make_branch('referenced')
510
client = FakeClient(transport.base)
511
client.add_expected_call(
512
'BzrDir.destroy_branch', ('quack/', ),
514
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
516
a_bzrdir.destroy_branch()
517
self.assertFinished(client)
519
def test_destroy_named(self):
520
transport = self.get_transport('quack')
521
referenced = self.make_branch('referenced')
522
client = FakeClient(transport.base)
523
client.add_expected_call(
524
'BzrDir.destroy_branch', ('quack/', "foo"),
526
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
528
a_bzrdir.destroy_branch("foo")
529
self.assertFinished(client)
532
class TestBzrDirHasWorkingTree(TestRemote):
534
def test_has_workingtree(self):
535
transport = self.get_transport('quack')
536
client = FakeClient(transport.base)
537
client.add_expected_call(
538
'BzrDir.has_workingtree', ('quack/',),
539
'success', ('yes',)),
540
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
542
self.assertTrue(a_bzrdir.has_workingtree())
543
self.assertFinished(client)
545
def test_no_workingtree(self):
546
transport = self.get_transport('quack')
547
client = FakeClient(transport.base)
548
client.add_expected_call(
549
'BzrDir.has_workingtree', ('quack/',),
551
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
553
self.assertFalse(a_bzrdir.has_workingtree())
554
self.assertFinished(client)
557
class TestBzrDirDestroyRepository(TestRemote):
559
def test_destroy_repository(self):
560
transport = self.get_transport('quack')
561
client = FakeClient(transport.base)
562
client.add_expected_call(
563
'BzrDir.destroy_repository', ('quack/',),
565
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
567
a_bzrdir.destroy_repository()
568
self.assertFinished(client)
484
571
class TestBzrDirOpen(TestRemote):
724
811
format = branch._format
725
812
self.assertEqual(network_name, format.network_name())
814
def test_already_open_repo_and_reused_medium(self):
815
"""Bug 726584: create_branch(..., repository=repo) should work
816
regardless of what the smart medium's base URL is.
818
self.transport_server = test_server.SmartTCPServer_for_testing
819
transport = self.get_transport('.')
820
repo = self.make_repository('quack')
821
# Client's medium rooted a transport root (not at the bzrdir)
822
client = FakeClient(transport.base)
823
transport = transport.clone('quack')
824
reference_bzrdir_format = bzrdir.format_registry.get('default')()
825
reference_format = reference_bzrdir_format.get_branch_format()
826
network_name = reference_format.network_name()
827
reference_repo_fmt = reference_bzrdir_format.repository_format
828
reference_repo_name = reference_repo_fmt.network_name()
829
client.add_expected_call(
830
'BzrDir.create_branch', ('extra/quack/', network_name),
831
'success', ('ok', network_name, '', 'no', 'no', 'yes',
832
reference_repo_name))
833
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
835
branch = a_bzrdir.create_branch(repository=repo)
836
# We should have got a remote branch
837
self.assertIsInstance(branch, remote.RemoteBranch)
838
# its format should have the settings from the response
839
format = branch._format
840
self.assertEqual(network_name, format.network_name())
728
843
class TestBzrDirCreateRepository(TestRemote):
967
1082
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1085
class TestBranchBreakLock(RemoteBranchTestCase):
1087
def test_break_lock(self):
1088
transport_path = 'quack'
1089
transport = MemoryTransport()
1090
client = FakeClient(transport.base)
1091
client.add_expected_call(
1092
'Branch.get_stacked_on_url', ('quack/',),
1093
'error', ('NotStacked',))
1094
client.add_expected_call(
1095
'Branch.break_lock', ('quack/',),
1097
transport.mkdir('quack')
1098
transport = transport.clone('quack')
1099
branch = self.make_remote_branch(transport, client)
1101
self.assertFinished(client)
1104
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1106
def test_get_physical_lock_status_yes(self):
1107
transport = MemoryTransport()
1108
client = FakeClient(transport.base)
1109
client.add_expected_call(
1110
'Branch.get_stacked_on_url', ('quack/',),
1111
'error', ('NotStacked',))
1112
client.add_expected_call(
1113
'Branch.get_physical_lock_status', ('quack/',),
1114
'success', ('yes',))
1115
transport.mkdir('quack')
1116
transport = transport.clone('quack')
1117
branch = self.make_remote_branch(transport, client)
1118
result = branch.get_physical_lock_status()
1119
self.assertFinished(client)
1120
self.assertEqual(True, result)
1122
def test_get_physical_lock_status_no(self):
1123
transport = MemoryTransport()
1124
client = FakeClient(transport.base)
1125
client.add_expected_call(
1126
'Branch.get_stacked_on_url', ('quack/',),
1127
'error', ('NotStacked',))
1128
client.add_expected_call(
1129
'Branch.get_physical_lock_status', ('quack/',),
1131
transport.mkdir('quack')
1132
transport = transport.clone('quack')
1133
branch = self.make_remote_branch(transport, client)
1134
result = branch.get_physical_lock_status()
1135
self.assertFinished(client)
1136
self.assertEqual(False, result)
970
1139
class TestBranchGetParent(RemoteBranchTestCase):
972
1141
def test_no_parent(self):
1143
1312
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1315
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1317
def test_uses_last_revision_info_and_tags_by_default(self):
1318
transport = MemoryTransport()
1319
client = FakeClient(transport.base)
1320
client.add_expected_call(
1321
'Branch.get_stacked_on_url', ('quack/',),
1322
'error', ('NotStacked',))
1323
client.add_expected_call(
1324
'Branch.last_revision_info', ('quack/',),
1325
'success', ('ok', '1', 'rev-tip'))
1326
client.add_expected_call(
1327
'Branch.get_config_file', ('quack/',),
1328
'success', ('ok',), '')
1329
transport.mkdir('quack')
1330
transport = transport.clone('quack')
1331
branch = self.make_remote_branch(transport, client)
1332
result = branch.heads_to_fetch()
1333
self.assertFinished(client)
1334
self.assertEqual((set(['rev-tip']), set()), result)
1336
def test_uses_last_revision_info_and_tags_when_set(self):
1337
transport = MemoryTransport()
1338
client = FakeClient(transport.base)
1339
client.add_expected_call(
1340
'Branch.get_stacked_on_url', ('quack/',),
1341
'error', ('NotStacked',))
1342
client.add_expected_call(
1343
'Branch.last_revision_info', ('quack/',),
1344
'success', ('ok', '1', 'rev-tip'))
1345
client.add_expected_call(
1346
'Branch.get_config_file', ('quack/',),
1347
'success', ('ok',), 'branch.fetch_tags = True')
1348
# XXX: this will break if the default format's serialization of tags
1349
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1350
client.add_expected_call(
1351
'Branch.get_tags_bytes', ('quack/',),
1352
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1353
transport.mkdir('quack')
1354
transport = transport.clone('quack')
1355
branch = self.make_remote_branch(transport, client)
1356
result = branch.heads_to_fetch()
1357
self.assertFinished(client)
1359
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1361
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1362
transport = MemoryTransport()
1363
client = FakeClient(transport.base)
1364
client.add_expected_call(
1365
'Branch.get_stacked_on_url', ('quack/',),
1366
'error', ('NotStacked',))
1367
client.add_expected_call(
1368
'Branch.heads_to_fetch', ('quack/',),
1369
'success', (['tip'], ['tagged-1', 'tagged-2']))
1370
transport.mkdir('quack')
1371
transport = transport.clone('quack')
1372
branch = self.make_remote_branch(transport, client)
1373
branch._format._use_default_local_heads_to_fetch = lambda: False
1374
result = branch.heads_to_fetch()
1375
self.assertFinished(client)
1376
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1378
def make_branch_with_tags(self):
1379
self.setup_smart_server_with_call_log()
1380
# Make a branch with a single revision.
1381
builder = self.make_branch_builder('foo')
1382
builder.start_series()
1383
builder.build_snapshot('tip', None, [
1384
('add', ('', 'root-id', 'directory', ''))])
1385
builder.finish_series()
1386
branch = builder.get_branch()
1387
# Add two tags to that branch
1388
branch.tags.set_tag('tag-1', 'rev-1')
1389
branch.tags.set_tag('tag-2', 'rev-2')
1392
def test_backwards_compatible(self):
1393
branch = self.make_branch_with_tags()
1394
c = branch.get_config()
1395
c.set_user_option('branch.fetch_tags', 'True')
1396
self.addCleanup(branch.lock_read().unlock)
1397
# Disable the heads_to_fetch verb
1398
verb = 'Branch.heads_to_fetch'
1399
self.disable_verb(verb)
1400
self.reset_smart_call_log()
1401
result = branch.heads_to_fetch()
1402
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1404
['Branch.last_revision_info', 'Branch.get_config_file',
1405
'Branch.get_tags_bytes'],
1406
[call.call.method for call in self.hpss_calls])
1408
def test_backwards_compatible_no_tags(self):
1409
branch = self.make_branch_with_tags()
1410
c = branch.get_config()
1411
c.set_user_option('branch.fetch_tags', 'False')
1412
self.addCleanup(branch.lock_read().unlock)
1413
# Disable the heads_to_fetch verb
1414
verb = 'Branch.heads_to_fetch'
1415
self.disable_verb(verb)
1416
self.reset_smart_call_log()
1417
result = branch.heads_to_fetch()
1418
self.assertEqual((set(['tip']), set()), result)
1420
['Branch.last_revision_info', 'Branch.get_config_file'],
1421
[call.call.method for call in self.hpss_calls])
1146
1424
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1426
def test_empty_branch(self):
1652
1924
branch.unlock()
1653
1925
self.assertFinished(client)
1927
def test_set_option_with_dict(self):
1928
client = FakeClient()
1929
client.add_expected_call(
1930
'Branch.get_stacked_on_url', ('memory:///',),
1931
'error', ('NotStacked',),)
1932
client.add_expected_call(
1933
'Branch.lock_write', ('memory:///', '', ''),
1934
'success', ('ok', 'branch token', 'repo token'))
1935
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1936
client.add_expected_call(
1937
'Branch.set_config_option_dict', ('memory:///', 'branch token',
1938
'repo token', encoded_dict_value, 'foo', ''),
1940
client.add_expected_call(
1941
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1943
transport = MemoryTransport()
1944
branch = self.make_remote_branch(transport, client)
1946
config = branch._get_config()
1948
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1951
self.assertFinished(client)
1655
1953
def test_backwards_compat_set_option(self):
1656
1954
self.setup_smart_server_with_call_log()
1657
1955
branch = self.make_branch('.')
1664
1962
self.assertLength(10, self.hpss_calls)
1665
1963
self.assertEqual('value', branch._get_config().get_option('name'))
1965
def test_backwards_compat_set_option_with_dict(self):
1966
self.setup_smart_server_with_call_log()
1967
branch = self.make_branch('.')
1968
verb = 'Branch.set_config_option_dict'
1969
self.disable_verb(verb)
1971
self.addCleanup(branch.unlock)
1972
self.reset_smart_call_log()
1973
config = branch._get_config()
1974
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1975
config.set_option(value_dict, 'name')
1976
self.assertLength(10, self.hpss_calls)
1977
self.assertEqual(value_dict, branch._get_config().get_option('name'))
1980
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
1982
def test_get_branch_conf(self):
1983
# in an empty branch we decode the response properly
1984
client = FakeClient()
1985
client.add_expected_call(
1986
'Branch.get_stacked_on_url', ('memory:///',),
1987
'error', ('NotStacked',),)
1988
client.add_success_response_with_body('# config file body', 'ok')
1989
transport = MemoryTransport()
1990
branch = self.make_remote_branch(transport, client)
1991
config = branch.get_config_stack()
1993
config.get("log_format")
1995
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1996
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1999
def test_set_branch_conf(self):
2000
client = FakeClient()
2001
client.add_expected_call(
2002
'Branch.get_stacked_on_url', ('memory:///',),
2003
'error', ('NotStacked',),)
2004
client.add_expected_call(
2005
'Branch.lock_write', ('memory:///', '', ''),
2006
'success', ('ok', 'branch token', 'repo token'))
2007
client.add_expected_call(
2008
'Branch.get_config_file', ('memory:///', ),
2009
'success', ('ok', ), "# line 1\n")
2010
client.add_expected_call(
2011
'Branch.put_config_file', ('memory:///', 'branch token',
2014
client.add_expected_call(
2015
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2017
transport = MemoryTransport()
2018
branch = self.make_remote_branch(transport, client)
2020
config = branch.get_config_stack()
2021
config.set('email', 'The Dude <lebowski@example.com>')
2023
self.assertFinished(client)
2025
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2026
('call', 'Branch.lock_write', ('memory:///', '', '')),
2027
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2028
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2029
('memory:///', 'branch token', 'repo token'),
2030
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2031
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2035
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2050
self.assertFinished(client)
2053
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2055
def test_simple(self):
2056
transport = MemoryTransport()
2057
client = FakeClient(transport.base)
2058
client.add_expected_call(
2059
'Branch.get_stacked_on_url', ('quack/',),
2060
'error', ('NotStacked',),)
2061
client.add_expected_call(
2062
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2063
'success', ('ok', '0',),)
2064
client.add_expected_call(
2065
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2066
'error', ('NoSuchRevision', 'unknown',),)
2067
transport.mkdir('quack')
2068
transport = transport.clone('quack')
2069
branch = self.make_remote_branch(transport, client)
2070
self.assertEquals(0, branch.revision_id_to_revno('null:'))
2071
self.assertRaises(errors.NoSuchRevision,
2072
branch.revision_id_to_revno, 'unknown')
2073
self.assertFinished(client)
2075
def test_dotted(self):
2076
transport = MemoryTransport()
2077
client = FakeClient(transport.base)
2078
client.add_expected_call(
2079
'Branch.get_stacked_on_url', ('quack/',),
2080
'error', ('NotStacked',),)
2081
client.add_expected_call(
2082
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2083
'success', ('ok', '0',),)
2084
client.add_expected_call(
2085
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2086
'error', ('NoSuchRevision', 'unknown',),)
2087
transport.mkdir('quack')
2088
transport = transport.clone('quack')
2089
branch = self.make_remote_branch(transport, client)
2090
self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
2091
self.assertRaises(errors.NoSuchRevision,
2092
branch.revision_id_to_dotted_revno, 'unknown')
2093
self.assertFinished(client)
2095
def test_dotted_no_smart_verb(self):
2096
self.setup_smart_server_with_call_log()
2097
branch = self.make_branch('.')
2098
self.disable_verb('Branch.revision_id_to_revno')
2099
self.reset_smart_call_log()
2100
self.assertEquals((0, ),
2101
branch.revision_id_to_dotted_revno('null:'))
2102
self.assertLength(7, self.hpss_calls)
1686
2105
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2107
def test__get_config(self):
1828
2247
class TestRepositoryFormat(TestRemoteRepository):
1830
2249
def test_fast_delta(self):
1831
true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
2250
true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2251
true_format = RemoteRepositoryFormat()
1833
2252
true_format._network_name = true_name
1834
2253
self.assertEqual(True, true_format.fast_deltas)
1835
false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
2254
false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2255
false_format = RemoteRepositoryFormat()
1837
2256
false_format._network_name = false_name
1838
2257
self.assertEqual(False, false_format.fast_deltas)
1840
2259
def test_get_format_description(self):
1841
2260
remote_repo_format = RemoteRepositoryFormat()
1842
real_format = repository.RepositoryFormat.get_default_format()
2261
real_format = repository.format_registry.get_default()
1843
2262
remote_repo_format._network_name = real_format.network_name()
1844
2263
self.assertEqual(remoted_description(real_format),
1845
2264
remote_repo_format.get_format_description())
2267
class TestRepositoryAllRevisionIds(TestRemoteRepository):
2269
def test_empty(self):
2270
transport_path = 'quack'
2271
repo, client = self.setup_fake_client_and_repository(transport_path)
2272
client.add_success_response_with_body('', 'ok')
2273
self.assertEquals([], repo.all_revision_ids())
2275
[('call_expecting_body', 'Repository.all_revision_ids',
2279
def test_with_some_content(self):
2280
transport_path = 'quack'
2281
repo, client = self.setup_fake_client_and_repository(transport_path)
2282
client.add_success_response_with_body(
2283
'rev1\nrev2\nanotherrev\n', 'ok')
2284
self.assertEquals(["rev1", "rev2", "anotherrev"],
2285
repo.all_revision_ids())
2287
[('call_expecting_body', 'Repository.all_revision_ids',
1848
2292
class TestRepositoryGatherStats(TestRemoteRepository):
1850
2294
def test_revid_none(self):
2350
class TestRepositoryBreakLock(TestRemoteRepository):
2352
def test_break_lock(self):
2353
transport_path = 'quack'
2354
repo, client = self.setup_fake_client_and_repository(transport_path)
2355
client.add_success_response('ok')
2358
[('call', 'Repository.break_lock', ('quack/',))],
2362
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2364
def test_get_serializer_format(self):
2365
transport_path = 'hill'
2366
repo, client = self.setup_fake_client_and_repository(transport_path)
2367
client.add_success_response('ok', '7')
2368
self.assertEquals('7', repo.get_serializer_format())
2370
[('call', 'VersionedFileRepository.get_serializer_format',
2375
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2377
def test_text(self):
2378
# ('ok',), body with signature text
2379
transport_path = 'quack'
2380
repo, client = self.setup_fake_client_and_repository(transport_path)
2381
client.add_success_response_with_body(
2383
self.assertEquals("THETEXT", repo.get_signature_text("revid"))
2385
[('call_expecting_body', 'Repository.get_revision_signature_text',
2386
('quack/', 'revid'))],
2389
def test_no_signature(self):
2390
transport_path = 'quick'
2391
repo, client = self.setup_fake_client_and_repository(transport_path)
2392
client.add_error_response('nosuchrevision', 'unknown')
2393
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2396
[('call_expecting_body', 'Repository.get_revision_signature_text',
2397
('quick/', 'unknown'))],
1906
2401
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2403
def test_get_graph(self):
2115
2663
self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2666
class TestRepositoryGetRevisions(TestRemoteRepository):
2668
def test_hpss_missing_revision(self):
2669
transport_path = 'quack'
2670
repo, client = self.setup_fake_client_and_repository(transport_path)
2671
client.add_success_response_with_body(
2673
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2674
['somerev1', 'anotherrev2'])
2676
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2677
('quack/', ), "somerev1\nanotherrev2")],
2680
def test_hpss_get_single_revision(self):
2681
transport_path = 'quack'
2682
repo, client = self.setup_fake_client_and_repository(transport_path)
2683
somerev1 = Revision("somerev1")
2684
somerev1.committer = "Joe Committer <joe@example.com>"
2685
somerev1.timestamp = 1321828927
2686
somerev1.timezone = -60
2687
somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
2688
somerev1.message = "Message"
2689
body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
2691
# Split up body into two bits to make sure the zlib compression object
2692
# gets data fed twice.
2693
client.add_success_response_with_body(
2694
[body[:10], body[10:]], 'ok', '10')
2695
revs = repo.get_revisions(['somerev1'])
2696
self.assertEquals(revs, [somerev1])
2698
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2699
('quack/', ), "somerev1")],
2118
2703
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2120
2705
def test_null_revision(self):
2270
2856
call.call.method == verb])
2859
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2861
def test_has_signature_for_revision_id(self):
2862
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2863
transport_path = 'quack'
2864
repo, client = self.setup_fake_client_and_repository(transport_path)
2865
client.add_success_response('yes')
2866
result = repo.has_signature_for_revision_id('A')
2868
[('call', 'Repository.has_signature_for_revision_id',
2871
self.assertEqual(True, result)
2873
def test_is_not_shared(self):
2874
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2875
transport_path = 'qwack'
2876
repo, client = self.setup_fake_client_and_repository(transport_path)
2877
client.add_success_response('no')
2878
result = repo.has_signature_for_revision_id('A')
2880
[('call', 'Repository.has_signature_for_revision_id',
2883
self.assertEqual(False, result)
2886
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2888
def test_get_physical_lock_status_yes(self):
2889
transport_path = 'qwack'
2890
repo, client = self.setup_fake_client_and_repository(transport_path)
2891
client.add_success_response('yes')
2892
result = repo.get_physical_lock_status()
2894
[('call', 'Repository.get_physical_lock_status',
2897
self.assertEqual(True, result)
2899
def test_get_physical_lock_status_no(self):
2900
transport_path = 'qwack'
2901
repo, client = self.setup_fake_client_and_repository(transport_path)
2902
client.add_success_response('no')
2903
result = repo.get_physical_lock_status()
2905
[('call', 'Repository.get_physical_lock_status',
2908
self.assertEqual(False, result)
2273
2911
class TestRepositoryIsShared(TestRemoteRepository):
2275
2913
def test_is_shared(self):
2295
2933
self.assertEqual(False, result)
2936
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
2938
def test_make_working_trees(self):
2939
# ('yes', ) for Repository.make_working_trees -> 'True'.
2940
transport_path = 'quack'
2941
repo, client = self.setup_fake_client_and_repository(transport_path)
2942
client.add_success_response('yes')
2943
result = repo.make_working_trees()
2945
[('call', 'Repository.make_working_trees', ('quack/',))],
2947
self.assertEqual(True, result)
2949
def test_no_working_trees(self):
2950
# ('no', ) for Repository.make_working_trees -> 'False'.
2951
transport_path = 'qwack'
2952
repo, client = self.setup_fake_client_and_repository(transport_path)
2953
client.add_success_response('no')
2954
result = repo.make_working_trees()
2956
[('call', 'Repository.make_working_trees', ('qwack/',))],
2958
self.assertEqual(False, result)
2298
2961
class TestRepositoryLockWrite(TestRemoteRepository):
2300
2963
def test_lock_write(self):
2301
2964
transport_path = 'quack'
2302
2965
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
2966
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
2967
token = repo.lock_write().repository_token
2305
2968
self.assertEqual(
2306
2969
[('call', 'Repository.lock_write', ('quack/', ''))],
2308
self.assertEqual('a token', result)
2971
self.assertEqual('a token', token)
2310
2973
def test_lock_write_already_locked(self):
2311
2974
transport_path = 'quack'
2992
class TestRepositoryWriteGroups(TestRemoteRepository):
2994
def test_start_write_group(self):
2995
transport_path = 'quack'
2996
repo, client = self.setup_fake_client_and_repository(transport_path)
2997
client.add_expected_call(
2998
'Repository.lock_write', ('quack/', ''),
2999
'success', ('ok', 'a token'))
3000
client.add_expected_call(
3001
'Repository.start_write_group', ('quack/', 'a token'),
3002
'success', ('ok', ('token1', )))
3004
repo.start_write_group()
3006
def test_start_write_group_unsuspendable(self):
3007
# Some repositories do not support suspending write
3008
# groups. For those, fall back to the "real" repository.
3009
transport_path = 'quack'
3010
repo, client = self.setup_fake_client_and_repository(transport_path)
3011
def stub_ensure_real():
3012
client._calls.append(('_ensure_real',))
3013
repo._real_repository = _StubRealPackRepository(client._calls)
3014
repo._ensure_real = stub_ensure_real
3015
client.add_expected_call(
3016
'Repository.lock_write', ('quack/', ''),
3017
'success', ('ok', 'a token'))
3018
client.add_expected_call(
3019
'Repository.start_write_group', ('quack/', 'a token'),
3020
'error', ('UnsuspendableWriteGroup',))
3022
repo.start_write_group()
3023
self.assertEquals(client._calls[-2:], [
3025
('start_write_group',)])
3027
def test_commit_write_group(self):
3028
transport_path = 'quack'
3029
repo, client = self.setup_fake_client_and_repository(transport_path)
3030
client.add_expected_call(
3031
'Repository.lock_write', ('quack/', ''),
3032
'success', ('ok', 'a token'))
3033
client.add_expected_call(
3034
'Repository.start_write_group', ('quack/', 'a token'),
3035
'success', ('ok', ['token1']))
3036
client.add_expected_call(
3037
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3040
repo.start_write_group()
3041
repo.commit_write_group()
3043
def test_abort_write_group(self):
3044
transport_path = 'quack'
3045
repo, client = self.setup_fake_client_and_repository(transport_path)
3046
client.add_expected_call(
3047
'Repository.lock_write', ('quack/', ''),
3048
'success', ('ok', 'a token'))
3049
client.add_expected_call(
3050
'Repository.start_write_group', ('quack/', 'a token'),
3051
'success', ('ok', ['token1']))
3052
client.add_expected_call(
3053
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3056
repo.start_write_group()
3057
repo.abort_write_group(False)
3059
def test_suspend_write_group(self):
3060
transport_path = 'quack'
3061
repo, client = self.setup_fake_client_and_repository(transport_path)
3062
self.assertEquals([], repo.suspend_write_group())
3064
def test_resume_write_group(self):
3065
transport_path = 'quack'
3066
repo, client = self.setup_fake_client_and_repository(transport_path)
3067
client.add_expected_call(
3068
'Repository.lock_write', ('quack/', ''),
3069
'success', ('ok', 'a token'))
3070
client.add_expected_call(
3071
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3074
repo.resume_write_group(['token1'])
2329
3077
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3079
def test_backwards_compat(self):
2895
3697
expected_error = errors.PermissionDenied(path, extra)
2896
3698
self.assertEqual(expected_error, translated_error)
3700
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3702
def test_NoSuchFile_context_path(self):
3703
local_path = "local path"
3704
translated_error = self.translateTuple(('ReadError', "remote path"),
3706
expected_error = errors.ReadError(local_path)
3707
self.assertEqual(expected_error, translated_error)
3709
def test_NoSuchFile_without_context(self):
3710
remote_path = "remote path"
3711
translated_error = self.translateTuple(('ReadError', remote_path))
3712
expected_error = errors.ReadError(remote_path)
3713
self.assertEqual(expected_error, translated_error)
3715
def test_ReadOnlyError(self):
3716
translated_error = self.translateTuple(('ReadOnlyError',))
3717
expected_error = errors.TransportNotPossible("readonly transport")
3718
self.assertEqual(expected_error, translated_error)
3720
def test_MemoryError(self):
3721
translated_error = self.translateTuple(('MemoryError',))
3722
self.assertStartsWith(str(translated_error),
3723
"remote server out of memory")
3725
def test_generic_IndexError_no_classname(self):
3726
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3727
translated_error = self.translateErrorFromSmartServer(err)
3728
expected_error = errors.UnknownErrorFromSmartServer(err)
3729
self.assertEqual(expected_error, translated_error)
3731
# GZ 2011-03-02: TODO test generic non-ascii error string
3733
def test_generic_KeyError(self):
3734
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3735
translated_error = self.translateErrorFromSmartServer(err)
3736
expected_error = errors.UnknownErrorFromSmartServer(err)
3737
self.assertEqual(expected_error, translated_error)
2899
3740
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3741
"""Unit tests for bzrlib.remote._translate_error's robustness.
3143
3986
def test_copy_content_into_avoids_revision_history(self):
3144
3987
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
3988
builder = self.make_branch_builder('remote')
3989
builder.build_commit(message="Commit.")
3147
3990
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
3991
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
3992
local.repository.fetch(remote_branch.repository)
3150
3993
self.hpss_calls = []
3151
3994
remote_branch.copy_content_into(local)
3152
3995
self.assertFalse('Branch.revision_history' in self.hpss_calls)
3997
def test_fetch_everything_needs_just_one_call(self):
3998
local = self.make_branch('local')
3999
builder = self.make_branch_builder('remote')
4000
builder.build_commit(message="Commit.")
4001
remote_branch_url = self.smart_server.get_url() + 'remote'
4002
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4003
self.hpss_calls = []
4004
local.repository.fetch(
4005
remote_branch.repository,
4006
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
4007
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4009
def override_verb(self, verb_name, verb):
4010
request_handlers = request.request_handlers
4011
orig_verb = request_handlers.get(verb_name)
4012
request_handlers.register(verb_name, verb, override_existing=True)
4013
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4014
override_existing=True)
4016
def test_fetch_everything_backwards_compat(self):
4017
"""Can fetch with EverythingResult even with pre 2.4 servers.
4019
Pre-2.4 do not support 'everything' searches with the
4020
Repository.get_stream_1.19 verb.
4023
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4024
"""A version of the Repository.get_stream_1.19 verb patched to
4025
reject 'everything' searches the way 2.3 and earlier do.
4027
def recreate_search(self, repository, search_bytes,
4028
discard_excess=False):
4029
verb_log.append(search_bytes.split('\n', 1)[0])
4030
if search_bytes == 'everything':
4032
request.FailedSmartServerResponse(('BadSearch',)))
4033
return super(OldGetStreamVerb,
4034
self).recreate_search(repository, search_bytes,
4035
discard_excess=discard_excess)
4036
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4037
local = self.make_branch('local')
4038
builder = self.make_branch_builder('remote')
4039
builder.build_commit(message="Commit.")
4040
remote_branch_url = self.smart_server.get_url() + 'remote'
4041
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4042
self.hpss_calls = []
4043
local.repository.fetch(
4044
remote_branch.repository,
4045
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
4046
# make sure the overridden verb was used
4047
self.assertLength(1, verb_log)
4048
# more than one HPSS call is needed, but because it's a VFS callback
4049
# its hard to predict exactly how many.
4050
self.assertTrue(len(self.hpss_calls) > 1)
4053
class TestUpdateBoundBranchWithModifiedBoundLocation(
4054
tests.TestCaseWithTransport):
4055
"""Ensure correct handling of bound_location modifications.
4057
This is tested against a smart server as http://pad.lv/786980 was about a
4058
ReadOnlyError (write attempt during a read-only transaction) which can only
4059
happen in this context.
4063
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4064
self.transport_server = test_server.SmartTCPServer_for_testing
4066
def make_master_and_checkout(self, master_name, checkout_name):
4067
# Create the master branch and its associated checkout
4068
self.master = self.make_branch_and_tree(master_name)
4069
self.checkout = self.master.branch.create_checkout(checkout_name)
4070
# Modify the master branch so there is something to update
4071
self.master.commit('add stuff')
4072
self.last_revid = self.master.commit('even more stuff')
4073
self.bound_location = self.checkout.branch.get_bound_location()
4075
def assertUpdateSucceeds(self, new_location):
4076
self.checkout.branch.set_bound_location(new_location)
4077
self.checkout.update()
4078
self.assertEquals(self.last_revid, self.checkout.last_revision())
4080
def test_without_final_slash(self):
4081
self.make_master_and_checkout('master', 'checkout')
4082
# For unclear reasons some users have a bound_location without a final
4083
# '/', simulate that by forcing such a value
4084
self.assertEndsWith(self.bound_location, '/')
4085
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4087
def test_plus_sign(self):
4088
self.make_master_and_checkout('+master', 'checkout')
4089
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4091
def test_tilda(self):
4092
# Embed ~ in the middle of the path just to avoid any $HOME
4094
self.make_master_and_checkout('mas~ter', 'checkout')
4095
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4098
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4100
def test_no_context(self):
4101
class OutOfCoffee(errors.BzrError):
4102
"""A dummy exception for testing."""
4104
def __init__(self, urgency):
4105
self.urgency = urgency
4106
remote.no_context_error_translators.register("OutOfCoffee",
4107
lambda err: OutOfCoffee(err.error_args[0]))
4108
transport = MemoryTransport()
4109
client = FakeClient(transport.base)
4110
client.add_expected_call(
4111
'Branch.get_stacked_on_url', ('quack/',),
4112
'error', ('NotStacked',))
4113
client.add_expected_call(
4114
'Branch.last_revision_info',
4116
'error', ('OutOfCoffee', 'low'))
4117
transport.mkdir('quack')
4118
transport = transport.clone('quack')
4119
branch = self.make_remote_branch(transport, client)
4120
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4121
self.assertFinished(client)
4123
def test_with_context(self):
4124
class OutOfTea(errors.BzrError):
4125
def __init__(self, branch, urgency):
4126
self.branch = branch
4127
self.urgency = urgency
4128
remote.error_translators.register("OutOfTea",
4129
lambda err, find, path: OutOfTea(err.error_args[0],
4131
transport = MemoryTransport()
4132
client = FakeClient(transport.base)
4133
client.add_expected_call(
4134
'Branch.get_stacked_on_url', ('quack/',),
4135
'error', ('NotStacked',))
4136
client.add_expected_call(
4137
'Branch.last_revision_info',
4139
'error', ('OutOfTea', 'low'))
4140
transport.mkdir('quack')
4141
transport = transport.clone('quack')
4142
branch = self.make_remote_branch(transport, client)
4143
self.assertRaises(OutOfTea, branch.last_revision_info)
4144
self.assertFinished(client)
4147
class TestRepositoryPack(TestRemoteRepository):
4149
def test_pack(self):
4150
transport_path = 'quack'
4151
repo, client = self.setup_fake_client_and_repository(transport_path)
4152
client.add_expected_call(
4153
'Repository.lock_write', ('quack/', ''),
4154
'success', ('ok', 'token'))
4155
client.add_expected_call(
4156
'Repository.pack', ('quack/', 'token', 'False'),
4157
'success', ('ok',), )
4158
client.add_expected_call(
4159
'Repository.unlock', ('quack/', 'token'),
4160
'success', ('ok', ))
4163
def test_pack_with_hint(self):
4164
transport_path = 'quack'
4165
repo, client = self.setup_fake_client_and_repository(transport_path)
4166
client.add_expected_call(
4167
'Repository.lock_write', ('quack/', ''),
4168
'success', ('ok', 'token'))
4169
client.add_expected_call(
4170
'Repository.pack', ('quack/', 'token', 'False'),
4171
'success', ('ok',), )
4172
client.add_expected_call(
4173
'Repository.unlock', ('quack/', 'token', 'False'),
4174
'success', ('ok', ))
4175
repo.pack(['hinta', 'hintb'])