1183
1183
client.add_expected_call(
1184
1184
'Branch.last_revision_info', ('quack/',),
1185
1185
'success', ('ok', '1', 'rev-tip'))
1186
client.add_expected_call(
1187
'Branch.get_config_file', ('quack/',),
1188
'success', ('ok',), '')
1189
transport.mkdir('quack')
1190
transport = transport.clone('quack')
1191
branch = self.make_remote_branch(transport, client)
1192
result = branch.heads_to_fetch()
1193
self.assertFinished(client)
1194
self.assertEqual((set(['rev-tip']), set()), result)
1196
def test_uses_last_revision_info_and_tags_when_set(self):
1197
transport = MemoryTransport()
1198
client = FakeClient(transport.base)
1199
client.add_expected_call(
1200
'Branch.get_stacked_on_url', ('quack/',),
1201
'error', ('NotStacked',))
1202
client.add_expected_call(
1203
'Branch.last_revision_info', ('quack/',),
1204
'success', ('ok', '1', 'rev-tip'))
1205
client.add_expected_call(
1206
'Branch.get_config_file', ('quack/',),
1207
'success', ('ok',), 'branch.fetch_tags = True')
1186
1208
# XXX: this will break if the default format's serialization of tags
1187
1209
# changes, or if the RPC for fetching tags changes from get_tags_bytes.
1188
1210
client.add_expected_call(
1213
1235
self.assertFinished(client)
1214
1236
self.assertEqual((set(['tip']), set(['tagged-1', 'tagged-2'])), result)
1216
def test_backwards_compatible(self):
1238
def make_branch_with_tags(self):
1217
1239
self.setup_smart_server_with_call_log()
1218
1240
# Make a branch with a single revision.
1219
1241
builder = self.make_branch_builder('foo')
1225
1247
# Add two tags to that branch
1226
1248
branch.tags.set_tag('tag-1', 'rev-1')
1227
1249
branch.tags.set_tag('tag-2', 'rev-2')
1252
def test_backwards_compatible(self):
1253
branch = self.make_branch_with_tags()
1254
c = branch.get_config()
1255
c.set_user_option('branch.fetch_tags', 'True')
1228
1256
self.addCleanup(branch.lock_read().unlock)
1229
1257
# Disable the heads_to_fetch verb
1230
1258
verb = 'Branch.heads_to_fetch'
1233
1261
result = branch.heads_to_fetch()
1234
1262
self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result)
1235
1263
self.assertEqual(
1236
['Branch.last_revision_info', 'Branch.get_tags_bytes'],
1264
['Branch.last_revision_info', 'Branch.get_config_file',
1265
'Branch.get_tags_bytes'],
1266
[call.call.method for call in self.hpss_calls])
1268
def test_backwards_compatible_no_tags(self):
1269
branch = self.make_branch_with_tags()
1270
c = branch.get_config()
1271
c.set_user_option('branch.fetch_tags', 'False')
1272
self.addCleanup(branch.lock_read().unlock)
1273
# Disable the heads_to_fetch verb
1274
verb = 'Branch.heads_to_fetch'
1275
self.disable_verb(verb)
1276
self.reset_smart_call_log()
1277
result = branch.heads_to_fetch()
1278
self.assertEqual((set(['tip']), set()), result)
1280
['Branch.last_revision_info', 'Branch.get_config_file'],
1237
1281
[call.call.method for call in self.hpss_calls])
2103
2147
parents = repo.get_parent_map([rev_id])
2104
2148
self.assertEqual(
2105
2149
[('call_with_body_bytes_expecting_body',
2106
'Repository.get_parent_map', ('quack/', 'include-missing:',
2150
'Repository.get_parent_map',
2151
('quack/', 'include-missing:', rev_id), '\n\n0'),
2108
2152
('disconnect medium',),
2109
2153
('call_expecting_body', 'Repository.get_revision_graph',
2110
2154
('quack/', ''))],
2230
2274
self.assertEqual({}, repo.get_parent_map(['non-existant']))
2231
2275
self.assertLength(0, self.hpss_calls)
2277
def test_exposes_get_cached_parent_map(self):
2278
"""RemoteRepository exposes get_cached_parent_map from
2281
r1 = u'\u0e33'.encode('utf8')
2282
r2 = u'\u0dab'.encode('utf8')
2283
lines = [' '.join([r2, r1]), r1]
2284
encoded_body = bz2.compress('\n'.join(lines))
2286
transport_path = 'quack'
2287
repo, client = self.setup_fake_client_and_repository(transport_path)
2288
client.add_success_response_with_body(encoded_body, 'ok')
2290
# get_cached_parent_map should *not* trigger an RPC
2291
self.assertEqual({}, repo.get_cached_parent_map([r1]))
2292
self.assertEqual([], client._calls)
2293
self.assertEqual({r2: (r1,)}, repo.get_parent_map([r2]))
2294
self.assertEqual({r1: (NULL_REVISION,)},
2295
repo.get_cached_parent_map([r1]))
2297
[('call_with_body_bytes_expecting_body',
2298
'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
2234
2304
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
3244
3314
_, stacked = branch_factory()
3245
3315
source = stacked.repository._get_source(target_repository_format)
3246
3316
tip = stacked.last_revision()
3247
revs = stacked.repository.get_ancestry(tip)
3248
search = graph.PendingAncestryResult([tip], stacked.repository)
3317
stacked.repository._ensure_real()
3318
graph = stacked.repository.get_graph()
3319
revs = [r for (r,ps) in graph.iter_ancestry([tip])
3320
if r != NULL_REVISION]
3322
search = _mod_graph.PendingAncestryResult([tip], stacked.repository)
3249
3323
self.reset_smart_call_log()
3250
3324
stream = source.get_stream(search)
3253
3325
# We trust that if a revision is in the stream the rest of the new
3254
3326
# content for it is too, as per our main fetch tests; here we are
3255
3327
# checking that the revisions are actually included at all, and their
3294
3366
self.assertEqual(expected_revs, rev_ord)
3295
3367
# Getting topological sort requires VFS calls still - one of which is
3296
3368
# pushing up from the bound branch.
3297
self.assertLength(13, self.hpss_calls)
3369
self.assertLength(14, self.hpss_calls)
3299
3371
def test_stacked_get_stream_groupcompress(self):
3300
3372
# Repository._get_source.get_stream() from a stacked repository with
3357
3429
remote_branch_url = self.smart_server.get_url() + 'remote'
3358
3430
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3359
3431
self.hpss_calls = []
3360
local.repository.fetch(remote_branch.repository,
3361
fetch_spec=graph.EverythingResult(remote_branch.repository))
3432
local.repository.fetch(
3433
remote_branch.repository,
3434
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3362
3435
self.assertEqual(['Repository.get_stream_1.19'], self.hpss_calls)
3364
3437
def override_verb(self, verb_name, verb):
3379
3452
"""A version of the Repository.get_stream_1.19 verb patched to
3380
3453
reject 'everything' searches the way 2.3 and earlier do.
3382
def recreate_search(self, repository, search_bytes, discard_excess=False):
3455
def recreate_search(self, repository, search_bytes,
3456
discard_excess=False):
3383
3457
verb_log.append(search_bytes.split('\n', 1)[0])
3384
3458
if search_bytes == 'everything':
3385
return (None, request.FailedSmartServerResponse(('BadSearch',)))
3460
request.FailedSmartServerResponse(('BadSearch',)))
3386
3461
return super(OldGetStreamVerb,
3387
3462
self).recreate_search(repository, search_bytes,
3388
3463
discard_excess=discard_excess)
3393
3468
remote_branch_url = self.smart_server.get_url() + 'remote'
3394
3469
remote_branch = bzrdir.BzrDir.open(remote_branch_url).open_branch()
3395
3470
self.hpss_calls = []
3396
local.repository.fetch(remote_branch.repository,
3397
fetch_spec=graph.EverythingResult(remote_branch.repository))
3471
local.repository.fetch(
3472
remote_branch.repository,
3473
fetch_spec=_mod_graph.EverythingResult(remote_branch.repository))
3398
3474
# make sure the overridden verb was used
3399
3475
self.assertLength(1, verb_log)
3400
3476
# more than one HPSS call is needed, but because it's a VFS callback
3401
3477
# its hard to predict exactly how many.
3402
3478
self.assertTrue(len(self.hpss_calls) > 1)
3481
class TestUpdateBoundBranchWithModifiedBoundLocation(
3482
tests.TestCaseWithTransport):
3483
"""Ensure correct handling of bound_location modifications.
3485
This is tested against a smart server as http://pad.lv/786980 was about a
3486
ReadOnlyError (write attempt during a read-only transaction) which can only
3487
happen in this context.
3491
super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
3492
self.transport_server = test_server.SmartTCPServer_for_testing
3494
def make_master_and_checkout(self, master_name, checkout_name):
3495
# Create the master branch and its associated checkout
3496
self.master = self.make_branch_and_tree(master_name)
3497
self.checkout = self.master.branch.create_checkout(checkout_name)
3498
# Modify the master branch so there is something to update
3499
self.master.commit('add stuff')
3500
self.last_revid = self.master.commit('even more stuff')
3501
self.bound_location = self.checkout.branch.get_bound_location()
3503
def assertUpdateSucceeds(self, new_location):
3504
self.checkout.branch.set_bound_location(new_location)
3505
self.checkout.update()
3506
self.assertEquals(self.last_revid, self.checkout.last_revision())
3508
def test_without_final_slash(self):
3509
self.make_master_and_checkout('master', 'checkout')
3510
# For unclear reasons some users have a bound_location without a final
3511
# '/', simulate that by forcing such a value
3512
self.assertEndsWith(self.bound_location, '/')
3513
self.assertUpdateSucceeds(self.bound_location.rstrip('/'))
3515
def test_plus_sign(self):
3516
self.make_master_and_checkout('+master', 'checkout')
3517
self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
3519
def test_tilda(self):
3520
# Embed ~ in the middle of the path just to avoid any $HOME
3522
self.make_master_and_checkout('mas~ter', 'checkout')
3523
self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))