~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_repository.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-04-09 20:23:07 UTC
  • mfrom: (4265.1.4 bbc-merge)
  • Revision ID: pqm@pqm.ubuntu.com-20090409202307-n0depb16qepoe21o
(jam) Change _fetch_uses_deltas = False for CHK repos until we can
        write a better fix.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
                           UnknownFormatError,
32
32
                           UnsupportedFormatError,
33
33
                           )
34
 
from bzrlib import (
35
 
    graph,
36
 
    tests,
37
 
    )
 
34
from bzrlib import graph
38
35
from bzrlib.branchbuilder import BranchBuilder
39
36
from bzrlib.btree_index import BTreeBuilder, BTreeGraphIndex
40
37
from bzrlib.index import GraphIndex, InMemoryGraphIndex
51
48
    get_transport,
52
49
    )
53
50
from bzrlib.transport.memory import MemoryServer
 
51
from bzrlib.util import bencode
54
52
from bzrlib import (
55
 
    bencode,
56
53
    bzrdir,
57
54
    errors,
58
55
    inventory,
486
483
    _serializer = None
487
484
 
488
485
    def supports_rich_root(self):
489
 
        if self._format is not None:
490
 
            return self._format.rich_root_data
491
486
        return False
492
487
 
493
488
    def get_graph(self):
544
539
        # pair that it returns true on for the is_compatible static method
545
540
        # check
546
541
        dummy_a = DummyRepository()
547
 
        dummy_a._format = RepositoryFormat()
548
542
        dummy_b = DummyRepository()
549
 
        dummy_b._format = RepositoryFormat()
550
543
        repo = self.make_repository('.')
551
544
        # hack dummies to look like repo somewhat.
552
545
        dummy_a._serializer = repo._serializer
553
 
        dummy_a._format.supports_tree_reference = repo._format.supports_tree_reference
554
 
        dummy_a._format.rich_root_data = repo._format.rich_root_data
555
546
        dummy_b._serializer = repo._serializer
556
 
        dummy_b._format.supports_tree_reference = repo._format.supports_tree_reference
557
 
        dummy_b._format.rich_root_data = repo._format.rich_root_data
558
547
        repository.InterRepository.register_optimiser(InterDummy)
559
548
        try:
560
549
            # we should get the default for something InterDummy returns False
681
670
        self.assertFalse(repo._format.supports_external_lookups)
682
671
 
683
672
 
684
 
class Test2a(TestCaseWithTransport):
685
 
 
686
 
    def test_format_pack_compresses_True(self):
687
 
        repo = self.make_repository('repo', format='2a')
688
 
        self.assertTrue(repo._format.pack_compresses)
 
673
class TestDevelopment6(TestCaseWithTransport):
689
674
 
690
675
    def test_inventories_use_chk_map_with_parent_base_dict(self):
691
 
        tree = self.make_branch_and_tree('repo', format="2a")
 
676
        tree = self.make_branch_and_tree('repo', format="development6-rich-root")
692
677
        revid = tree.commit("foo")
693
678
        tree.lock_read()
694
679
        self.addCleanup(tree.unlock)
700
685
        self.assertEqual(65536,
701
686
            inv.parent_id_basename_to_file_id._root_node.maximum_size)
702
687
 
703
 
    def test_autopack_unchanged_chk_nodes(self):
704
 
        # at 20 unchanged commits, chk pages are packed that are split into
705
 
        # two groups such that the new pack being made doesn't have all its
706
 
        # pages in the source packs (though they are in the repository).
707
 
        tree = self.make_branch_and_tree('tree', format='2a')
708
 
        for pos in range(20):
709
 
            tree.commit(str(pos))
710
 
 
711
 
    def test_pack_with_hint(self):
712
 
        tree = self.make_branch_and_tree('tree', format='2a')
713
 
        # 1 commit to leave untouched
714
 
        tree.commit('1')
715
 
        to_keep = tree.branch.repository._pack_collection.names()
716
 
        # 2 to combine
717
 
        tree.commit('2')
718
 
        tree.commit('3')
719
 
        all = tree.branch.repository._pack_collection.names()
720
 
        combine = list(set(all) - set(to_keep))
721
 
        self.assertLength(3, all)
722
 
        self.assertLength(2, combine)
723
 
        tree.branch.repository.pack(hint=combine)
724
 
        final = tree.branch.repository._pack_collection.names()
725
 
        self.assertLength(2, final)
726
 
        self.assertFalse(combine[0] in final)
727
 
        self.assertFalse(combine[1] in final)
728
 
        self.assertSubset(to_keep, final)
729
 
 
730
 
    def test_stream_source_to_gc(self):
731
 
        source = self.make_repository('source', format='2a')
732
 
        target = self.make_repository('target', format='2a')
733
 
        stream = source._get_source(target._format)
734
 
        self.assertIsInstance(stream, groupcompress_repo.GroupCHKStreamSource)
735
 
 
736
 
    def test_stream_source_to_non_gc(self):
737
 
        source = self.make_repository('source', format='2a')
738
 
        target = self.make_repository('target', format='rich-root-pack')
739
 
        stream = source._get_source(target._format)
740
 
        # We don't want the child GroupCHKStreamSource
741
 
        self.assertIs(type(stream), repository.StreamSource)
742
 
 
743
 
    def test_get_stream_for_missing_keys_includes_all_chk_refs(self):
744
 
        source_builder = self.make_branch_builder('source',
745
 
                            format='2a')
746
 
        # We have to build a fairly large tree, so that we are sure the chk
747
 
        # pages will have split into multiple pages.
748
 
        entries = [('add', ('', 'a-root-id', 'directory', None))]
749
 
        for i in 'abcdefghijklmnopqrstuvwxyz123456789':
750
 
            for j in 'abcdefghijklmnopqrstuvwxyz123456789':
751
 
                fname = i + j
752
 
                fid = fname + '-id'
753
 
                content = 'content for %s\n' % (fname,)
754
 
                entries.append(('add', (fname, fid, 'file', content)))
755
 
        source_builder.start_series()
756
 
        source_builder.build_snapshot('rev-1', None, entries)
757
 
        # Now change a few of them, so we get a few new pages for the second
758
 
        # revision
759
 
        source_builder.build_snapshot('rev-2', ['rev-1'], [
760
 
            ('modify', ('aa-id', 'new content for aa-id\n')),
761
 
            ('modify', ('cc-id', 'new content for cc-id\n')),
762
 
            ('modify', ('zz-id', 'new content for zz-id\n')),
763
 
            ])
764
 
        source_builder.finish_series()
765
 
        source_branch = source_builder.get_branch()
766
 
        source_branch.lock_read()
767
 
        self.addCleanup(source_branch.unlock)
768
 
        target = self.make_repository('target', format='2a')
769
 
        source = source_branch.repository._get_source(target._format)
770
 
        self.assertIsInstance(source, groupcompress_repo.GroupCHKStreamSource)
771
 
 
772
 
        # On a regular pass, getting the inventories and chk pages for rev-2
773
 
        # would only get the newly created chk pages
774
 
        search = graph.SearchResult(set(['rev-2']), set(['rev-1']), 1,
775
 
                                    set(['rev-2']))
776
 
        simple_chk_records = []
777
 
        for vf_name, substream in source.get_stream(search):
778
 
            if vf_name == 'chk_bytes':
779
 
                for record in substream:
780
 
                    simple_chk_records.append(record.key)
781
 
            else:
782
 
                for _ in substream:
783
 
                    continue
784
 
        # 3 pages, the root (InternalNode), + 2 pages which actually changed
785
 
        self.assertEqual([('sha1:91481f539e802c76542ea5e4c83ad416bf219f73',),
786
 
                          ('sha1:4ff91971043668583985aec83f4f0ab10a907d3f',),
787
 
                          ('sha1:81e7324507c5ca132eedaf2d8414ee4bb2226187',),
788
 
                          ('sha1:b101b7da280596c71a4540e9a1eeba8045985ee0',)],
789
 
                         simple_chk_records)
790
 
        # Now, when we do a similar call using 'get_stream_for_missing_keys'
791
 
        # we should get a much larger set of pages.
792
 
        missing = [('inventories', 'rev-2')]
793
 
        full_chk_records = []
794
 
        for vf_name, substream in source.get_stream_for_missing_keys(missing):
795
 
            if vf_name == 'inventories':
796
 
                for record in substream:
797
 
                    self.assertEqual(('rev-2',), record.key)
798
 
            elif vf_name == 'chk_bytes':
799
 
                for record in substream:
800
 
                    full_chk_records.append(record.key)
801
 
            else:
802
 
                self.fail('Should not be getting a stream of %s' % (vf_name,))
803
 
        # We have 257 records now. This is because we have 1 root page, and 256
804
 
        # leaf pages in a complete listing.
805
 
        self.assertEqual(257, len(full_chk_records))
806
 
        self.assertSubset(simple_chk_records, full_chk_records)
807
 
 
808
 
    def test_inconsistency_fatal(self):
809
 
        repo = self.make_repository('repo', format='2a')
810
 
        self.assertTrue(repo.revisions._index._inconsistency_fatal)
811
 
        self.assertFalse(repo.texts._index._inconsistency_fatal)
812
 
        self.assertFalse(repo.inventories._index._inconsistency_fatal)
813
 
        self.assertFalse(repo.signatures._index._inconsistency_fatal)
814
 
        self.assertFalse(repo.chk_bytes._index._inconsistency_fatal)
815
 
 
816
 
 
817
 
class TestKnitPackStreamSource(tests.TestCaseWithMemoryTransport):
818
 
 
819
 
    def test_source_to_exact_pack_092(self):
820
 
        source = self.make_repository('source', format='pack-0.92')
821
 
        target = self.make_repository('target', format='pack-0.92')
822
 
        stream_source = source._get_source(target._format)
823
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
824
 
 
825
 
    def test_source_to_exact_pack_rich_root_pack(self):
826
 
        source = self.make_repository('source', format='rich-root-pack')
827
 
        target = self.make_repository('target', format='rich-root-pack')
828
 
        stream_source = source._get_source(target._format)
829
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
830
 
 
831
 
    def test_source_to_exact_pack_19(self):
832
 
        source = self.make_repository('source', format='1.9')
833
 
        target = self.make_repository('target', format='1.9')
834
 
        stream_source = source._get_source(target._format)
835
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
836
 
 
837
 
    def test_source_to_exact_pack_19_rich_root(self):
838
 
        source = self.make_repository('source', format='1.9-rich-root')
839
 
        target = self.make_repository('target', format='1.9-rich-root')
840
 
        stream_source = source._get_source(target._format)
841
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
842
 
 
843
 
    def test_source_to_remote_exact_pack_19(self):
844
 
        trans = self.make_smart_server('target')
845
 
        trans.ensure_base()
846
 
        source = self.make_repository('source', format='1.9')
847
 
        target = self.make_repository('target', format='1.9')
848
 
        target = repository.Repository.open(trans.base)
849
 
        stream_source = source._get_source(target._format)
850
 
        self.assertIsInstance(stream_source, pack_repo.KnitPackStreamSource)
851
 
 
852
 
    def test_stream_source_to_non_exact(self):
853
 
        source = self.make_repository('source', format='pack-0.92')
854
 
        target = self.make_repository('target', format='1.9')
855
 
        stream = source._get_source(target._format)
856
 
        self.assertIs(type(stream), repository.StreamSource)
857
 
 
858
 
    def test_stream_source_to_non_exact_rich_root(self):
859
 
        source = self.make_repository('source', format='1.9')
860
 
        target = self.make_repository('target', format='1.9-rich-root')
861
 
        stream = source._get_source(target._format)
862
 
        self.assertIs(type(stream), repository.StreamSource)
863
 
 
864
 
    def test_source_to_remote_non_exact_pack_19(self):
865
 
        trans = self.make_smart_server('target')
866
 
        trans.ensure_base()
867
 
        source = self.make_repository('source', format='1.9')
868
 
        target = self.make_repository('target', format='1.6')
869
 
        target = repository.Repository.open(trans.base)
870
 
        stream_source = source._get_source(target._format)
871
 
        self.assertIs(type(stream_source), repository.StreamSource)
872
 
 
873
 
    def test_stream_source_to_knit(self):
874
 
        source = self.make_repository('source', format='pack-0.92')
875
 
        target = self.make_repository('target', format='dirstate')
876
 
        stream = source._get_source(target._format)
877
 
        self.assertIs(type(stream), repository.StreamSource)
878
 
 
879
 
 
880
 
class TestDevelopment6FindParentIdsOfRevisions(TestCaseWithTransport):
881
 
    """Tests for _find_parent_ids_of_revisions."""
 
688
 
 
689
class TestDevelopment6FindRevisionOutsideSet(TestCaseWithTransport):
 
690
    """Tests for _find_revision_outside_set."""
882
691
 
883
692
    def setUp(self):
884
 
        super(TestDevelopment6FindParentIdsOfRevisions, self).setUp()
 
693
        super(TestDevelopment6FindRevisionOutsideSet, self).setUp()
885
694
        self.builder = self.make_branch_builder('source',
886
695
            format='development6-rich-root')
887
696
        self.builder.start_series()
890
699
        self.repo = self.builder.get_branch().repository
891
700
        self.addCleanup(self.builder.finish_series)
892
701
 
893
 
    def assertParentIds(self, expected_result, rev_set):
894
 
        self.assertEqual(sorted(expected_result),
895
 
            sorted(self.repo._find_parent_ids_of_revisions(rev_set)))
 
702
    def assertRevisionOutsideSet(self, expected_result, rev_set):
 
703
        self.assertEqual(
 
704
            expected_result, self.repo._find_revision_outside_set(rev_set))
896
705
 
897
706
    def test_simple(self):
898
707
        self.builder.build_snapshot('revid1', None, [])
899
 
        self.builder.build_snapshot('revid2', ['revid1'], [])
 
708
        self.builder.build_snapshot('revid2', None, [])
900
709
        rev_set = ['revid2']
901
 
        self.assertParentIds(['revid1'], rev_set)
 
710
        self.assertRevisionOutsideSet('revid1', rev_set)
902
711
 
903
712
    def test_not_first_parent(self):
904
713
        self.builder.build_snapshot('revid1', None, [])
905
 
        self.builder.build_snapshot('revid2', ['revid1'], [])
906
 
        self.builder.build_snapshot('revid3', ['revid2'], [])
 
714
        self.builder.build_snapshot('revid2', None, [])
 
715
        self.builder.build_snapshot('revid3', None, [])
907
716
        rev_set = ['revid3', 'revid2']
908
 
        self.assertParentIds(['revid1'], rev_set)
 
717
        self.assertRevisionOutsideSet('revid1', rev_set)
909
718
 
910
719
    def test_not_null(self):
911
720
        rev_set = ['initial']
912
 
        self.assertParentIds([], rev_set)
 
721
        self.assertRevisionOutsideSet(_mod_revision.NULL_REVISION, rev_set)
913
722
 
914
723
    def test_not_null_set(self):
915
724
        self.builder.build_snapshot('revid1', None, [])
916
725
        rev_set = [_mod_revision.NULL_REVISION]
917
 
        self.assertParentIds([], rev_set)
 
726
        self.assertRevisionOutsideSet(_mod_revision.NULL_REVISION, rev_set)
918
727
 
919
728
    def test_ghost(self):
920
729
        self.builder.build_snapshot('revid1', None, [])
921
730
        rev_set = ['ghost', 'revid1']
922
 
        self.assertParentIds(['initial'], rev_set)
 
731
        self.assertRevisionOutsideSet('initial', rev_set)
923
732
 
924
733
    def test_ghost_parent(self):
925
734
        self.builder.build_snapshot('revid1', None, [])
926
735
        self.builder.build_snapshot('revid2', ['revid1', 'ghost'], [])
927
736
        rev_set = ['revid2', 'revid1']
928
 
        self.assertParentIds(['ghost', 'initial'], rev_set)
 
737
        self.assertRevisionOutsideSet('initial', rev_set)
929
738
 
930
739
    def test_righthand_parent(self):
931
740
        self.builder.build_snapshot('revid1', None, [])
933
742
        self.builder.build_snapshot('revid2b', ['revid1'], [])
934
743
        self.builder.build_snapshot('revid3', ['revid2a', 'revid2b'], [])
935
744
        rev_set = ['revid3', 'revid2a']
936
 
        self.assertParentIds(['revid1', 'revid2b'], rev_set)
 
745
        self.assertRevisionOutsideSet('revid2b', rev_set)
937
746
 
938
747
 
939
748
class TestWithBrokenRepo(TestCaseWithTransport):
1016
825
        """
1017
826
        broken_repo = self.make_broken_repository()
1018
827
        empty_repo = self.make_repository('empty-repo')
1019
 
        try:
1020
 
            empty_repo.fetch(broken_repo)
1021
 
        except (errors.RevisionNotPresent, errors.BzrCheckError):
1022
 
            # Test successful: compression parent not being copied leads to
1023
 
            # error.
1024
 
            return
1025
 
        empty_repo.lock_read()
1026
 
        self.addCleanup(empty_repo.unlock)
1027
 
        text = empty_repo.texts.get_record_stream(
1028
 
            [('file2-id', 'rev3')], 'topological', True).next()
1029
 
        self.assertEqual('line\n', text.get_bytes_as('fulltext'))
 
828
        self.assertRaises((errors.RevisionNotPresent, errors.BzrCheckError),
 
829
                          empty_repo.fetch, broken_repo)
1030
830
 
1031
831
 
1032
832
class TestRepositoryPackCollection(TestCaseWithTransport):
1041
841
 
1042
842
    def make_packs_and_alt_repo(self, write_lock=False):
1043
843
        """Create a pack repo with 3 packs, and access it via a second repo."""
1044
 
        tree = self.make_branch_and_tree('.', format=self.get_format())
 
844
        tree = self.make_branch_and_tree('.')
1045
845
        tree.lock_write()
1046
846
        self.addCleanup(tree.unlock)
1047
847
        rev1 = tree.commit('one')
1357
1157
    """Tests for the packs repository Packer class."""
1358
1158
 
1359
1159
    def test_pack_optimizes_pack_order(self):
1360
 
        builder = self.make_branch_builder('.', format="1.9")
 
1160
        builder = self.make_branch_builder('.')
1361
1161
        builder.start_series()
1362
1162
        builder.build_snapshot('A', None, [
1363
1163
            ('add', ('', 'root-id', 'directory', None)),
1406
1206
        self.assertTrue(new_pack.signature_index._optimize_for_size)
1407
1207
 
1408
1208
 
1409
 
class TestCrossFormatPacks(TestCaseWithTransport):
1410
 
 
1411
 
    def log_pack(self, hint=None):
1412
 
        self.calls.append(('pack', hint))
1413
 
        self.orig_pack(hint=hint)
1414
 
        if self.expect_hint:
1415
 
            self.assertTrue(hint)
1416
 
 
1417
 
    def run_stream(self, src_fmt, target_fmt, expect_pack_called):
1418
 
        self.expect_hint = expect_pack_called
1419
 
        self.calls = []
1420
 
        source_tree = self.make_branch_and_tree('src', format=src_fmt)
1421
 
        source_tree.lock_write()
1422
 
        self.addCleanup(source_tree.unlock)
1423
 
        tip = source_tree.commit('foo')
1424
 
        target = self.make_repository('target', format=target_fmt)
1425
 
        target.lock_write()
1426
 
        self.addCleanup(target.unlock)
1427
 
        source = source_tree.branch.repository._get_source(target._format)
1428
 
        self.orig_pack = target.pack
1429
 
        target.pack = self.log_pack
1430
 
        search = target.search_missing_revision_ids(
1431
 
            source_tree.branch.repository, tip)
1432
 
        stream = source.get_stream(search)
1433
 
        from_format = source_tree.branch.repository._format
1434
 
        sink = target._get_sink()
1435
 
        sink.insert_stream(stream, from_format, [])
1436
 
        if expect_pack_called:
1437
 
            self.assertLength(1, self.calls)
1438
 
        else:
1439
 
            self.assertLength(0, self.calls)
1440
 
 
1441
 
    def run_fetch(self, src_fmt, target_fmt, expect_pack_called):
1442
 
        self.expect_hint = expect_pack_called
1443
 
        self.calls = []
1444
 
        source_tree = self.make_branch_and_tree('src', format=src_fmt)
1445
 
        source_tree.lock_write()
1446
 
        self.addCleanup(source_tree.unlock)
1447
 
        tip = source_tree.commit('foo')
1448
 
        target = self.make_repository('target', format=target_fmt)
1449
 
        target.lock_write()
1450
 
        self.addCleanup(target.unlock)
1451
 
        source = source_tree.branch.repository
1452
 
        self.orig_pack = target.pack
1453
 
        target.pack = self.log_pack
1454
 
        target.fetch(source)
1455
 
        if expect_pack_called:
1456
 
            self.assertLength(1, self.calls)
1457
 
        else:
1458
 
            self.assertLength(0, self.calls)
1459
 
 
1460
 
    def test_sink_format_hint_no(self):
1461
 
        # When the target format says packing makes no difference, pack is not
1462
 
        # called.
1463
 
        self.run_stream('1.9', 'rich-root-pack', False)
1464
 
 
1465
 
    def test_sink_format_hint_yes(self):
1466
 
        # When the target format says packing makes a difference, pack is
1467
 
        # called.
1468
 
        self.run_stream('1.9', '2a', True)
1469
 
 
1470
 
    def test_sink_format_same_no(self):
1471
 
        # When the formats are the same, pack is not called.
1472
 
        self.run_stream('2a', '2a', False)
1473
 
 
1474
 
    def test_IDS_format_hint_no(self):
1475
 
        # When the target format says packing makes no difference, pack is not
1476
 
        # called.
1477
 
        self.run_fetch('1.9', 'rich-root-pack', False)
1478
 
 
1479
 
    def test_IDS_format_hint_yes(self):
1480
 
        # When the target format says packing makes a difference, pack is
1481
 
        # called.
1482
 
        self.run_fetch('1.9', '2a', True)
1483
 
 
1484
 
    def test_IDS_format_same_no(self):
1485
 
        # When the formats are the same, pack is not called.
1486
 
        self.run_fetch('2a', '2a', False)
 
1209
class TestGCCHKPackCollection(TestCaseWithTransport):
 
1210
 
 
1211
    def test_stream_source_to_gc(self):
 
1212
        source = self.make_repository('source', format='development6-rich-root')
 
1213
        target = self.make_repository('target', format='development6-rich-root')
 
1214
        stream = source._get_source(target._format)
 
1215
        self.assertIsInstance(stream, groupcompress_repo.GroupCHKStreamSource)
 
1216
 
 
1217
    def test_stream_source_to_non_gc(self):
 
1218
        source = self.make_repository('source', format='development6-rich-root')
 
1219
        target = self.make_repository('target', format='rich-root-pack')
 
1220
        stream = source._get_source(target._format)
 
1221
        # We don't want the child GroupCHKStreamSource
 
1222
        self.assertIs(type(stream), repository.StreamSource)