374
375
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
375
376
                          target._fetch_order, False),
 
376
377
                         self.find_get_record_stream(source.inventories.calls))
 
377
 
        # Because of bugs in the old fetch code, revisions could accidentally
 
378
 
        # have deltas present in knits. However, it was never intended, so we
 
379
 
        # always for include_delta_closure=True, to make sure we get fulltexts.
 
381
378
        self.assertEqual(('get_record_stream', [('rev-one',)],
 
382
 
                          target._fetch_order, True),
 
 
379
                          target._fetch_order, False),
 
383
380
                         self.find_get_record_stream(source.revisions.calls))
 
384
381
        # XXX: Signatures is special, and slightly broken. The
 
385
382
        # standard item_keys_introduced_by actually does a lookup for every
 
 
432
429
                          target._fetch_order, True),
 
433
430
                         self.find_get_record_stream(signature_calls))
 
 
432
    def test_fetch_revisions_with_deltas_into_pack(self):
 
 
433
        # See BUG #261339, dev versions of bzr could accidentally create deltas
 
 
434
        # in revision texts in knit branches (when fetching from packs). So we
 
 
435
        # ensure that *if* a knit repository has a delta in revisions, that it
 
 
436
        # gets properly expanded back into a fulltext when stored in the pack
 
 
438
        tree = self.make_branch_and_tree('source', format='dirstate')
 
 
439
        target = self.make_repository('target', format='pack-0.92')
 
 
440
        self.build_tree(['source/file'])
 
 
441
        tree.set_root_id('root-id')
 
 
442
        tree.add('file', 'file-id')
 
 
443
        tree.commit('one', rev_id='rev-one')
 
 
444
        # Hack the KVF for revisions so that it "accidentally" allows a delta
 
 
445
        tree.branch.repository.revisions._max_delta_chain = 200
 
 
446
        tree.commit('two', rev_id='rev-two')
 
 
447
        source = tree.branch.repository
 
 
448
        # Ensure that we stored a delta
 
 
450
        self.addCleanup(source.unlock)
 
 
451
        record = source.revisions.get_record_stream([('rev-two',)],
 
 
452
            'unordered', False).next()
 
 
453
        self.assertEqual('knit-delta-gz', record.storage_kind)
 
 
454
        target.fetch(tree.branch.repository, revision_id='rev-two')
 
 
455
        # The record should get expanded back to a fulltext
 
 
457
        self.addCleanup(target.unlock)
 
 
458
        record = target.revisions.get_record_stream([('rev-two',)],
 
 
459
            'unordered', False).next()
 
 
460
        self.assertEqual('knit-ft-gz', record.storage_kind)
 
 
462
    def test_fetch_with_fallback_and_merge(self):
 
 
463
        builder = self.make_branch_builder('source', format='pack-0.92')
 
 
464
        builder.start_series()
 
 
475
        # A & B are present in the base (stacked-on) repository, A-E are
 
 
476
        # present in the source.
 
 
477
        # This reproduces bug #304841
 
 
478
        # We need a large enough inventory that total size of compressed deltas
 
 
479
        # is shorter than the size of a compressed fulltext. We have to use
 
 
480
        # random ids because otherwise the inventory fulltext compresses too
 
 
481
        # well and the deltas get bigger.
 
 
483
            ('add', ('', 'TREE_ROOT', 'directory', None))]
 
 
485
            fname = 'file%03d' % (i,)
 
 
486
            fileid = '%s-%s' % (fname, osutils.rand_chars(64))
 
 
487
            to_add.append(('add', (fname, fileid, 'file', 'content\n')))
 
 
488
        builder.build_snapshot('A', None, to_add)
 
 
489
        builder.build_snapshot('B', ['A'], [])
 
 
490
        builder.build_snapshot('C', ['A'], [])
 
 
491
        builder.build_snapshot('D', ['C'], [])
 
 
492
        builder.build_snapshot('E', ['D'], [])
 
 
493
        builder.build_snapshot('F', ['E', 'B'], [])
 
 
494
        builder.finish_series()
 
 
495
        source_branch = builder.get_branch()
 
 
496
        source_branch.bzrdir.sprout('base', revision_id='B')
 
 
497
        target_branch = self.make_branch('target', format='1.6')
 
 
498
        target_branch.set_stacked_on_url('../base')
 
 
499
        source = source_branch.repository
 
 
501
        self.addCleanup(source.unlock)
 
 
502
        source.inventories = versionedfile.OrderingVersionedFilesDecorator(
 
 
504
                        key_priority={('E',): 1, ('D',): 2, ('C',): 4,
 
 
506
        # Ensure that the content is yielded in the proper order, and given as
 
 
508
        records = [(record.key, record.storage_kind)
 
 
509
                   for record in source.inventories.get_record_stream(
 
 
510
                        [('D',), ('C',), ('E',), ('F',)], 'unordered', False)]
 
 
511
        self.assertEqual([(('E',), 'knit-delta-gz'), (('D',), 'knit-delta-gz'),
 
 
512
                          (('F',), 'knit-delta-gz'), (('C',), 'knit-delta-gz')],
 
 
515
        target_branch.lock_write()
 
 
516
        self.addCleanup(target_branch.unlock)
 
 
517
        target = target_branch.repository
 
 
518
        target.fetch(source, revision_id='F')
 
 
519
        # 'C' should be expanded to a fulltext, but D and E should still be
 
 
521
        stream = target.inventories.get_record_stream(
 
 
522
            [('C',), ('D',), ('E',), ('F',)],
 
 
524
        kinds = dict((record.key, record.storage_kind) for record in stream)
 
 
525
        self.assertEqual({('C',): 'knit-ft-gz', ('D',): 'knit-delta-gz',
 
 
526
                          ('E',): 'knit-delta-gz', ('F',): 'knit-delta-gz'},
 
436
530
class Test1To2Fetch(TestCaseWithTransport):
 
437
531
    """Tests for Model1To2 failure modes"""