~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_remote.py

Abbreviate pack_stat struct format to '>6L'

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
    config,
33
33
    controldir,
34
34
    errors,
35
 
    graph,
 
35
    graph as _mod_graph,
36
36
    inventory,
37
37
    inventory_delta,
38
38
    remote,
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)
 
1195
 
 
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)
1215
1237
 
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')
 
1250
        return branch
 
1251
 
 
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])
 
1267
 
 
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)
 
1279
        self.assertEqual(
 
1280
            ['Branch.last_revision_info', 'Branch.get_config_file'],
1237
1281
            [call.call.method for call in self.hpss_calls])
1238
1282
 
1239
1283
 
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:',
2107
 
              rev_id), '\n\n0'),
 
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)
2232
2276
 
 
2277
    def test_exposes_get_cached_parent_map(self):
 
2278
        """RemoteRepository exposes get_cached_parent_map from
 
2279
        _unstacked_provider
 
2280
        """
 
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))
 
2285
 
 
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')
 
2289
        repo.lock_read()
 
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]))
 
2296
        self.assertEqual(
 
2297
            [('call_with_body_bytes_expecting_body',
 
2298
              'Repository.get_parent_map', ('quack/', 'include-missing:', r2),
 
2299
              '\n\n0')],
 
2300
            client._calls)
 
2301
        repo.unlock()
 
2302
 
2233
2303
 
2234
2304
class TestGetParentMapAllowsNew(tests.TestCaseWithTransport):
2235
2305
 
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]
 
3321
        revs.reverse()
 
3322
        search = _mod_graph.PendingAncestryResult([tip], stacked.repository)
3249
3323
        self.reset_smart_call_log()
3250
3324
        stream = source.get_stream(search)
3251
 
        if None in revs:
3252
 
            revs.remove(None)
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)
3298
3370
 
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)
3363
3436
 
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.
3381
3454
            """
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',)))
 
3459
                    return (None,
 
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)
3403
3479
 
 
3480
 
 
3481
class TestUpdateBoundBranchWithModifiedBoundLocation(
 
3482
    tests.TestCaseWithTransport):
 
3483
    """Ensure correct handling of bound_location modifications.
 
3484
 
 
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.
 
3488
    """
 
3489
 
 
3490
    def setUp(self):
 
3491
        super(TestUpdateBoundBranchWithModifiedBoundLocation, self).setUp()
 
3492
        self.transport_server = test_server.SmartTCPServer_for_testing
 
3493
 
 
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()
 
3502
 
 
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())
 
3507
 
 
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('/'))
 
3514
 
 
3515
    def test_plus_sign(self):
 
3516
        self.make_master_and_checkout('+master', 'checkout')
 
3517
        self.assertUpdateSucceeds(self.bound_location.replace('%2B', '+', 1))
 
3518
 
 
3519
    def test_tilda(self):
 
3520
        # Embed ~ in the middle of the path just to avoid any $HOME
 
3521
        # interpretation
 
3522
        self.make_master_and_checkout('mas~ter', 'checkout')
 
3523
        self.assertUpdateSucceeds(self.bound_location.replace('%2E', '~', 1))