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 TestBzrDirCheckoutMetaDir(TestRemote):
508
def test__get_checkout_format(self):
509
transport = MemoryTransport()
510
client = FakeClient(transport.base)
511
reference_bzrdir_format = bzrdir.format_registry.get('default')()
512
control_name = reference_bzrdir_format.network_name()
513
client.add_expected_call(
514
'BzrDir.checkout_metadir', ('quack/', ),
515
'success', (control_name, '', ''))
516
transport.mkdir('quack')
517
transport = transport.clone('quack')
518
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
520
result = a_bzrdir.checkout_metadir()
521
# We should have got a reference control dir with default branch and
522
# repository formats.
523
self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
524
self.assertEqual(None, result._repository_format)
525
self.assertEqual(None, result._branch_format)
526
self.assertFinished(client)
528
def test_unknown_format(self):
529
transport = MemoryTransport()
530
client = FakeClient(transport.base)
531
client.add_expected_call(
532
'BzrDir.checkout_metadir', ('quack/',),
533
'success', ('dontknow', '', ''))
534
transport.mkdir('quack')
535
transport = transport.clone('quack')
536
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
538
self.assertRaises(errors.UnknownFormatError,
539
a_bzrdir.checkout_metadir)
540
self.assertFinished(client)
543
class TestBzrDirDestroyBranch(TestRemote):
545
def test_destroy_default(self):
546
transport = self.get_transport('quack')
547
referenced = self.make_branch('referenced')
548
client = FakeClient(transport.base)
549
client.add_expected_call(
550
'BzrDir.destroy_branch', ('quack/', ),
552
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
554
a_bzrdir.destroy_branch()
555
self.assertFinished(client)
557
def test_destroy_named(self):
558
transport = self.get_transport('quack')
559
referenced = self.make_branch('referenced')
560
client = FakeClient(transport.base)
561
client.add_expected_call(
562
'BzrDir.destroy_branch', ('quack/', "foo"),
564
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
566
a_bzrdir.destroy_branch("foo")
567
self.assertFinished(client)
570
class TestBzrDirHasWorkingTree(TestRemote):
572
def test_has_workingtree(self):
573
transport = self.get_transport('quack')
574
client = FakeClient(transport.base)
575
client.add_expected_call(
576
'BzrDir.has_workingtree', ('quack/',),
577
'success', ('yes',)),
578
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
580
self.assertTrue(a_bzrdir.has_workingtree())
581
self.assertFinished(client)
583
def test_no_workingtree(self):
584
transport = self.get_transport('quack')
585
client = FakeClient(transport.base)
586
client.add_expected_call(
587
'BzrDir.has_workingtree', ('quack/',),
589
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
591
self.assertFalse(a_bzrdir.has_workingtree())
592
self.assertFinished(client)
595
class TestBzrDirDestroyRepository(TestRemote):
597
def test_destroy_repository(self):
598
transport = self.get_transport('quack')
599
client = FakeClient(transport.base)
600
client.add_expected_call(
601
'BzrDir.destroy_repository', ('quack/',),
603
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
605
a_bzrdir.destroy_repository()
606
self.assertFinished(client)
484
609
class TestBzrDirOpen(TestRemote):
967
1120
return RemoteBranch(bzrdir, repo, _client=client, format=format)
1123
class TestBranchBreakLock(RemoteBranchTestCase):
1125
def test_break_lock(self):
1126
transport_path = 'quack'
1127
transport = MemoryTransport()
1128
client = FakeClient(transport.base)
1129
client.add_expected_call(
1130
'Branch.get_stacked_on_url', ('quack/',),
1131
'error', ('NotStacked',))
1132
client.add_expected_call(
1133
'Branch.break_lock', ('quack/',),
1135
transport.mkdir('quack')
1136
transport = transport.clone('quack')
1137
branch = self.make_remote_branch(transport, client)
1139
self.assertFinished(client)
1142
class TestBranchGetPhysicalLockStatus(RemoteBranchTestCase):
1144
def test_get_physical_lock_status_yes(self):
1145
transport = MemoryTransport()
1146
client = FakeClient(transport.base)
1147
client.add_expected_call(
1148
'Branch.get_stacked_on_url', ('quack/',),
1149
'error', ('NotStacked',))
1150
client.add_expected_call(
1151
'Branch.get_physical_lock_status', ('quack/',),
1152
'success', ('yes',))
1153
transport.mkdir('quack')
1154
transport = transport.clone('quack')
1155
branch = self.make_remote_branch(transport, client)
1156
result = branch.get_physical_lock_status()
1157
self.assertFinished(client)
1158
self.assertEqual(True, result)
1160
def test_get_physical_lock_status_no(self):
1161
transport = MemoryTransport()
1162
client = FakeClient(transport.base)
1163
client.add_expected_call(
1164
'Branch.get_stacked_on_url', ('quack/',),
1165
'error', ('NotStacked',))
1166
client.add_expected_call(
1167
'Branch.get_physical_lock_status', ('quack/',),
1169
transport.mkdir('quack')
1170
transport = transport.clone('quack')
1171
branch = self.make_remote_branch(transport, client)
1172
result = branch.get_physical_lock_status()
1173
self.assertFinished(client)
1174
self.assertEqual(False, result)
970
1177
class TestBranchGetParent(RemoteBranchTestCase):
972
1179
def test_no_parent(self):
1143
1350
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1353
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1355
def test_uses_last_revision_info_and_tags_by_default(self):
1356
transport = MemoryTransport()
1357
client = FakeClient(transport.base)
1358
client.add_expected_call(
1359
'Branch.get_stacked_on_url', ('quack/',),
1360
'error', ('NotStacked',))
1361
client.add_expected_call(
1362
'Branch.last_revision_info', ('quack/',),
1363
'success', ('ok', '1', 'rev-tip'))
1364
client.add_expected_call(
1365
'Branch.get_config_file', ('quack/',),
1366
'success', ('ok',), '')
1367
transport.mkdir('quack')
1368
transport = transport.clone('quack')
1369
branch = self.make_remote_branch(transport, client)
1370
result = branch.heads_to_fetch()
1371
self.assertFinished(client)
1372
self.assertEqual((set(['rev-tip']), set()), result)
1374
def test_uses_last_revision_info_and_tags_when_set(self):
1375
transport = MemoryTransport()
1376
client = FakeClient(transport.base)
1377
client.add_expected_call(
1378
'Branch.get_stacked_on_url', ('quack/',),
1379
'error', ('NotStacked',))
1380
client.add_expected_call(
1381
'Branch.last_revision_info', ('quack/',),
1382
'success', ('ok', '1', 'rev-tip'))
1383
client.add_expected_call(
1384
'Branch.get_config_file', ('quack/',),
1385
'success', ('ok',), 'branch.fetch_tags = True')
1386
# XXX: this will break if the default format's serialization of tags
1387
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1388
client.add_expected_call(
1389
'Branch.get_tags_bytes', ('quack/',),
1390
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1391
transport.mkdir('quack')
1392
transport = transport.clone('quack')
1393
branch = self.make_remote_branch(transport, client)
1394
result = branch.heads_to_fetch()
1395
self.assertFinished(client)
1397
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1399
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1400
transport = MemoryTransport()
1401
client = FakeClient(transport.base)
1402
client.add_expected_call(
1403
'Branch.get_stacked_on_url', ('quack/',),
1404
'error', ('NotStacked',))
1405
client.add_expected_call(
1406
'Branch.heads_to_fetch', ('quack/',),
1407
'success', (['tip'], ['tagged-1', 'tagged-2']))
1408
transport.mkdir('quack')
1409
transport = transport.clone('quack')
1410
branch = self.make_remote_branch(transport, client)
1411
branch._format._use_default_local_heads_to_fetch = lambda: False
1412
result = branch.heads_to_fetch()
1413
self.assertFinished(client)
1414
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1416
def make_branch_with_tags(self):
1417
self.setup_smart_server_with_call_log()
1418
# Make a branch with a single revision.
1419
builder = self.make_branch_builder('foo')
1420
builder.start_series()
1421
builder.build_snapshot('tip', None, [
1422
('add', ('', 'root-id', 'directory', ''))])
1423
builder.finish_series()
1424
branch = builder.get_branch()
1425
# Add two tags to that branch
1426
branch.tags.set_tag('tag-1', 'rev-1')
1427
branch.tags.set_tag('tag-2', 'rev-2')
1430
def test_backwards_compatible(self):
1431
branch = self.make_branch_with_tags()
1432
c = branch.get_config()
1433
c.set_user_option('branch.fetch_tags', 'True')
1434
self.addCleanup(branch.lock_read().unlock)
1435
# Disable the heads_to_fetch verb
1436
verb = 'Branch.heads_to_fetch'
1437
self.disable_verb(verb)
1438
self.reset_smart_call_log()
1439
result = branch.heads_to_fetch()
1440
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1442
['Branch.last_revision_info', 'Branch.get_config_file',
1443
'Branch.get_tags_bytes'],
1444
[call.call.method for call in self.hpss_calls])
1446
def test_backwards_compatible_no_tags(self):
1447
branch = self.make_branch_with_tags()
1448
c = branch.get_config()
1449
c.set_user_option('branch.fetch_tags', 'False')
1450
self.addCleanup(branch.lock_read().unlock)
1451
# Disable the heads_to_fetch verb
1452
verb = 'Branch.heads_to_fetch'
1453
self.disable_verb(verb)
1454
self.reset_smart_call_log()
1455
result = branch.heads_to_fetch()
1456
self.assertEqual((set(['tip']), set()), result)
1458
['Branch.last_revision_info', 'Branch.get_config_file'],
1459
[call.call.method for call in self.hpss_calls])
1146
1462
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1464
def test_empty_branch(self):
1652
1962
branch.unlock()
1653
1963
self.assertFinished(client)
1965
def test_set_option_with_dict(self):
1966
client = FakeClient()
1967
client.add_expected_call(
1968
'Branch.get_stacked_on_url', ('memory:///',),
1969
'error', ('NotStacked',),)
1970
client.add_expected_call(
1971
'Branch.lock_write', ('memory:///', '', ''),
1972
'success', ('ok', 'branch token', 'repo token'))
1973
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1974
client.add_expected_call(
1975
'Branch.set_config_option_dict', ('memory:///', 'branch token',
1976
'repo token', encoded_dict_value, 'foo', ''),
1978
client.add_expected_call(
1979
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1981
transport = MemoryTransport()
1982
branch = self.make_remote_branch(transport, client)
1984
config = branch._get_config()
1986
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1989
self.assertFinished(client)
1655
1991
def test_backwards_compat_set_option(self):
1656
1992
self.setup_smart_server_with_call_log()
1657
1993
branch = self.make_branch('.')
1664
2000
self.assertLength(10, self.hpss_calls)
1665
2001
self.assertEqual('value', branch._get_config().get_option('name'))
2003
def test_backwards_compat_set_option_with_dict(self):
2004
self.setup_smart_server_with_call_log()
2005
branch = self.make_branch('.')
2006
verb = 'Branch.set_config_option_dict'
2007
self.disable_verb(verb)
2009
self.addCleanup(branch.unlock)
2010
self.reset_smart_call_log()
2011
config = branch._get_config()
2012
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
2013
config.set_option(value_dict, 'name')
2014
self.assertLength(10, self.hpss_calls)
2015
self.assertEqual(value_dict, branch._get_config().get_option('name'))
2018
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
2020
def test_get_branch_conf(self):
2021
# in an empty branch we decode the response properly
2022
client = FakeClient()
2023
client.add_expected_call(
2024
'Branch.get_stacked_on_url', ('memory:///',),
2025
'error', ('NotStacked',),)
2026
client.add_success_response_with_body('# config file body', 'ok')
2027
transport = MemoryTransport()
2028
branch = self.make_remote_branch(transport, client)
2029
config = branch.get_config_stack()
2031
config.get("log_format")
2033
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2034
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
2037
def test_set_branch_conf(self):
2038
client = FakeClient()
2039
client.add_expected_call(
2040
'Branch.get_stacked_on_url', ('memory:///',),
2041
'error', ('NotStacked',),)
2042
client.add_expected_call(
2043
'Branch.lock_write', ('memory:///', '', ''),
2044
'success', ('ok', 'branch token', 'repo token'))
2045
client.add_expected_call(
2046
'Branch.get_config_file', ('memory:///', ),
2047
'success', ('ok', ), "# line 1\n")
2048
client.add_expected_call(
2049
'Branch.put_config_file', ('memory:///', 'branch token',
2052
client.add_expected_call(
2053
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
2055
transport = MemoryTransport()
2056
branch = self.make_remote_branch(transport, client)
2058
config = branch.get_config_stack()
2059
config.set('email', 'The Dude <lebowski@example.com>')
2061
self.assertFinished(client)
2063
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
2064
('call', 'Branch.lock_write', ('memory:///', '', '')),
2065
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
2066
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
2067
('memory:///', 'branch token', 'repo token'),
2068
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
2069
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
2073
class TestBranchLockWrite(RemoteBranchTestCase):
1683
2088
self.assertFinished(client)
2091
class TestBranchRevisionIdToRevno(RemoteBranchTestCase):
2093
def test_simple(self):
2094
transport = MemoryTransport()
2095
client = FakeClient(transport.base)
2096
client.add_expected_call(
2097
'Branch.get_stacked_on_url', ('quack/',),
2098
'error', ('NotStacked',),)
2099
client.add_expected_call(
2100
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2101
'success', ('ok', '0',),)
2102
client.add_expected_call(
2103
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2104
'error', ('NoSuchRevision', 'unknown',),)
2105
transport.mkdir('quack')
2106
transport = transport.clone('quack')
2107
branch = self.make_remote_branch(transport, client)
2108
self.assertEquals(0, branch.revision_id_to_revno('null:'))
2109
self.assertRaises(errors.NoSuchRevision,
2110
branch.revision_id_to_revno, 'unknown')
2111
self.assertFinished(client)
2113
def test_dotted(self):
2114
transport = MemoryTransport()
2115
client = FakeClient(transport.base)
2116
client.add_expected_call(
2117
'Branch.get_stacked_on_url', ('quack/',),
2118
'error', ('NotStacked',),)
2119
client.add_expected_call(
2120
'Branch.revision_id_to_revno', ('quack/', 'null:'),
2121
'success', ('ok', '0',),)
2122
client.add_expected_call(
2123
'Branch.revision_id_to_revno', ('quack/', 'unknown'),
2124
'error', ('NoSuchRevision', 'unknown',),)
2125
transport.mkdir('quack')
2126
transport = transport.clone('quack')
2127
branch = self.make_remote_branch(transport, client)
2128
self.assertEquals((0, ), branch.revision_id_to_dotted_revno('null:'))
2129
self.assertRaises(errors.NoSuchRevision,
2130
branch.revision_id_to_dotted_revno, 'unknown')
2131
self.assertFinished(client)
2133
def test_dotted_no_smart_verb(self):
2134
self.setup_smart_server_with_call_log()
2135
branch = self.make_branch('.')
2136
self.disable_verb('Branch.revision_id_to_revno')
2137
self.reset_smart_call_log()
2138
self.assertEquals((0, ),
2139
branch.revision_id_to_dotted_revno('null:'))
2140
self.assertLength(7, self.hpss_calls)
1686
2143
class TestBzrDirGetSetConfig(RemoteBzrDirTestCase):
1688
2145
def test__get_config(self):
1828
2285
class TestRepositoryFormat(TestRemoteRepository):
1830
2287
def test_fast_delta(self):
1831
true_name = groupcompress_repo.RepositoryFormatCHK1().network_name()
2288
true_name = groupcompress_repo.RepositoryFormat2a().network_name()
1832
2289
true_format = RemoteRepositoryFormat()
1833
2290
true_format._network_name = true_name
1834
2291
self.assertEqual(True, true_format.fast_deltas)
1835
false_name = pack_repo.RepositoryFormatKnitPack1().network_name()
2292
false_name = knitpack_repo.RepositoryFormatKnitPack1().network_name()
1836
2293
false_format = RemoteRepositoryFormat()
1837
2294
false_format._network_name = false_name
1838
2295
self.assertEqual(False, false_format.fast_deltas)
1840
2297
def test_get_format_description(self):
1841
2298
remote_repo_format = RemoteRepositoryFormat()
1842
real_format = repository.RepositoryFormat.get_default_format()
2299
real_format = repository.format_registry.get_default()
1843
2300
remote_repo_format._network_name = real_format.network_name()
1844
2301
self.assertEqual(remoted_description(real_format),
1845
2302
remote_repo_format.get_format_description())
2305
class TestRepositoryAllRevisionIds(TestRemoteRepository):
2307
def test_empty(self):
2308
transport_path = 'quack'
2309
repo, client = self.setup_fake_client_and_repository(transport_path)
2310
client.add_success_response_with_body('', 'ok')
2311
self.assertEquals([], repo.all_revision_ids())
2313
[('call_expecting_body', 'Repository.all_revision_ids',
2317
def test_with_some_content(self):
2318
transport_path = 'quack'
2319
repo, client = self.setup_fake_client_and_repository(transport_path)
2320
client.add_success_response_with_body(
2321
'rev1\nrev2\nanotherrev\n', 'ok')
2322
self.assertEquals(["rev1", "rev2", "anotherrev"],
2323
repo.all_revision_ids())
2325
[('call_expecting_body', 'Repository.all_revision_ids',
1848
2330
class TestRepositoryGatherStats(TestRemoteRepository):
1850
2332
def test_revid_none(self):
2388
class TestRepositoryBreakLock(TestRemoteRepository):
2390
def test_break_lock(self):
2391
transport_path = 'quack'
2392
repo, client = self.setup_fake_client_and_repository(transport_path)
2393
client.add_success_response('ok')
2396
[('call', 'Repository.break_lock', ('quack/',))],
2400
class TestRepositoryGetSerializerFormat(TestRemoteRepository):
2402
def test_get_serializer_format(self):
2403
transport_path = 'hill'
2404
repo, client = self.setup_fake_client_and_repository(transport_path)
2405
client.add_success_response('ok', '7')
2406
self.assertEquals('7', repo.get_serializer_format())
2408
[('call', 'VersionedFileRepository.get_serializer_format',
2413
class TestRepositoryReconcile(TestRemoteRepository):
2415
def test_reconcile(self):
2416
transport_path = 'hill'
2417
repo, client = self.setup_fake_client_and_repository(transport_path)
2418
body = ("garbage_inventories: 2\n"
2419
"inconsistent_parents: 3\n")
2420
client.add_expected_call(
2421
'Repository.lock_write', ('hill/', ''),
2422
'success', ('ok', 'a token'))
2423
client.add_success_response_with_body(body, 'ok')
2424
reconciler = repo.reconcile()
2426
[('call', 'Repository.lock_write', ('hill/', '')),
2427
('call_expecting_body', 'Repository.reconcile',
2428
('hill/', 'a token'))],
2430
self.assertEquals(2, reconciler.garbage_inventories)
2431
self.assertEquals(3, reconciler.inconsistent_parents)
2434
class TestRepositoryGetRevisionSignatureText(TestRemoteRepository):
2436
def test_text(self):
2437
# ('ok',), body with signature text
2438
transport_path = 'quack'
2439
repo, client = self.setup_fake_client_and_repository(transport_path)
2440
client.add_success_response_with_body(
2442
self.assertEquals("THETEXT", repo.get_signature_text("revid"))
2444
[('call_expecting_body', 'Repository.get_revision_signature_text',
2445
('quack/', 'revid'))],
2448
def test_no_signature(self):
2449
transport_path = 'quick'
2450
repo, client = self.setup_fake_client_and_repository(transport_path)
2451
client.add_error_response('nosuchrevision', 'unknown')
2452
self.assertRaises(errors.NoSuchRevision, repo.get_signature_text,
2455
[('call_expecting_body', 'Repository.get_revision_signature_text',
2456
('quick/', 'unknown'))],
1906
2460
class TestRepositoryGetGraph(TestRemoteRepository):
1908
2462
def test_get_graph(self):
2115
2722
self.assertEqual({'rev1': ('null:',)}, graph.get_parent_map(['rev1']))
2725
class TestRepositoryGetRevisions(TestRemoteRepository):
2727
def test_hpss_missing_revision(self):
2728
transport_path = 'quack'
2729
repo, client = self.setup_fake_client_and_repository(transport_path)
2730
client.add_success_response_with_body(
2732
self.assertRaises(errors.NoSuchRevision, repo.get_revisions,
2733
['somerev1', 'anotherrev2'])
2735
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2736
('quack/', ), "somerev1\nanotherrev2")],
2739
def test_hpss_get_single_revision(self):
2740
transport_path = 'quack'
2741
repo, client = self.setup_fake_client_and_repository(transport_path)
2742
somerev1 = Revision("somerev1")
2743
somerev1.committer = "Joe Committer <joe@example.com>"
2744
somerev1.timestamp = 1321828927
2745
somerev1.timezone = -60
2746
somerev1.inventory_sha1 = "691b39be74c67b1212a75fcb19c433aaed903c2b"
2747
somerev1.message = "Message"
2748
body = zlib.compress(chk_bencode_serializer.write_revision_to_string(
2750
# Split up body into two bits to make sure the zlib compression object
2751
# gets data fed twice.
2752
client.add_success_response_with_body(
2753
[body[:10], body[10:]], 'ok', '10')
2754
revs = repo.get_revisions(['somerev1'])
2755
self.assertEquals(revs, [somerev1])
2757
[('call_with_body_bytes_expecting_body', 'Repository.iter_revisions',
2758
('quack/', ), "somerev1")],
2118
2762
class TestRepositoryGetRevisionGraph(TestRemoteRepository):
2120
2764
def test_null_revision(self):
2270
2915
call.call.method == verb])
2918
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2920
def test_has_signature_for_revision_id(self):
2921
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2922
transport_path = 'quack'
2923
repo, client = self.setup_fake_client_and_repository(transport_path)
2924
client.add_success_response('yes')
2925
result = repo.has_signature_for_revision_id('A')
2927
[('call', 'Repository.has_signature_for_revision_id',
2930
self.assertEqual(True, result)
2932
def test_is_not_shared(self):
2933
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2934
transport_path = 'qwack'
2935
repo, client = self.setup_fake_client_and_repository(transport_path)
2936
client.add_success_response('no')
2937
result = repo.has_signature_for_revision_id('A')
2939
[('call', 'Repository.has_signature_for_revision_id',
2942
self.assertEqual(False, result)
2945
class TestRepositoryPhysicalLockStatus(TestRemoteRepository):
2947
def test_get_physical_lock_status_yes(self):
2948
transport_path = 'qwack'
2949
repo, client = self.setup_fake_client_and_repository(transport_path)
2950
client.add_success_response('yes')
2951
result = repo.get_physical_lock_status()
2953
[('call', 'Repository.get_physical_lock_status',
2956
self.assertEqual(True, result)
2958
def test_get_physical_lock_status_no(self):
2959
transport_path = 'qwack'
2960
repo, client = self.setup_fake_client_and_repository(transport_path)
2961
client.add_success_response('no')
2962
result = repo.get_physical_lock_status()
2964
[('call', 'Repository.get_physical_lock_status',
2967
self.assertEqual(False, result)
2273
2970
class TestRepositoryIsShared(TestRemoteRepository):
2275
2972
def test_is_shared(self):
2295
2992
self.assertEqual(False, result)
2995
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
2997
def test_make_working_trees(self):
2998
# ('yes', ) for Repository.make_working_trees -> 'True'.
2999
transport_path = 'quack'
3000
repo, client = self.setup_fake_client_and_repository(transport_path)
3001
client.add_success_response('yes')
3002
result = repo.make_working_trees()
3004
[('call', 'Repository.make_working_trees', ('quack/',))],
3006
self.assertEqual(True, result)
3008
def test_no_working_trees(self):
3009
# ('no', ) for Repository.make_working_trees -> 'False'.
3010
transport_path = 'qwack'
3011
repo, client = self.setup_fake_client_and_repository(transport_path)
3012
client.add_success_response('no')
3013
result = repo.make_working_trees()
3015
[('call', 'Repository.make_working_trees', ('qwack/',))],
3017
self.assertEqual(False, result)
2298
3020
class TestRepositoryLockWrite(TestRemoteRepository):
2300
3022
def test_lock_write(self):
2301
3023
transport_path = 'quack'
2302
3024
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
3025
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
3026
token = repo.lock_write().repository_token
2305
3027
self.assertEqual(
2306
3028
[('call', 'Repository.lock_write', ('quack/', ''))],
2308
self.assertEqual('a token', result)
3030
self.assertEqual('a token', token)
2310
3032
def test_lock_write_already_locked(self):
2311
3033
transport_path = 'quack'
3051
class TestRepositoryWriteGroups(TestRemoteRepository):
3053
def test_start_write_group(self):
3054
transport_path = 'quack'
3055
repo, client = self.setup_fake_client_and_repository(transport_path)
3056
client.add_expected_call(
3057
'Repository.lock_write', ('quack/', ''),
3058
'success', ('ok', 'a token'))
3059
client.add_expected_call(
3060
'Repository.start_write_group', ('quack/', 'a token'),
3061
'success', ('ok', ('token1', )))
3063
repo.start_write_group()
3065
def test_start_write_group_unsuspendable(self):
3066
# Some repositories do not support suspending write
3067
# groups. For those, fall back to the "real" repository.
3068
transport_path = 'quack'
3069
repo, client = self.setup_fake_client_and_repository(transport_path)
3070
def stub_ensure_real():
3071
client._calls.append(('_ensure_real',))
3072
repo._real_repository = _StubRealPackRepository(client._calls)
3073
repo._ensure_real = stub_ensure_real
3074
client.add_expected_call(
3075
'Repository.lock_write', ('quack/', ''),
3076
'success', ('ok', 'a token'))
3077
client.add_expected_call(
3078
'Repository.start_write_group', ('quack/', 'a token'),
3079
'error', ('UnsuspendableWriteGroup',))
3081
repo.start_write_group()
3082
self.assertEquals(client._calls[-2:], [
3084
('start_write_group',)])
3086
def test_commit_write_group(self):
3087
transport_path = 'quack'
3088
repo, client = self.setup_fake_client_and_repository(transport_path)
3089
client.add_expected_call(
3090
'Repository.lock_write', ('quack/', ''),
3091
'success', ('ok', 'a token'))
3092
client.add_expected_call(
3093
'Repository.start_write_group', ('quack/', 'a token'),
3094
'success', ('ok', ['token1']))
3095
client.add_expected_call(
3096
'Repository.commit_write_group', ('quack/', 'a token', ['token1']),
3099
repo.start_write_group()
3100
repo.commit_write_group()
3102
def test_abort_write_group(self):
3103
transport_path = 'quack'
3104
repo, client = self.setup_fake_client_and_repository(transport_path)
3105
client.add_expected_call(
3106
'Repository.lock_write', ('quack/', ''),
3107
'success', ('ok', 'a token'))
3108
client.add_expected_call(
3109
'Repository.start_write_group', ('quack/', 'a token'),
3110
'success', ('ok', ['token1']))
3111
client.add_expected_call(
3112
'Repository.abort_write_group', ('quack/', 'a token', ['token1']),
3115
repo.start_write_group()
3116
repo.abort_write_group(False)
3118
def test_suspend_write_group(self):
3119
transport_path = 'quack'
3120
repo, client = self.setup_fake_client_and_repository(transport_path)
3121
self.assertEquals([], repo.suspend_write_group())
3123
def test_resume_write_group(self):
3124
transport_path = 'quack'
3125
repo, client = self.setup_fake_client_and_repository(transport_path)
3126
client.add_expected_call(
3127
'Repository.lock_write', ('quack/', ''),
3128
'success', ('ok', 'a token'))
3129
client.add_expected_call(
3130
'Repository.check_write_group', ('quack/', 'a token', ['token1']),
3133
repo.resume_write_group(['token1'])
2329
3136
class TestRepositorySetMakeWorkingTrees(TestRemoteRepository):
2331
3138
def test_backwards_compat(self):
2895
3756
expected_error = errors.PermissionDenied(path, extra)
2896
3757
self.assertEqual(expected_error, translated_error)
3759
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3761
def test_NoSuchFile_context_path(self):
3762
local_path = "local path"
3763
translated_error = self.translateTuple(('ReadError', "remote path"),
3765
expected_error = errors.ReadError(local_path)
3766
self.assertEqual(expected_error, translated_error)
3768
def test_NoSuchFile_without_context(self):
3769
remote_path = "remote path"
3770
translated_error = self.translateTuple(('ReadError', remote_path))
3771
expected_error = errors.ReadError(remote_path)
3772
self.assertEqual(expected_error, translated_error)
3774
def test_ReadOnlyError(self):
3775
translated_error = self.translateTuple(('ReadOnlyError',))
3776
expected_error = errors.TransportNotPossible("readonly transport")
3777
self.assertEqual(expected_error, translated_error)
3779
def test_MemoryError(self):
3780
translated_error = self.translateTuple(('MemoryError',))
3781
self.assertStartsWith(str(translated_error),
3782
"remote server out of memory")
3784
def test_generic_IndexError_no_classname(self):
3785
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3786
translated_error = self.translateErrorFromSmartServer(err)
3787
expected_error = errors.UnknownErrorFromSmartServer(err)
3788
self.assertEqual(expected_error, translated_error)
3790
# GZ 2011-03-02: TODO test generic non-ascii error string
3792
def test_generic_KeyError(self):
3793
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3794
translated_error = self.translateErrorFromSmartServer(err)
3795
expected_error = errors.UnknownErrorFromSmartServer(err)
3796
self.assertEqual(expected_error, translated_error)
2899
3799
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3800
"""Unit tests for bzrlib.remote._translate_error's robustness.
3143
4045
def test_copy_content_into_avoids_revision_history(self):
3144
4046
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
4047
builder = self.make_branch_builder('remote')
4048
builder.build_commit(message="Commit.")
3147
4049
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
4050
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
4051
local.repository.fetch(remote_branch.repository)
3150
4052
self.hpss_calls = []
3151
4053
remote_branch.copy_content_into(local)
3152
4054
self.assertFalse('Branch.revision_history' in self.hpss_calls)
4056
def test_fetch_everything_needs_just_one_call(self):
4057
local = self.make_branch('local')
4058
builder = self.make_branch_builder('remote')
4059
builder.build_commit(message="Commit.")
4060
remote_branch_url = self.smart_server.get_url() + 'remote'
4061
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4062
self.hpss_calls = []
4063
local.repository.fetch(
4064
remote_branch.repository,
4065
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4066
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
4068
def override_verb(self, verb_name, verb):
4069
request_handlers = request.request_handlers
4070
orig_verb = request_handlers.get(verb_name)
4071
orig_info = request_handlers.get_info(verb_name)
4072
request_handlers.register(verb_name, verb, override_existing=True)
4073
self.addCleanup(request_handlers.register, verb_name, orig_verb,
4074
override_existing=True, info=orig_info)
4076
def test_fetch_everything_backwards_compat(self):
4077
"""Can fetch with EverythingResult even with pre 2.4 servers.
4079
Pre-2.4 do not support 'everything' searches with the
4080
Repository.get_stream_1.19 verb.
4083
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
4084
"""A version of the Repository.get_stream_1.19 verb patched to
4085
reject 'everything' searches the way 2.3 and earlier do.
4087
def recreate_search(self, repository, search_bytes,
4088
discard_excess=False):
4089
verb_log.append(search_bytes.split('\n', 1)[0])
4090
if search_bytes == 'everything':
4092
request.FailedSmartServerResponse(('BadSearch',)))
4093
return super(OldGetStreamVerb,
4094
self).recreate_search(repository, search_bytes,
4095
discard_excess=discard_excess)
4096
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
4097
local = self.make_branch('local')
4098
builder = self.make_branch_builder('remote')
4099
builder.build_commit(message="Commit.")
4100
remote_branch_url = self.smart_server.get_url() + 'remote'
4101
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
4102
self.hpss_calls = []
4103
local.repository.fetch(
4104
remote_branch.repository,
4105
fetch_spec=vf_search.EverythingResult(remote_branch.repository))
4106
# make sure the overridden verb was used
4107
self.assertLength(1, verb_log)
4108
# more than one HPSS call is needed, but because it's a VFS callback
4109
# its hard to predict exactly how many.
4110
self.assertTrue(len(self.hpss_calls) > 1)
4113
class TestUpdateBoundBranchWithModifiedBoundLocation(
4114
tests.TestCaseWithTransport):
4115
"""Ensure correct handling of bound_location modifications.
4117
This is tested against a smart server as http://pad.lv/786980 was about a
4118
ReadOnlyError (write attempt during a read-only transaction) which can only
4119
happen in this context.
4123
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
4124
self.transport_server = test_server.SmartTCPServer_for_testing
4126
def make_master_and_checkout(self, master_name, checkout_name):
4127
# Create the master branch and its associated checkout
4128
self.master = self.make_branch_and_tree(master_name)
4129
self.checkout = self.master.branch.create_checkout(checkout_name)
4130
# Modify the master branch so there is something to update
4131
self.master.commit('add stuff')
4132
self.last_revid = self.master.commit('even more stuff')
4133
self.bound_location = self.checkout.branch.get_bound_location()
4135
def assertUpdateSucceeds(self, new_location):
4136
self.checkout.branch.set_bound_location(new_location)
4137
self.checkout.update()
4138
self.assertEquals(self.last_revid, self.checkout.last_revision())
4140
def test_without_final_slash(self):
4141
self.make_master_and_checkout('master', 'checkout')
4142
# For unclear reasons some users have a bound_location without a final
4143
# '/', simulate that by forcing such a value
4144
self.assertEndsWith(self.bound_location, '/')
4145
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
4147
def test_plus_sign(self):
4148
self.make_master_and_checkout('+master', 'checkout')
4149
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
4151
def test_tilda(self):
4152
# Embed ~ in the middle of the path just to avoid any $HOME
4154
self.make_master_and_checkout('mas~ter', 'checkout')
4155
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))
4158
class TestWithCustomErrorHandler(RemoteBranchTestCase):
4160
def test_no_context(self):
4161
class OutOfCoffee(errors.BzrError):
4162
"""A dummy exception for testing."""
4164
def __init__(self, urgency):
4165
self.urgency = urgency
4166
remote.no_context_error_translators.register("OutOfCoffee",
4167
lambda err: OutOfCoffee(err.error_args[0]))
4168
transport = MemoryTransport()
4169
client = FakeClient(transport.base)
4170
client.add_expected_call(
4171
'Branch.get_stacked_on_url', ('quack/',),
4172
'error', ('NotStacked',))
4173
client.add_expected_call(
4174
'Branch.last_revision_info',
4176
'error', ('OutOfCoffee', 'low'))
4177
transport.mkdir('quack')
4178
transport = transport.clone('quack')
4179
branch = self.make_remote_branch(transport, client)
4180
self.assertRaises(OutOfCoffee, branch.last_revision_info)
4181
self.assertFinished(client)
4183
def test_with_context(self):
4184
class OutOfTea(errors.BzrError):
4185
def __init__(self, branch, urgency):
4186
self.branch = branch
4187
self.urgency = urgency
4188
remote.error_translators.register("OutOfTea",
4189
lambda err, find, path: OutOfTea(err.error_args[0],
4191
transport = MemoryTransport()
4192
client = FakeClient(transport.base)
4193
client.add_expected_call(
4194
'Branch.get_stacked_on_url', ('quack/',),
4195
'error', ('NotStacked',))
4196
client.add_expected_call(
4197
'Branch.last_revision_info',
4199
'error', ('OutOfTea', 'low'))
4200
transport.mkdir('quack')
4201
transport = transport.clone('quack')
4202
branch = self.make_remote_branch(transport, client)
4203
self.assertRaises(OutOfTea, branch.last_revision_info)
4204
self.assertFinished(client)
4207
class TestRepositoryPack(TestRemoteRepository):
4209
def test_pack(self):
4210
transport_path = 'quack'
4211
repo, client = self.setup_fake_client_and_repository(transport_path)
4212
client.add_expected_call(
4213
'Repository.lock_write', ('quack/', ''),
4214
'success', ('ok', 'token'))
4215
client.add_expected_call(
4216
'Repository.pack', ('quack/', 'token', 'False'),
4217
'success', ('ok',), )
4218
client.add_expected_call(
4219
'Repository.unlock', ('quack/', 'token'),
4220
'success', ('ok', ))
4223
def test_pack_with_hint(self):
4224
transport_path = 'quack'
4225
repo, client = self.setup_fake_client_and_repository(transport_path)
4226
client.add_expected_call(
4227
'Repository.lock_write', ('quack/', ''),
4228
'success', ('ok', 'token'))
4229
client.add_expected_call(
4230
'Repository.pack', ('quack/', 'token', 'False'),
4231
'success', ('ok',), )
4232
client.add_expected_call(
4233
'Repository.unlock', ('quack/', 'token', 'False'),
4234
'success', ('ok', ))
4235
repo.pack(['hinta', 'hintb'])