53
57
RemoteRepositoryFormat,
55
from bzrlib.repofmt import groupcompress_repo, pack_repo
59
from bzrlib.repofmt import groupcompress_repo, knitpack_repo
56
60
from bzrlib.revision import NULL_REVISION
57
from bzrlib.smart import medium
61
from bzrlib.smart import medium, request
58
62
from bzrlib.smart.client import _SmartClient
59
from bzrlib.smart.repository import SmartServerRepositoryGetParentMap
63
from bzrlib.smart.repository import (
64
SmartServerRepositoryGetParentMap,
65
SmartServerRepositoryGetStream_1_19,
67
from bzrlib.symbol_versioning import deprecated_in
60
68
from bzrlib.tests import (
62
split_suite_by_condition,
66
from bzrlib.transport import get_transport
71
from bzrlib.tests.scenarios import load_tests_apply_scenarios
67
72
from bzrlib.transport.memory import MemoryTransport
68
73
from bzrlib.transport.remote import (
70
75
RemoteSSHTransport,
71
76
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 = [
80
load_tests = load_tests_apply_scenarios
83
class BasicRemoteObjectTests(tests.TestCaseWithTransport):
79
{'transport_server': test_server.SmartTCPServer_for_testing_v2_only}),
87
{'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):
89
{'transport_server': test_server.SmartTCPServer_for_testing})]
88
93
super(BasicRemoteObjectTests, self).setUp()
89
94
self.transport = self.get_transport()
90
95
# make a branch that can be opened over the smart transport
91
96
self.local_wt = BzrDir.create_standalone_workingtree('.')
94
self.transport.disconnect()
95
tests.TestCaseWithTransport.tearDown(self)
97
self.addCleanup(self.transport.disconnect)
97
99
def test_create_remote_bzrdir(self):
98
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
100
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
99
101
self.assertIsInstance(b, BzrDir)
101
103
def test_open_remote_branch(self):
102
104
# open a standalone branch in the working directory
103
b = remote.RemoteBzrDir(self.transport, remote.RemoteBzrDirFormat())
105
b = remote.RemoteBzrDir(self.transport, RemoteBzrDirFormat())
104
106
branch = b.open_branch()
105
107
self.assertIsInstance(branch, Branch)
115
117
def test_remote_branch_revision_history(self):
116
118
b = BzrDir.open_from_transport(self.transport).open_branch()
117
self.assertEqual([], b.revision_history())
120
self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
118
121
r1 = self.local_wt.commit('1st commit')
119
122
r2 = self.local_wt.commit('1st commit', rev_id=u'\xc8'.encode('utf8'))
120
self.assertEqual([r1, r2], b.revision_history())
123
self.assertEqual([r1, r2],
124
self.applyDeprecated(deprecated_in((2, 5, 0)), b.revision_history))
122
126
def test_find_correct_format(self):
123
127
"""Should open a RemoteBzrDir over a RemoteTransport"""
124
128
fmt = BzrDirFormat.find_format(self.transport)
125
self.assertTrue(RemoteBzrDirFormat
126
in BzrDirFormat._control_server_formats)
127
self.assertIsInstance(fmt, remote.RemoteBzrDirFormat)
129
self.assertTrue(bzrdir.RemoteBzrProber
130
in controldir.ControlDirFormat._server_probers)
131
self.assertIsInstance(fmt, RemoteBzrDirFormat)
129
133
def test_open_detected_smart_format(self):
130
134
fmt = BzrDirFormat.find_format(self.transport)
481
485
self.assertFinished(client)
488
class TestBzrDirHasWorkingTree(TestRemote):
490
def test_has_workingtree(self):
491
transport = self.get_transport('quack')
492
client = FakeClient(transport.base)
493
client.add_expected_call(
494
'BzrDir.has_workingtree', ('quack/',),
495
'success', ('yes',)),
496
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
498
self.assertTrue(a_bzrdir.has_workingtree())
499
self.assertFinished(client)
501
def test_no_workingtree(self):
502
transport = self.get_transport('quack')
503
client = FakeClient(transport.base)
504
client.add_expected_call(
505
'BzrDir.has_workingtree', ('quack/',),
507
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
509
self.assertFalse(a_bzrdir.has_workingtree())
510
self.assertFinished(client)
513
class TestBzrDirDestroyRepository(TestRemote):
515
def test_destroy_repository(self):
516
transport = self.get_transport('quack')
517
client = FakeClient(transport.base)
518
client.add_expected_call(
519
'BzrDir.destroy_repository', ('quack/',),
521
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
523
a_bzrdir.destroy_repository()
524
self.assertFinished(client)
484
527
class TestBzrDirOpen(TestRemote):
486
529
def make_fake_client_and_transport(self, path='quack'):
495
538
client.add_expected_call(
496
539
'BzrDir.open_2.1', ('quack/',), 'success', ('no',))
497
540
self.assertRaises(errors.NotBranchError, RemoteBzrDir, transport,
498
remote.RemoteBzrDirFormat(), _client=client, _force_probe=True)
541
RemoteBzrDirFormat(), _client=client, _force_probe=True)
499
542
self.assertFinished(client)
501
544
def test_present_without_workingtree(self):
502
545
client, transport = self.make_fake_client_and_transport()
503
546
client.add_expected_call(
504
547
'BzrDir.open_2.1', ('quack/',), 'success', ('yes', 'no'))
505
bd = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
548
bd = RemoteBzrDir(transport, RemoteBzrDirFormat(),
506
549
_client=client, _force_probe=True)
507
550
self.assertIsInstance(bd, RemoteBzrDir)
508
551
self.assertFalse(bd.has_workingtree())
724
767
format = branch._format
725
768
self.assertEqual(network_name, format.network_name())
770
def test_already_open_repo_and_reused_medium(self):
771
"""Bug 726584: create_branch(..., repository=repo) should work
772
regardless of what the smart medium's base URL is.
774
self.transport_server = test_server.SmartTCPServer_for_testing
775
transport = self.get_transport('.')
776
repo = self.make_repository('quack')
777
# Client's medium rooted a transport root (not at the bzrdir)
778
client = FakeClient(transport.base)
779
transport = transport.clone('quack')
780
reference_bzrdir_format = bzrdir.format_registry.get('default')()
781
reference_format = reference_bzrdir_format.get_branch_format()
782
network_name = reference_format.network_name()
783
reference_repo_fmt = reference_bzrdir_format.repository_format
784
reference_repo_name = reference_repo_fmt.network_name()
785
client.add_expected_call(
786
'BzrDir.create_branch', ('extra/quack/', network_name),
787
'success', ('ok', network_name, '', 'no', 'no', 'yes',
788
reference_repo_name))
789
a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(),
791
branch = a_bzrdir.create_branch(repository=repo)
792
# We should have got a remote branch
793
self.assertIsInstance(branch, remote.RemoteBranch)
794
# its format should have the settings from the response
795
format = branch._format
796
self.assertEqual(network_name, format.network_name())
728
799
class TestBzrDirCreateRepository(TestRemote):
1143
1214
[('set_tags_bytes', 'tags bytes')] * 2, real_branch.calls)
1217
class TestBranchHeadsToFetch(RemoteBranchTestCase):
1219
def test_uses_last_revision_info_and_tags_by_default(self):
1220
transport = MemoryTransport()
1221
client = FakeClient(transport.base)
1222
client.add_expected_call(
1223
'Branch.get_stacked_on_url', ('quack/',),
1224
'error', ('NotStacked',))
1225
client.add_expected_call(
1226
'Branch.last_revision_info', ('quack/',),
1227
'success', ('ok', '1', 'rev-tip'))
1228
client.add_expected_call(
1229
'Branch.get_config_file', ('quack/',),
1230
'success', ('ok',), '')
1231
transport.mkdir('quack')
1232
transport = transport.clone('quack')
1233
branch = self.make_remote_branch(transport, client)
1234
result = branch.heads_to_fetch()
1235
self.assertFinished(client)
1236
self.assertEqual((set(['rev-tip']), set()), result)
1238
def test_uses_last_revision_info_and_tags_when_set(self):
1239
transport = MemoryTransport()
1240
client = FakeClient(transport.base)
1241
client.add_expected_call(
1242
'Branch.get_stacked_on_url', ('quack/',),
1243
'error', ('NotStacked',))
1244
client.add_expected_call(
1245
'Branch.last_revision_info', ('quack/',),
1246
'success', ('ok', '1', 'rev-tip'))
1247
client.add_expected_call(
1248
'Branch.get_config_file', ('quack/',),
1249
'success', ('ok',), 'branch.fetch_tags = True')
1250
# XXX: this will break if the default format's serialization of tags
1251
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1252
client.add_expected_call(
1253
'Branch.get_tags_bytes', ('quack/',),
1254
'success', ('d5:tag-17:rev-foo5:tag-27:rev-bare',))
1255
transport.mkdir('quack')
1256
transport = transport.clone('quack')
1257
branch = self.make_remote_branch(transport, client)
1258
result = branch.heads_to_fetch()
1259
self.assertFinished(client)
1261
(set(['rev-tip']), set(['rev-foo', 'rev-bar'])), result)
1263
def test_uses_rpc_for_formats_with_non_default_heads_to_fetch(self):
1264
transport = MemoryTransport()
1265
client = FakeClient(transport.base)
1266
client.add_expected_call(
1267
'Branch.get_stacked_on_url', ('quack/',),
1268
'error', ('NotStacked',))
1269
client.add_expected_call(
1270
'Branch.heads_to_fetch', ('quack/',),
1271
'success', (['tip'], ['tagged-1', 'tagged-2']))
1272
transport.mkdir('quack')
1273
transport = transport.clone('quack')
1274
branch = self.make_remote_branch(transport, client)
1275
branch._format._use_default_local_heads_to_fetch = lambda: False
1276
result = branch.heads_to_fetch()
1277
self.assertFinished(client)
1278
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1280
def make_branch_with_tags(self):
1281
self.setup_smart_server_with_call_log()
1282
# Make a branch with a single revision.
1283
builder = self.make_branch_builder('foo')
1284
builder.start_series()
1285
builder.build_snapshot('tip', None, [
1286
('add', ('', 'root-id', 'directory', ''))])
1287
builder.finish_series()
1288
branch = builder.get_branch()
1289
# Add two tags to that branch
1290
branch.tags.set_tag('tag-1', 'rev-1')
1291
branch.tags.set_tag('tag-2', 'rev-2')
1294
def test_backwards_compatible(self):
1295
branch = self.make_branch_with_tags()
1296
c = branch.get_config()
1297
c.set_user_option('branch.fetch_tags', 'True')
1298
self.addCleanup(branch.lock_read().unlock)
1299
# Disable the heads_to_fetch verb
1300
verb = 'Branch.heads_to_fetch'
1301
self.disable_verb(verb)
1302
self.reset_smart_call_log()
1303
result = branch.heads_to_fetch()
1304
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1306
['Branch.last_revision_info', 'Branch.get_config_file',
1307
'Branch.get_tags_bytes'],
1308
[call.call.method for call in self.hpss_calls])
1310
def test_backwards_compatible_no_tags(self):
1311
branch = self.make_branch_with_tags()
1312
c = branch.get_config()
1313
c.set_user_option('branch.fetch_tags', 'False')
1314
self.addCleanup(branch.lock_read().unlock)
1315
# Disable the heads_to_fetch verb
1316
verb = 'Branch.heads_to_fetch'
1317
self.disable_verb(verb)
1318
self.reset_smart_call_log()
1319
result = branch.heads_to_fetch()
1320
self.assertEqual((set(['tip']), set()), result)
1322
['Branch.last_revision_info', 'Branch.get_config_file'],
1323
[call.call.method for call in self.hpss_calls])
1146
1326
class TestBranchLastRevisionInfo(RemoteBranchTestCase):
1148
1328
def test_empty_branch(self):
1652
1833
branch.unlock()
1653
1834
self.assertFinished(client)
1836
def test_set_option_with_dict(self):
1837
client = FakeClient()
1838
client.add_expected_call(
1839
'Branch.get_stacked_on_url', ('memory:///',),
1840
'error', ('NotStacked',),)
1841
client.add_expected_call(
1842
'Branch.lock_write', ('memory:///', '', ''),
1843
'success', ('ok', 'branch token', 'repo token'))
1844
encoded_dict_value = 'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde'
1845
client.add_expected_call(
1846
'Branch.set_config_option_dict', ('memory:///', 'branch token',
1847
'repo token', encoded_dict_value, 'foo', ''),
1849
client.add_expected_call(
1850
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1852
transport = MemoryTransport()
1853
branch = self.make_remote_branch(transport, client)
1855
config = branch._get_config()
1857
{'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'},
1860
self.assertFinished(client)
1655
1862
def test_backwards_compat_set_option(self):
1656
1863
self.setup_smart_server_with_call_log()
1657
1864
branch = self.make_branch('.')
1664
1871
self.assertLength(10, self.hpss_calls)
1665
1872
self.assertEqual('value', branch._get_config().get_option('name'))
1874
def test_backwards_compat_set_option_with_dict(self):
1875
self.setup_smart_server_with_call_log()
1876
branch = self.make_branch('.')
1877
verb = 'Branch.set_config_option_dict'
1878
self.disable_verb(verb)
1880
self.addCleanup(branch.unlock)
1881
self.reset_smart_call_log()
1882
config = branch._get_config()
1883
value_dict = {'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
1884
config.set_option(value_dict, 'name')
1885
self.assertLength(10, self.hpss_calls)
1886
self.assertEqual(value_dict, branch._get_config().get_option('name'))
1889
class TestBranchGetPutConfigStore(RemoteBranchTestCase):
1891
def test_get_branch_conf(self):
1892
# in an empty branch we decode the response properly
1893
client = FakeClient()
1894
client.add_expected_call(
1895
'Branch.get_stacked_on_url', ('memory:///',),
1896
'error', ('NotStacked',),)
1897
client.add_success_response_with_body('# config file body', 'ok')
1898
transport = MemoryTransport()
1899
branch = self.make_remote_branch(transport, client)
1900
config = branch.get_config_stack()
1902
config.get("log_format")
1904
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1905
('call_expecting_body', 'Branch.get_config_file', ('memory:///',))],
1908
def test_set_branch_conf(self):
1909
client = FakeClient()
1910
client.add_expected_call(
1911
'Branch.get_stacked_on_url', ('memory:///',),
1912
'error', ('NotStacked',),)
1913
client.add_expected_call(
1914
'Branch.lock_write', ('memory:///', '', ''),
1915
'success', ('ok', 'branch token', 'repo token'))
1916
client.add_expected_call(
1917
'Branch.get_config_file', ('memory:///', ),
1918
'success', ('ok', ), "# line 1\n")
1919
client.add_expected_call(
1920
'Branch.put_config_file', ('memory:///', 'branch token',
1923
client.add_expected_call(
1924
'Branch.unlock', ('memory:///', 'branch token', 'repo token'),
1926
transport = MemoryTransport()
1927
branch = self.make_remote_branch(transport, client)
1929
config = branch.get_config_stack()
1930
config.set('email', 'The Dude <lebowski@example.com>')
1932
self.assertFinished(client)
1934
[('call', 'Branch.get_stacked_on_url', ('memory:///',)),
1935
('call', 'Branch.lock_write', ('memory:///', '', '')),
1936
('call_expecting_body', 'Branch.get_config_file', ('memory:///',)),
1937
('call_with_body_bytes_expecting_body', 'Branch.put_config_file',
1938
('memory:///', 'branch token', 'repo token'),
1939
'# line 1\nemail = The Dude <lebowski@example.com>\n'),
1940
('call', 'Branch.unlock', ('memory:///', 'branch token', 'repo token'))],
1668
1944
class TestBranchLockWrite(RemoteBranchTestCase):
2095
2371
self.assertEqual({}, repo.get_parent_map(['non-existant']))
2096
2372
self.assertLength(0, self.hpss_calls)
2374
def test_exposes_get_cached_parent_map(self):
2375
"""RemoteRepository exposes get_cached_parent_map from
2378
r1 = u'\u0e33'.encode('utf8')
2379
r2 = u'\u0dab'.encode('utf8')
2380
lines = [' '.join([r2, r1]), r1]
2381
encoded_body = bz2.compress('\n'.join(lines))
2383
transport_path = 'quack'
2384
repo, client = self.setup_fake_client_and_repository(transport_path)
2385
client.add_success_response_with_body(encoded_body, 'ok')
2387
# get_cached_parent_map should *not* trigger an RPC
2388
self.assertEqual({}, repo.get_cached_parent_map([r1]))
2389
self.assertEqual([], client._calls)
2390
self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
2391
self.assertEqual({r1: (NULL_REVISION,)},
2392
repo.get_cached_parent_map([r1]))
2394
[('call_with_body_bytes_expecting_body',
2395
'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
2099
2401
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2270
2573
call.call.method == verb])
2576
class TestRepositoryHasSignatureForRevisionId(TestRemoteRepository):
2578
def test_has_signature_for_revision_id(self):
2579
# ('yes', ) for Repository.has_signature_for_revision_id -> 'True'.
2580
transport_path = 'quack'
2581
repo, client = self.setup_fake_client_and_repository(transport_path)
2582
client.add_success_response('yes')
2583
result = repo.has_signature_for_revision_id('A')
2585
[('call', 'Repository.has_signature_for_revision_id',
2588
self.assertEqual(True, result)
2590
def test_is_not_shared(self):
2591
# ('no', ) for Repository.has_signature_for_revision_id -> 'False'.
2592
transport_path = 'qwack'
2593
repo, client = self.setup_fake_client_and_repository(transport_path)
2594
client.add_success_response('no')
2595
result = repo.has_signature_for_revision_id('A')
2597
[('call', 'Repository.has_signature_for_revision_id',
2600
self.assertEqual(False, result)
2273
2603
class TestRepositoryIsShared(TestRemoteRepository):
2275
2605
def test_is_shared(self):
2295
2625
self.assertEqual(False, result)
2628
class TestRepositoryMakeWorkingTrees(TestRemoteRepository):
2630
def test_make_working_trees(self):
2631
# ('yes', ) for Repository.make_working_trees -> 'True'.
2632
transport_path = 'quack'
2633
repo, client = self.setup_fake_client_and_repository(transport_path)
2634
client.add_success_response('yes')
2635
result = repo.make_working_trees()
2637
[('call', 'Repository.make_working_trees', ('quack/',))],
2639
self.assertEqual(True, result)
2641
def test_no_working_trees(self):
2642
# ('no', ) for Repository.make_working_trees -> 'False'.
2643
transport_path = 'qwack'
2644
repo, client = self.setup_fake_client_and_repository(transport_path)
2645
client.add_success_response('no')
2646
result = repo.make_working_trees()
2648
[('call', 'Repository.make_working_trees', ('qwack/',))],
2650
self.assertEqual(False, result)
2298
2653
class TestRepositoryLockWrite(TestRemoteRepository):
2300
2655
def test_lock_write(self):
2301
2656
transport_path = 'quack'
2302
2657
repo, client = self.setup_fake_client_and_repository(transport_path)
2303
2658
client.add_success_response('ok', 'a token')
2304
result = repo.lock_write()
2659
token = repo.lock_write().repository_token
2305
2660
self.assertEqual(
2306
2661
[('call', 'Repository.lock_write', ('quack/', ''))],
2308
self.assertEqual('a token', result)
2663
self.assertEqual('a token', token)
2310
2665
def test_lock_write_already_locked(self):
2311
2666
transport_path = 'quack'
2895
3274
expected_error = errors.PermissionDenied(path, extra)
2896
3275
self.assertEqual(expected_error, translated_error)
3277
# GZ 2011-03-02: TODO test for PermissionDenied with non-ascii 'extra'
3279
def test_NoSuchFile_context_path(self):
3280
local_path = "local path"
3281
translated_error = self.translateTuple(('ReadError', "remote path"),
3283
expected_error = errors.ReadError(local_path)
3284
self.assertEqual(expected_error, translated_error)
3286
def test_NoSuchFile_without_context(self):
3287
remote_path = "remote path"
3288
translated_error = self.translateTuple(('ReadError', remote_path))
3289
expected_error = errors.ReadError(remote_path)
3290
self.assertEqual(expected_error, translated_error)
3292
def test_ReadOnlyError(self):
3293
translated_error = self.translateTuple(('ReadOnlyError',))
3294
expected_error = errors.TransportNotPossible("readonly transport")
3295
self.assertEqual(expected_error, translated_error)
3297
def test_MemoryError(self):
3298
translated_error = self.translateTuple(('MemoryError',))
3299
self.assertStartsWith(str(translated_error),
3300
"remote server out of memory")
3302
def test_generic_IndexError_no_classname(self):
3303
err = errors.ErrorFromSmartServer(('error', "list index out of range"))
3304
translated_error = self.translateErrorFromSmartServer(err)
3305
expected_error = errors.UnknownErrorFromSmartServer(err)
3306
self.assertEqual(expected_error, translated_error)
3308
# GZ 2011-03-02: TODO test generic non-ascii error string
3310
def test_generic_KeyError(self):
3311
err = errors.ErrorFromSmartServer(('error', 'KeyError', "1"))
3312
translated_error = self.translateErrorFromSmartServer(err)
3313
expected_error = errors.UnknownErrorFromSmartServer(err)
3314
self.assertEqual(expected_error, translated_error)
2899
3317
class TestErrorTranslationRobustness(TestErrorTranslationBase):
2900
3318
"""Unit tests for bzrlib.remote._translate_error's robustness.
3143
3563
def test_copy_content_into_avoids_revision_history(self):
3144
3564
local = self.make_branch('local')
3145
remote_backing_tree = self.make_branch_and_tree('remote')
3146
remote_backing_tree.commit("Commit.")
3565
builder = self.make_branch_builder('remote')
3566
builder.build_commit(message="Commit.")
3147
3567
remote_branch_url = self.smart_server.get_url() + 'remote'
3148
3568
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3149
3569
local.repository.fetch(remote_branch.repository)
3150
3570
self.hpss_calls = []
3151
3571
remote_branch.copy_content_into(local)
3152
3572
self.assertFalse('Branch.revision_history' in self.hpss_calls)
3574
def test_fetch_everything_needs_just_one_call(self):
3575
local = self.make_branch('local')
3576
builder = self.make_branch_builder('remote')
3577
builder.build_commit(message="Commit.")
3578
remote_branch_url = self.smart_server.get_url() + 'remote'
3579
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3580
self.hpss_calls = []
3581
local.repository.fetch(
3582
remote_branch.repository,
3583
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3584
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
3586
def override_verb(self, verb_name, verb):
3587
request_handlers = request.request_handlers
3588
orig_verb = request_handlers.get(verb_name)
3589
request_handlers.register(verb_name, verb, override_existing=True)
3590
self.addCleanup(request_handlers.register, verb_name, orig_verb,
3591
override_existing=True)
3593
def test_fetch_everything_backwards_compat(self):
3594
"""Can fetch with EverythingResult even with pre 2.4 servers.
3596
Pre-2.4 do not support 'everything' searches with the
3597
Repository.get_stream_1.19 verb.
3600
class OldGetStreamVerb(SmartServerRepositoryGetStream_1_19):
3601
"""A version of the Repository.get_stream_1.19 verb patched to
3602
reject 'everything' searches the way 2.3 and earlier do.
3604
def recreate_search(self, repository, search_bytes,
3605
discard_excess=False):
3606
verb_log.append(search_bytes.split('\n', 1)[0])
3607
if search_bytes == 'everything':
3609
request.FailedSmartServerResponse(('BadSearch',)))
3610
return super(OldGetStreamVerb,
3611
self).recreate_search(repository, search_bytes,
3612
discard_excess=discard_excess)
3613
self.override_verb('Repository.get_stream_1.19', OldGetStreamVerb)
3614
local = self.make_branch('local')
3615
builder = self.make_branch_builder('remote')
3616
builder.build_commit(message="Commit.")
3617
remote_branch_url = self.smart_server.get_url() + 'remote'
3618
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3619
self.hpss_calls = []
3620
local.repository.fetch(
3621
remote_branch.repository,
3622
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3623
# make sure the overridden verb was used
3624
self.assertLength(1, verb_log)
3625
# more than one HPSS call is needed, but because it's a VFS callback
3626
# its hard to predict exactly how many.
3627
self.assertTrue(len(self.hpss_calls) > 1)
3630
class TestUpdateBoundBranchWithModifiedBoundLocation(
3631
tests.TestCaseWithTransport):
3632
"""Ensure correct handling of bound_location modifications.
3634
This is tested against a smart server as http://pad.lv/786980 was about a
3635
ReadOnlyError (write attempt during a read-only transaction) which can only
3636
happen in this context.
3640
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
3641
self.transport_server = test_server.SmartTCPServer_for_testing
3643
def make_master_and_checkout(self, master_name, checkout_name):
3644
# Create the master branch and its associated checkout
3645
self.master = self.make_branch_and_tree(master_name)
3646
self.checkout = self.master.branch.create_checkout(checkout_name)
3647
# Modify the master branch so there is something to update
3648
self.master.commit('add stuff')
3649
self.last_revid = self.master.commit('even more stuff')
3650
self.bound_location = self.checkout.branch.get_bound_location()
3652
def assertUpdateSucceeds(self, new_location):
3653
self.checkout.branch.set_bound_location(new_location)
3654
self.checkout.update()
3655
self.assertEquals(self.last_revid, self.checkout.last_revision())
3657
def test_without_final_slash(self):
3658
self.make_master_and_checkout('master', 'checkout')
3659
# For unclear reasons some users have a bound_location without a final
3660
# '/', simulate that by forcing such a value
3661
self.assertEndsWith(self.bound_location, '/')
3662
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
3664
def test_plus_sign(self):
3665
self.make_master_and_checkout('+master', 'checkout')
3666
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
3668
def test_tilda(self):
3669
# Embed ~ in the middle of the path just to avoid any $HOME
3671
self.make_master_and_checkout('mas~ter', 'checkout')
3672
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))