~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_repository/test_repository.py

(gz) Fix test failure on alpha by correcting format string for
 gc_chk_sha1_record (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    tests,
34
34
    transport,
35
35
    upgrade,
 
36
    versionedfile,
36
37
    workingtree,
37
38
    )
38
39
from bzrlib.repofmt import (
39
 
    knitpack_repo,
 
40
    pack_repo,
 
41
    weaverepo,
40
42
    )
41
43
from bzrlib.tests import (
42
44
    per_repository,
64
66
        repo = self.make_repository('repo')
65
67
        self.assertSubset([getattr(repo._format, attribute)], allowed_values)
66
68
 
 
69
    def test_attribute__fetch_order(self):
 
70
        """Test the _fetch_order attribute."""
 
71
        self.assertFormatAttribute('_fetch_order', ('topological', 'unordered'))
 
72
 
 
73
    def test_attribute__fetch_uses_deltas(self):
 
74
        """Test the _fetch_uses_deltas attribute."""
 
75
        self.assertFormatAttribute('_fetch_uses_deltas', (True, False))
 
76
 
67
77
    def test_attribute_fast_deltas(self):
68
78
        """Test the format.fast_deltas attribute."""
69
79
        self.assertFormatAttribute('fast_deltas', (True, False))
70
80
 
71
 
    def test_attribute_supports_nesting_repositories(self):
72
 
        """Test the format.supports_nesting_repositories."""
73
 
        self.assertFormatAttribute('supports_nesting_repositories',
74
 
            (True, False))
75
 
 
76
81
    def test_attribute__fetch_reconcile(self):
77
82
        """Test the _fetch_reconcile attribute."""
78
83
        self.assertFormatAttribute('_fetch_reconcile', (True, False))
83
88
    def test_attribute_format_pack_compresses(self):
84
89
        self.assertFormatAttribute('pack_compresses', (True, False))
85
90
 
86
 
    def test_attribute_format_supports_full_versioned_files(self):
87
 
        self.assertFormatAttribute('supports_full_versioned_files',
88
 
            (True, False))
89
 
 
90
 
    def test_attribute_format_supports_funky_characters(self):
91
 
        self.assertFormatAttribute('supports_funky_characters',
92
 
            (True, False))
93
 
 
94
 
    def test_attribute_format_supports_leaving_lock(self):
95
 
        self.assertFormatAttribute('supports_leaving_lock',
96
 
            (True, False))
97
 
 
98
 
    def test_attribute_format_versioned_directories(self):
99
 
        self.assertFormatAttribute('supports_versioned_directories', (True, False))
100
 
 
101
 
    def test_attribute_format_revision_graph_can_have_wrong_parents(self):
102
 
        self.assertFormatAttribute('revision_graph_can_have_wrong_parents',
103
 
            (True, False))
104
 
 
105
 
    def test_format_is_deprecated(self):
106
 
        repo = self.make_repository('repo')
107
 
        self.assertSubset([repo._format.is_deprecated()], (True, False))
108
 
 
109
 
    def test_format_is_supported(self):
110
 
        repo = self.make_repository('repo')
111
 
        self.assertSubset([repo._format.is_supported()], (True, False))
 
91
    def test_attribute_inventories_store(self):
 
92
        """Test the existence of the inventories attribute."""
 
93
        tree = self.make_branch_and_tree('tree')
 
94
        repo = tree.branch.repository
 
95
        self.assertIsInstance(repo.inventories, versionedfile.VersionedFiles)
 
96
 
 
97
    def test_attribute_inventories_basics(self):
 
98
        """Test basic aspects of the inventories attribute."""
 
99
        tree = self.make_branch_and_tree('tree')
 
100
        repo = tree.branch.repository
 
101
        rev_id = (tree.commit('a'),)
 
102
        tree.lock_read()
 
103
        self.addCleanup(tree.unlock)
 
104
        self.assertEqual(set([rev_id]), set(repo.inventories.keys()))
 
105
 
 
106
    def test_attribute_revision_store(self):
 
107
        """Test the existence of the revisions attribute."""
 
108
        tree = self.make_branch_and_tree('tree')
 
109
        repo = tree.branch.repository
 
110
        self.assertIsInstance(repo.revisions,
 
111
            versionedfile.VersionedFiles)
 
112
 
 
113
    def test_attribute_revision_store_basics(self):
 
114
        """Test the basic behaviour of the revisions attribute."""
 
115
        tree = self.make_branch_and_tree('tree')
 
116
        repo = tree.branch.repository
 
117
        repo.lock_write()
 
118
        try:
 
119
            self.assertEqual(set(), set(repo.revisions.keys()))
 
120
            revid = (tree.commit("foo"),)
 
121
            self.assertEqual(set([revid]), set(repo.revisions.keys()))
 
122
            self.assertEqual({revid:()},
 
123
                repo.revisions.get_parent_map([revid]))
 
124
        finally:
 
125
            repo.unlock()
 
126
        tree2 = self.make_branch_and_tree('tree2')
 
127
        tree2.pull(tree.branch)
 
128
        left_id = (tree2.commit('left'),)
 
129
        right_id = (tree.commit('right'),)
 
130
        tree.merge_from_branch(tree2.branch)
 
131
        merge_id = (tree.commit('merged'),)
 
132
        repo.lock_read()
 
133
        self.addCleanup(repo.unlock)
 
134
        self.assertEqual(set([revid, left_id, right_id, merge_id]),
 
135
            set(repo.revisions.keys()))
 
136
        self.assertEqual({revid:(), left_id:(revid,), right_id:(revid,),
 
137
             merge_id:(right_id, left_id)},
 
138
            repo.revisions.get_parent_map(repo.revisions.keys()))
 
139
 
 
140
    def test_attribute_signature_store(self):
 
141
        """Test the existence of the signatures attribute."""
 
142
        tree = self.make_branch_and_tree('tree')
 
143
        repo = tree.branch.repository
 
144
        self.assertIsInstance(repo.signatures,
 
145
            versionedfile.VersionedFiles)
 
146
 
 
147
    def test_attribute_text_store_basics(self):
 
148
        """Test the basic behaviour of the text store."""
 
149
        tree = self.make_branch_and_tree('tree')
 
150
        repo = tree.branch.repository
 
151
        file_id = "Foo:Bar"
 
152
        file_key = (file_id,)
 
153
        tree.lock_write()
 
154
        try:
 
155
            self.assertEqual(set(), set(repo.texts.keys()))
 
156
            tree.add(['foo'], [file_id], ['file'])
 
157
            tree.put_file_bytes_non_atomic(file_id, 'content\n')
 
158
            try:
 
159
                rev_key = (tree.commit("foo"),)
 
160
            except errors.IllegalPath:
 
161
                raise tests.TestNotApplicable(
 
162
                    'file_id %r cannot be stored on this'
 
163
                    ' platform for this repo format' % (file_id,))
 
164
            if repo._format.rich_root_data:
 
165
                root_commit = (tree.get_root_id(),) + rev_key
 
166
                keys = set([root_commit])
 
167
                parents = {root_commit:()}
 
168
            else:
 
169
                keys = set()
 
170
                parents = {}
 
171
            keys.add(file_key + rev_key)
 
172
            parents[file_key + rev_key] = ()
 
173
            self.assertEqual(keys, set(repo.texts.keys()))
 
174
            self.assertEqual(parents,
 
175
                repo.texts.get_parent_map(repo.texts.keys()))
 
176
        finally:
 
177
            tree.unlock()
 
178
        tree2 = self.make_branch_and_tree('tree2')
 
179
        tree2.pull(tree.branch)
 
180
        tree2.put_file_bytes_non_atomic('Foo:Bar', 'right\n')
 
181
        right_key = (tree2.commit('right'),)
 
182
        keys.add(file_key + right_key)
 
183
        parents[file_key + right_key] = (file_key + rev_key,)
 
184
        tree.put_file_bytes_non_atomic('Foo:Bar', 'left\n')
 
185
        left_key = (tree.commit('left'),)
 
186
        keys.add(file_key + left_key)
 
187
        parents[file_key + left_key] = (file_key + rev_key,)
 
188
        tree.merge_from_branch(tree2.branch)
 
189
        tree.put_file_bytes_non_atomic('Foo:Bar', 'merged\n')
 
190
        try:
 
191
            tree.auto_resolve()
 
192
        except errors.UnsupportedOperation:
 
193
            pass
 
194
        merge_key = (tree.commit('merged'),)
 
195
        keys.add(file_key + merge_key)
 
196
        parents[file_key + merge_key] = (file_key + left_key,
 
197
                                         file_key + right_key)
 
198
        repo.lock_read()
 
199
        self.addCleanup(repo.unlock)
 
200
        self.assertEqual(keys, set(repo.texts.keys()))
 
201
        self.assertEqual(parents, repo.texts.get_parent_map(repo.texts.keys()))
 
202
 
 
203
    def test_attribute_text_store(self):
 
204
        """Test the existence of the texts attribute."""
 
205
        tree = self.make_branch_and_tree('tree')
 
206
        repo = tree.branch.repository
 
207
        self.assertIsInstance(repo.texts,
 
208
            versionedfile.VersionedFiles)
 
209
 
 
210
    def test_exposed_versioned_files_are_marked_dirty(self):
 
211
        repo = self.make_repository('.')
 
212
        repo.lock_write()
 
213
        signatures = repo.signatures
 
214
        revisions = repo.revisions
 
215
        inventories = repo.inventories
 
216
        repo.unlock()
 
217
        self.assertRaises(errors.ObjectNotLocked,
 
218
            signatures.keys)
 
219
        self.assertRaises(errors.ObjectNotLocked,
 
220
            revisions.keys)
 
221
        self.assertRaises(errors.ObjectNotLocked,
 
222
            inventories.keys)
 
223
        self.assertRaises(errors.ObjectNotLocked,
 
224
            signatures.add_lines, ('foo',), [], [])
 
225
        self.assertRaises(errors.ObjectNotLocked,
 
226
            revisions.add_lines, ('foo',), [], [])
 
227
        self.assertRaises(errors.ObjectNotLocked,
 
228
            inventories.add_lines, ('foo',), [], [])
112
229
 
113
230
    def test_clone_to_default_format(self):
114
231
        #TODO: Test that cloning a repository preserves all the information
126
243
        tree_b.get_file_text('file1')
127
244
        rev1 = repo_b.get_revision('rev1')
128
245
 
 
246
    def test_iter_inventories_is_ordered(self):
 
247
        # just a smoke test
 
248
        tree = self.make_branch_and_tree('a')
 
249
        first_revision = tree.commit('')
 
250
        second_revision = tree.commit('')
 
251
        tree.lock_read()
 
252
        self.addCleanup(tree.unlock)
 
253
        revs = (first_revision, second_revision)
 
254
        invs = tree.branch.repository.iter_inventories(revs)
 
255
        for rev_id, inv in zip(revs, invs):
 
256
            self.assertEqual(rev_id, inv.revision_id)
 
257
            self.assertIsInstance(inv, inventory.CommonInventory)
 
258
 
129
259
    def test_supports_rich_root(self):
130
260
        tree = self.make_branch_and_tree('a')
131
261
        tree.commit('')
133
263
        rev_tree = tree.branch.repository.revision_tree(second_revision)
134
264
        rev_tree.lock_read()
135
265
        self.addCleanup(rev_tree.unlock)
136
 
        root_revision = rev_tree.get_file_revision(rev_tree.get_root_id())
137
 
        rich_root = (root_revision != second_revision)
 
266
        inv = rev_tree.inventory
 
267
        rich_root = (inv.root.revision != second_revision)
138
268
        self.assertEqual(rich_root,
139
269
                         tree.branch.repository.supports_rich_root())
140
270
 
165
295
                              self.repository_format.__class__)
166
296
        # find it via Repository.open
167
297
        opened_repo = repository.Repository.open(readonly_t.base)
168
 
        self.assertIsInstance(opened_repo, made_repo.__class__)
 
298
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
169
299
        self.assertEqual(made_repo._format.__class__,
170
300
                         opened_repo._format.__class__)
171
301
        # if it has a unique id string, can we probe for it ?
243
373
        tree = wt.branch.repository.revision_tree('revision-1')
244
374
        tree.lock_read()
245
375
        try:
246
 
            self.assertEqual('revision-1',
247
 
                tree.get_file_revision(tree.get_root_id()))
 
376
            self.assertEqual('revision-1', tree.inventory.root.revision)
248
377
            expected = inventory.InventoryDirectory('fixed-root', '', None)
249
378
            expected.revision = 'revision-1'
250
379
            self.assertEqual([('', 'V', 'directory', 'fixed-root', expected)],
352
481
            return
353
482
        try:
354
483
            made_repo.set_make_working_trees(False)
355
 
        except errors.UnsupportedOperation:
 
484
        except NotImplementedError:
356
485
            # the repository does not support having its tree-making flag
357
486
            # toggled.
358
487
            return
370
499
        repo = wt.branch.repository
371
500
        repo.lock_write()
372
501
        repo.start_write_group()
373
 
        try:
374
 
            repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
375
 
        except errors.UnsupportedOperation:
376
 
            self.assertFalse(repo._format.supports_revision_signatures)
377
 
            raise tests.TestNotApplicable("signatures not supported by repository format")
 
502
        repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
378
503
        repo.commit_write_group()
379
504
        repo.unlock()
380
505
        old_signature = repo.get_signature_text('A')
396
521
    def test_format_description(self):
397
522
        repo = self.make_repository('.')
398
523
        text = repo._format.get_format_description()
399
 
        self.assertTrue(len(text))
 
524
        self.failUnless(len(text))
400
525
 
401
526
    def test_format_supports_external_lookups(self):
402
527
        repo = self.make_repository('.')
408
533
        tree = self.make_branch_and_tree('.')
409
534
        tree.commit(message, rev_id='a', allow_pointless=True)
410
535
        rev = tree.branch.repository.get_revision('a')
411
 
        serializer = getattr(tree.branch.repository, "_serializer", None)
412
 
        if serializer is not None and serializer.squashes_xml_invalid_characters:
 
536
        if tree.branch.repository._serializer.squashes_xml_invalid_characters:
413
537
            # we have to manually escape this as we dont try to
414
538
            # roundtrip xml invalid characters in the xml-based serializers.
415
539
            escaped_message, escape_count = re.subn(
470
594
        rev_tree = tree.branch.repository.revision_tree(tree.last_revision())
471
595
        rev_tree.lock_read()
472
596
        self.addCleanup(rev_tree.unlock)
473
 
        root_id = rev_tree.get_root_id()
474
 
        self.assertEqual('rev_id', rev_tree.get_file_revision(root_id))
 
597
        self.assertEqual('rev_id', rev_tree.inventory.root.revision)
 
598
 
 
599
    def test_upgrade_from_format4(self):
 
600
        from bzrlib.tests.test_upgrade import _upgrade_dir_template
 
601
        if isinstance(self.repository_format, remote.RemoteRepositoryFormat):
 
602
            return # local conversion to/from RemoteObjects is irrelevant.
 
603
        if self.repository_format.get_format_description() \
 
604
            == "Repository format 4":
 
605
            raise tests.TestSkipped('Cannot convert format-4 to itself')
 
606
        self.build_tree_contents(_upgrade_dir_template)
 
607
        old_repodir = bzrdir.BzrDir.open_unsupported('.')
 
608
        old_repo_format = old_repodir.open_repository()._format
 
609
        format = self.repository_format._matchingbzrdir
 
610
        try:
 
611
            format.repository_format = self.repository_format
 
612
        except AttributeError:
 
613
            pass
 
614
        upgrade.upgrade('.', format)
475
615
 
476
616
    def test_pointless_commit(self):
477
617
        tree = self.make_branch_and_tree('.')
487
627
        repo._format.rich_root_data
488
628
        repo._format.supports_tree_reference
489
629
 
 
630
    def test_get_serializer_format(self):
 
631
        repo = self.make_repository('.')
 
632
        format = repo.get_serializer_format()
 
633
        self.assertEqual(repo._serializer.format_num, format)
 
634
 
490
635
    def test_iter_files_bytes(self):
491
636
        tree = self.make_branch_and_tree('tree')
492
637
        self.build_tree_contents([('tree/file1', 'foo'),
514
659
                          repository.iter_files_bytes(
515
660
                          [('file3-id', 'rev3', 'file1-notpresent')]))
516
661
 
 
662
    def test_item_keys_introduced_by(self):
 
663
        # Make a repo with one revision and one versioned file.
 
664
        tree = self.make_branch_and_tree('t')
 
665
        self.build_tree(['t/foo'])
 
666
        tree.add('foo', 'file1')
 
667
        tree.commit('message', rev_id='rev_id')
 
668
        repo = tree.branch.repository
 
669
        repo.lock_write()
 
670
        repo.start_write_group()
 
671
        repo.sign_revision('rev_id', gpg.LoopbackGPGStrategy(None))
 
672
        repo.commit_write_group()
 
673
        repo.unlock()
 
674
        repo.lock_read()
 
675
        self.addCleanup(repo.unlock)
 
676
 
 
677
        # Item keys will be in this order, for maximum convenience for
 
678
        # generating data to insert into knit repository:
 
679
        #   * files
 
680
        #   * inventory
 
681
        #   * signatures
 
682
        #   * revisions
 
683
        expected_item_keys = [
 
684
            ('file', 'file1', ['rev_id']),
 
685
            ('inventory', None, ['rev_id']),
 
686
            ('signatures', None, ['rev_id']),
 
687
            ('revisions', None, ['rev_id'])]
 
688
        item_keys = list(repo.item_keys_introduced_by(['rev_id']))
 
689
        item_keys = [
 
690
            (kind, file_id, list(versions))
 
691
            for (kind, file_id, versions) in item_keys]
 
692
 
 
693
        if repo.supports_rich_root():
 
694
            # Check for the root versioned file in the item_keys, then remove
 
695
            # it from streamed_names so we can compare that with
 
696
            # expected_record_names.
 
697
            # Note that the file keys can be in any order, so this test is
 
698
            # written to allow that.
 
699
            inv = repo.get_inventory('rev_id')
 
700
            root_item_key = ('file', inv.root.file_id, ['rev_id'])
 
701
            self.assertTrue(root_item_key in item_keys)
 
702
            item_keys.remove(root_item_key)
 
703
 
 
704
        self.assertEqual(expected_item_keys, item_keys)
 
705
 
517
706
    def test_get_graph(self):
518
707
        """Bare-bones smoketest that all repositories implement get_graph."""
519
708
        repo = self.make_repository('repo')
571
760
        """
572
761
        repo = self.make_repository('.')
573
762
        # This should work, not raise NotImplementedError:
574
 
        if not repo._format.revision_graph_can_have_wrong_parents:
 
763
        if not repo.revision_graph_can_have_wrong_parents():
575
764
            return
576
765
        repo.lock_read()
577
766
        self.addCleanup(repo.unlock)
583
772
        repo._check_for_inconsistent_revision_parents()
584
773
 
585
774
    def test_add_signature_text(self):
586
 
        builder = self.make_branch_builder('.')
587
 
        builder.start_series()
588
 
        builder.build_snapshot('A', None, [
589
 
            ('add', ('', 'root-id', 'directory', None))])
590
 
        builder.finish_series()
591
 
        b = builder.get_branch()
592
 
        b.lock_write()
593
 
        self.addCleanup(b.unlock)
594
 
        b.repository.start_write_group()
595
 
        self.addCleanup(b.repository.abort_write_group)
596
 
        if b.repository._format.supports_revision_signatures:
597
 
            b.repository.add_signature_text('A', 'This might be a signature')
598
 
            self.assertEqual('This might be a signature',
599
 
                             b.repository.get_signature_text('A'))
600
 
        else:
601
 
            self.assertRaises(errors.UnsupportedOperation,
602
 
                b.repository.add_signature_text, 'A',
603
 
                'This might be a signature')
 
775
        repo = self.make_repository('repo')
 
776
        repo.lock_write()
 
777
        self.addCleanup(repo.unlock)
 
778
        repo.start_write_group()
 
779
        self.addCleanup(repo.abort_write_group)
 
780
        inv = inventory.Inventory(revision_id='A')
 
781
        inv.root.revision = 'A'
 
782
        repo.add_inventory('A', inv, [])
 
783
        repo.add_revision('A', _mod_revision.Revision(
 
784
                'A', committer='A', timestamp=0,
 
785
                inventory_sha1='', timezone=0, message='A'))
 
786
        repo.add_signature_text('A', 'This might be a signature')
 
787
        self.assertEqual('This might be a signature',
 
788
                         repo.get_signature_text('A'))
 
789
 
 
790
    def test_add_revision_inventory_sha1(self):
 
791
        inv = inventory.Inventory(revision_id='A')
 
792
        inv.root.revision = 'A'
 
793
        inv.root.file_id = 'fixed-root'
 
794
        # Insert the inventory on its own to an identical repository, to get
 
795
        # its sha1.
 
796
        reference_repo = self.make_repository('reference_repo')
 
797
        reference_repo.lock_write()
 
798
        reference_repo.start_write_group()
 
799
        inv_sha1 = reference_repo.add_inventory('A', inv, [])
 
800
        reference_repo.abort_write_group()
 
801
        reference_repo.unlock()
 
802
        # Now insert a revision with this inventory, and it should get the same
 
803
        # sha1.
 
804
        repo = self.make_repository('repo')
 
805
        repo.lock_write()
 
806
        repo.start_write_group()
 
807
        root_id = inv.root.file_id
 
808
        repo.texts.add_lines(('fixed-root', 'A'), [], [])
 
809
        repo.add_revision('A', _mod_revision.Revision(
 
810
                'A', committer='B', timestamp=0,
 
811
                timezone=0, message='C'), inv=inv)
 
812
        repo.commit_write_group()
 
813
        repo.unlock()
 
814
        repo.lock_read()
 
815
        self.assertEquals(inv_sha1, repo.get_revision('A').inventory_sha1)
 
816
        repo.unlock()
 
817
 
 
818
    def test_install_revisions(self):
 
819
        wt = self.make_branch_and_tree('source')
 
820
        wt.commit('A', allow_pointless=True, rev_id='A')
 
821
        repo = wt.branch.repository
 
822
        repo.lock_write()
 
823
        repo.start_write_group()
 
824
        repo.sign_revision('A', gpg.LoopbackGPGStrategy(None))
 
825
        repo.commit_write_group()
 
826
        repo.unlock()
 
827
        repo.lock_read()
 
828
        self.addCleanup(repo.unlock)
 
829
        repo2 = self.make_repository('repo2')
 
830
        revision = repo.get_revision('A')
 
831
        tree = repo.revision_tree('A')
 
832
        signature = repo.get_signature_text('A')
 
833
        repo2.lock_write()
 
834
        self.addCleanup(repo2.unlock)
 
835
        repository.install_revisions(repo2, [(revision, tree, signature)])
 
836
        self.assertEqual(revision, repo2.get_revision('A'))
 
837
        self.assertEqual(signature, repo2.get_signature_text('A'))
604
838
 
605
839
    # XXX: this helper duplicated from tests.test_repository
606
840
    def make_remote_repository(self, path, shared=False):
609
843
        repo = self.make_repository(path, shared=shared)
610
844
        smart_server = test_server.SmartTCPServer_for_testing()
611
845
        self.start_server(smart_server, self.get_server())
612
 
        remote_transport = transport.get_transport_from_url(
 
846
        remote_transport = transport.get_transport(
613
847
            smart_server.get_url()).clone(path)
614
848
        remote_bzrdir = bzrdir.BzrDir.open_from_transport(remote_transport)
615
849
        remote_repo = remote_bzrdir.open_repository()
696
930
        except errors.IncompatibleFormat:
697
931
            raise tests.TestNotApplicable('Cannot make a shared repository')
698
932
        if repo.bzrdir._format.fixed_components:
699
 
            self.knownFailure(
 
933
            raise tests.KnownFailure(
700
934
                "pre metadir branches do not upgrade on push "
701
935
                "with stacking policy")
702
936
        if isinstance(repo._format,
703
 
                      knitpack_repo.RepositoryFormatKnitPack5RichRootBroken):
 
937
                      pack_repo.RepositoryFormatKnitPack5RichRootBroken):
704
938
            raise tests.TestNotApplicable("unsupported format")
705
939
        # Make a source branch in 'repo' in an unstackable branch format
706
940
        bzrdir_format = self.repository_format._matchingbzrdir
745
979
        else:
746
980
            self.assertEqual(stack_on.repository._format, target_repo._format)
747
981
 
 
982
    def test__get_sink(self):
 
983
        repo = self.make_repository('repo')
 
984
        sink = repo._get_sink()
 
985
        self.assertIsInstance(sink, repository.StreamSink)
 
986
 
748
987
    def test__make_parents_provider(self):
749
988
        """Repositories must have a _make_parents_provider method that returns
750
989
        an object with a get_parent_map method.
752
991
        repo = self.make_repository('repo')
753
992
        repo._make_parents_provider().get_parent_map
754
993
 
755
 
    def make_repository_and_foo_bar(self, shared=None):
 
994
    def make_repository_and_foo_bar(self, shared):
756
995
        made_control = self.make_bzrdir('repository')
757
996
        repo = made_control.create_repository(shared=shared)
758
 
        if not repo._format.supports_nesting_repositories:
759
 
            raise tests.TestNotApplicable("repository does not support "
760
 
                "nesting repositories")
761
997
        bzrdir.BzrDir.create_branch_convenience(self.get_url('repository/foo'),
762
998
                                                force_new_repo=False)
763
999
        bzrdir.BzrDir.create_branch_convenience(self.get_url('repository/bar'),
768
1004
        return repo
769
1005
 
770
1006
    def test_find_branches(self):
771
 
        repo = self.make_repository_and_foo_bar()
 
1007
        repo = self.make_repository_and_foo_bar(shared=False)
772
1008
        branches = repo.find_branches()
773
1009
        self.assertContainsRe(branches[-1].base, 'repository/foo/$')
774
1010
        self.assertContainsRe(branches[-3].base, 'repository/baz/qux/$')
797
1033
 
798
1034
    def test_find_branches_using_standalone(self):
799
1035
        branch = self.make_branch('branch')
800
 
        if not branch.repository._format.supports_nesting_repositories:
801
 
            raise tests.TestNotApplicable("format does not support nesting "
802
 
                "repositories")
803
1036
        contained = self.make_branch('branch/contained')
804
1037
        branches = branch.repository.find_branches(using=True)
805
1038
        self.assertEqual([branch.base], [b.base for b in branches])
808
1041
                         [b.base for b in branches])
809
1042
 
810
1043
    def test_find_branches_using_empty_standalone_repo(self):
811
 
        repo = self.make_repository('repo', shared=False)
 
1044
        repo = self.make_repository('repo')
 
1045
        self.assertFalse(repo.is_shared())
812
1046
        try:
813
1047
            repo.bzrdir.open_branch()
814
1048
        except errors.NotBranchError:
821
1055
        repo = self.make_repository('repo')
822
1056
        try:
823
1057
            repo.set_make_working_trees(True)
824
 
        except (errors.RepositoryUpgradeRequired, errors.UnsupportedOperation), e:
 
1058
        except errors.RepositoryUpgradeRequired, e:
825
1059
            raise tests.TestNotApplicable('Format does not support this flag.')
826
1060
        self.assertTrue(repo.make_working_trees())
827
1061
 
829
1063
        repo = self.make_repository('repo')
830
1064
        try:
831
1065
            repo.set_make_working_trees(False)
832
 
        except (errors.RepositoryUpgradeRequired, errors.UnsupportedOperation), e:
 
1066
        except errors.RepositoryUpgradeRequired, e:
833
1067
            raise tests.TestNotApplicable('Format does not support this flag.')
834
1068
        self.assertFalse(repo.make_working_trees())
835
1069
 
903
1137
        self.assertThat(repo.lock_write, ReturnsUnlockable(repo))
904
1138
 
905
1139
 
 
1140
class TestCaseWithComplexRepository(per_repository.TestCaseWithRepository):
 
1141
 
 
1142
    def setUp(self):
 
1143
        super(TestCaseWithComplexRepository, self).setUp()
 
1144
        tree_a = self.make_branch_and_tree('a')
 
1145
        self.bzrdir = tree_a.branch.bzrdir
 
1146
        # add a corrupt inventory 'orphan'
 
1147
        # this may need some generalising for knits.
 
1148
        tree_a.lock_write()
 
1149
        try:
 
1150
            tree_a.branch.repository.start_write_group()
 
1151
            try:
 
1152
                inv_file = tree_a.branch.repository.inventories
 
1153
                inv_file.add_lines(('orphan',), [], [])
 
1154
            except:
 
1155
                tree_a.branch.repository.commit_write_group()
 
1156
                raise
 
1157
            else:
 
1158
                tree_a.branch.repository.abort_write_group()
 
1159
        finally:
 
1160
            tree_a.unlock()
 
1161
        # add a real revision 'rev1'
 
1162
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
 
1163
        # add a real revision 'rev2' based on rev1
 
1164
        tree_a.commit('rev2', rev_id='rev2', allow_pointless=True)
 
1165
        # add a reference to a ghost
 
1166
        tree_a.add_parent_tree_id('ghost1')
 
1167
        try:
 
1168
            tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
 
1169
        except errors.RevisionNotPresent:
 
1170
            raise tests.TestNotApplicable(
 
1171
                "Cannot test with ghosts for this format.")
 
1172
        # add another reference to a ghost, and a second ghost.
 
1173
        tree_a.add_parent_tree_id('ghost1')
 
1174
        tree_a.add_parent_tree_id('ghost2')
 
1175
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
 
1176
 
 
1177
    def test_revision_trees(self):
 
1178
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
 
1179
        repository = self.bzrdir.open_repository()
 
1180
        repository.lock_read()
 
1181
        self.addCleanup(repository.unlock)
 
1182
        trees1 = list(repository.revision_trees(revision_ids))
 
1183
        trees2 = [repository.revision_tree(t) for t in revision_ids]
 
1184
        self.assertEqual(len(trees1), len(trees2))
 
1185
        for tree1, tree2 in zip(trees1, trees2):
 
1186
            self.assertFalse(tree2.changes_from(tree1).has_changed())
 
1187
 
 
1188
    def test_get_deltas_for_revisions(self):
 
1189
        repository = self.bzrdir.open_repository()
 
1190
        repository.lock_read()
 
1191
        self.addCleanup(repository.unlock)
 
1192
        revisions = [repository.get_revision(r) for r in
 
1193
                     ['rev1', 'rev2', 'rev3', 'rev4']]
 
1194
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
 
1195
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
 
1196
                   revisions]
 
1197
        self.assertEqual(deltas1, deltas2)
 
1198
 
 
1199
    def test_all_revision_ids(self):
 
1200
        # all_revision_ids -> all revisions
 
1201
        self.assertEqual(set(['rev1', 'rev2', 'rev3', 'rev4']),
 
1202
            set(self.bzrdir.open_repository().all_revision_ids()))
 
1203
 
 
1204
    def test_get_ancestry_missing_revision(self):
 
1205
        # get_ancestry(revision that is in some data but not fully installed
 
1206
        # -> NoSuchRevision
 
1207
        self.assertRaises(errors.NoSuchRevision,
 
1208
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
 
1209
 
 
1210
    def test_get_unordered_ancestry(self):
 
1211
        repo = self.bzrdir.open_repository()
 
1212
        self.assertEqual(set(repo.get_ancestry('rev3')),
 
1213
                         set(repo.get_ancestry('rev3', topo_sorted=False)))
 
1214
 
 
1215
    def test_reserved_id(self):
 
1216
        repo = self.make_repository('repository')
 
1217
        repo.lock_write()
 
1218
        repo.start_write_group()
 
1219
        try:
 
1220
            self.assertRaises(errors.ReservedId, repo.add_inventory, 'reserved:',
 
1221
                              None, None)
 
1222
            self.assertRaises(errors.ReservedId, repo.add_inventory_by_delta,
 
1223
                "foo", [], 'reserved:', None)
 
1224
            self.assertRaises(errors.ReservedId, repo.add_revision, 'reserved:',
 
1225
                              None)
 
1226
        finally:
 
1227
            repo.abort_write_group()
 
1228
            repo.unlock()
 
1229
 
 
1230
 
 
1231
class TestCaseWithCorruptRepository(per_repository.TestCaseWithRepository):
 
1232
 
 
1233
    def setUp(self):
 
1234
        super(TestCaseWithCorruptRepository, self).setUp()
 
1235
        # a inventory with no parents and the revision has parents..
 
1236
        # i.e. a ghost.
 
1237
        repo = self.make_repository('inventory_with_unnecessary_ghost')
 
1238
        repo.lock_write()
 
1239
        repo.start_write_group()
 
1240
        inv = inventory.Inventory(revision_id = 'ghost')
 
1241
        inv.root.revision = 'ghost'
 
1242
        if repo.supports_rich_root():
 
1243
            root_id = inv.root.file_id
 
1244
            repo.texts.add_lines((root_id, 'ghost'), [], [])
 
1245
        sha1 = repo.add_inventory('ghost', inv, [])
 
1246
        rev = _mod_revision.Revision(
 
1247
            timestamp=0, timezone=None, committer="Foo Bar <foo@example.com>",
 
1248
            message="Message", inventory_sha1=sha1, revision_id='ghost')
 
1249
        rev.parent_ids = ['the_ghost']
 
1250
        try:
 
1251
            repo.add_revision('ghost', rev)
 
1252
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
 
1253
            raise tests.TestNotApplicable(
 
1254
                "Cannot test with ghosts for this format.")
 
1255
 
 
1256
        inv = inventory.Inventory(revision_id = 'the_ghost')
 
1257
        inv.root.revision = 'the_ghost'
 
1258
        if repo.supports_rich_root():
 
1259
            root_id = inv.root.file_id
 
1260
            repo.texts.add_lines((root_id, 'the_ghost'), [], [])
 
1261
        sha1 = repo.add_inventory('the_ghost', inv, [])
 
1262
        rev = _mod_revision.Revision(
 
1263
            timestamp=0, timezone=None, committer="Foo Bar <foo@example.com>",
 
1264
            message="Message", inventory_sha1=sha1, revision_id='the_ghost')
 
1265
        rev.parent_ids = []
 
1266
        repo.add_revision('the_ghost', rev)
 
1267
        # check its setup usefully
 
1268
        inv_weave = repo.inventories
 
1269
        possible_parents = (None, (('ghost',),))
 
1270
        self.assertSubset(inv_weave.get_parent_map([('ghost',)])[('ghost',)],
 
1271
            possible_parents)
 
1272
        repo.commit_write_group()
 
1273
        repo.unlock()
 
1274
 
 
1275
    def test_corrupt_revision_access_asserts_if_reported_wrong(self):
 
1276
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
 
1277
        repo = repository.Repository.open(repo_url)
 
1278
        reported_wrong = False
 
1279
        try:
 
1280
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
 
1281
                reported_wrong = True
 
1282
        except errors.CorruptRepository:
 
1283
            # caught the bad data:
 
1284
            return
 
1285
        if not reported_wrong:
 
1286
            return
 
1287
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
 
1288
 
 
1289
    def test_corrupt_revision_get_revision_reconcile(self):
 
1290
        repo_url = self.get_url('inventory_with_unnecessary_ghost')
 
1291
        repo = repository.Repository.open(repo_url)
 
1292
        repo.get_revision_reconcile('ghost')
 
1293
 
 
1294
 
906
1295
# FIXME: document why this is a TestCaseWithTransport rather than a
907
1296
#        TestCaseWithRepository
908
1297
class TestEscaping(tests.TestCaseWithTransport):