/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
1
# Copyright (C) 2005, 2006 Canonical Ltd
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for bzrdir implementations - tests a bzrdir format."""
18
19
import os
1666.1.6 by Robert Collins
Make knit the default format.
20
import re
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
21
import sys
22
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
23
import bzrlib
1773.4.3 by Martin Pool
[merge] bzr.dev
24
from bzrlib import bzrdir, errors, repository
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
25
from bzrlib.branch import Branch, needs_read_lock, needs_write_lock
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
26
from bzrlib.delta import TreeDelta, compare_trees
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
27
from bzrlib.errors import (FileExists,
28
                           NoSuchRevision,
29
                           NoSuchFile,
30
                           UninitializableFormat,
31
                           NotBranchError,
32
                           )
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
33
from bzrlib.revision import NULL_REVISION
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
34
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
35
from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
36
from bzrlib.trace import mutter
37
import bzrlib.transactions as transactions
38
from bzrlib.transport import get_transport
39
from bzrlib.upgrade import upgrade
40
from bzrlib.workingtree import WorkingTree
41
42
43
class TestCaseWithRepository(TestCaseWithBzrDir):
44
45
    def setUp(self):
46
        super(TestCaseWithRepository, self).setUp()
47
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
48
    def make_branch(self, relpath, format=None):
49
        repo = self.make_repository(relpath, format=None)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
50
        return repo.bzrdir.create_branch()
51
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
52
    def make_repository(self, relpath, format=None):
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
53
        made_control = self.make_bzrdir(relpath)
54
        return self.repository_format.initialize(made_control)
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
55
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
56
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
57
class TestRepository(TestCaseWithRepository):
58
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
59
    def test_clone_to_default_format(self):
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
60
        #TODO: Test that cloning a repository preserves all the information
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
61
        # such as signatures[not tested yet] etc etc.
62
        # when changing to the current default format.
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
63
        tree_a = self.make_branch_and_tree('a')
64
        self.build_tree(['a/foo'])
65
        tree_a.add('foo', 'file1')
66
        tree_a.commit('rev1', rev_id='rev1')
67
        bzrdirb = self.make_bzrdir('b')
68
        repo_b = tree_a.branch.repository.clone(bzrdirb)
69
        tree_b = repo_b.revision_tree('rev1')
70
        tree_b.get_file_text('file1')
71
        rev1 = repo_b.get_revision('rev1')
72
73
    def test_clone_specific_format(self):
74
        """todo"""
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
75
76
    def test_format_initialize_find_open(self):
77
        # loopback test to check the current format initializes to itself.
78
        if not self.repository_format.is_supported():
79
            # unsupported formats are not loopback testable
80
            # because the default open will not open them and
81
            # they may not be initializable.
82
            return
83
        # supported formats must be able to init and open
84
        t = get_transport(self.get_url())
85
        readonly_t = get_transport(self.get_readonly_url())
86
        made_control = self.bzrdir_format.initialize(t.base)
87
        made_repo = self.repository_format.initialize(made_control)
88
        self.failUnless(isinstance(made_repo, repository.Repository))
89
        self.assertEqual(made_control, made_repo.bzrdir)
90
91
        # find it via bzrdir opening:
92
        opened_control = bzrdir.BzrDir.open(readonly_t.base)
93
        direct_opened_repo = opened_control.open_repository()
94
        self.assertEqual(direct_opened_repo.__class__, made_repo.__class__)
95
        self.assertEqual(opened_control, direct_opened_repo.bzrdir)
96
97
        self.failUnless(isinstance(direct_opened_repo._format,
98
                        self.repository_format.__class__))
99
        # find it via Repository.open
100
        opened_repo = repository.Repository.open(readonly_t.base)
101
        self.failUnless(isinstance(opened_repo, made_repo.__class__))
102
        self.assertEqual(made_repo._format.__class__,
103
                         opened_repo._format.__class__)
104
        # if it has a unique id string, can we probe for it ?
105
        try:
106
            self.repository_format.get_format_string()
107
        except NotImplementedError:
108
            return
109
        self.assertEqual(self.repository_format,
110
                         repository.RepositoryFormat.find_format(opened_control))
111
112
    def test_create_repository(self):
1534.6.1 by Robert Collins
allow API creation of shared repositories
113
        # bzrdir can construct a repository for itself.
1534.4.40 by Robert Collins
Add RepositoryFormats and allow bzrdir.open or create _repository to be used.
114
        if not self.bzrdir_format.is_supported():
115
            # unsupported formats are not loopback testable
116
            # because the default open will not open them and
117
            # they may not be initializable.
118
            return
119
        t = get_transport(self.get_url())
120
        made_control = self.bzrdir_format.initialize(t.base)
121
        made_repo = made_control.create_repository()
122
        self.failUnless(isinstance(made_repo, repository.Repository))
123
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.1 by Robert Collins
allow API creation of shared repositories
124
        
125
    def test_create_repository_shared(self):
126
        # bzrdir can construct a shared repository.
127
        if not self.bzrdir_format.is_supported():
128
            # unsupported formats are not loopback testable
129
            # because the default open will not open them and
130
            # they may not be initializable.
131
            return
132
        t = get_transport(self.get_url())
133
        made_control = self.bzrdir_format.initialize(t.base)
134
        try:
135
            made_repo = made_control.create_repository(shared=True)
136
        except errors.IncompatibleFormat:
137
            # not all repository formats understand being shared, or
138
            # may only be shared in some circumstances.
139
            return
140
        self.failUnless(isinstance(made_repo, repository.Repository))
141
        self.assertEqual(made_control, made_repo.bzrdir)
1534.6.3 by Robert Collins
find_repository sufficiently robust.
142
        self.assertTrue(made_repo.is_shared())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
143
144
    def test_revision_tree(self):
145
        wt = self.make_branch_and_tree('.')
146
        wt.commit('lala!', rev_id='revision-1', allow_pointless=True)
147
        tree = wt.branch.repository.revision_tree('revision-1')
148
        self.assertEqual(list(tree.list_files()), [])
149
        tree = wt.branch.repository.revision_tree(None)
150
        self.assertEqual(len(tree.list_files()), 0)
151
        tree = wt.branch.repository.revision_tree(NULL_REVISION)
152
        self.assertEqual(len(tree.list_files()), 0)
153
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
154
    def test_fetch(self):
1534.1.29 by Robert Collins
Add a test environment for InterRepository objects, and remove the fetch corner case tests from test_repository.
155
        # smoke test fetch to ensure that the convenience function works.
156
        # it is defined as a convenience function with the underlying 
157
        # functionality provided by an InterRepository
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
158
        tree_a = self.make_branch_and_tree('a')
159
        self.build_tree(['a/foo'])
160
        tree_a.add('foo', 'file1')
161
        tree_a.commit('rev1', rev_id='rev1')
1534.1.29 by Robert Collins
Add a test environment for InterRepository objects, and remove the fetch corner case tests from test_repository.
162
        # fetch with a default limit (grab everything)
163
        repo = bzrdir.BzrDir.create_repository(self.get_url('b'))
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
164
        repo.fetch(tree_a.branch.repository,
165
                   revision_id=None,
166
                   pb=bzrlib.progress.DummyProgress())
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
167
1770.3.3 by Jelmer Vernooij
Add tests for Branch.get_revision_delta() and Repository.get_revision_delta().
168
    def test_get_revision_delta(self):
169
        tree_a = self.make_branch_and_tree('a')
170
        self.build_tree(['a/foo'])
171
        tree_a.add('foo', 'file1')
172
        tree_a.commit('rev1', rev_id='rev1')
173
        self.build_tree(['a/vla'])
174
        tree_a.add('vla', 'file2')
175
        tree_a.commit('rev2', rev_id='rev2')
176
177
        delta = tree_a.branch.repository.get_revision_delta('rev1')
178
        self.assertIsInstance(delta, TreeDelta)
179
        self.assertEqual([('foo', 'file1', 'file')], delta.added)
180
        delta = tree_a.branch.repository.get_revision_delta('rev2')
181
        self.assertIsInstance(delta, TreeDelta)
182
        self.assertEqual([('vla', 'file2', 'file')], delta.added)
183
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
184
    def test_clone_bzrdir_repository_revision(self):
185
        # make a repository with some revisions,
186
        # and clone it, this should not have unreferenced revisions.
187
        # also: test cloning with a revision id of NULL_REVISION -> empty repo.
188
        raise TestSkipped('revision limiting is not implemented yet.')
189
190
    def test_clone_repository_basis_revision(self):
191
        raise TestSkipped('the use of a basis should not add noise data to the result.')
192
193
    def test_clone_repository_incomplete_source_with_basis(self):
194
        # ensure that basis really does grab from the basis by having incomplete source
195
        tree = self.make_branch_and_tree('commit_tree')
196
        self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
197
        tree.add('foo')
198
        tree.commit('revision 1', rev_id='1')
199
        source = self.make_repository('source')
200
        # this gives us an incomplete repository
201
        tree.bzrdir.open_repository().copy_content_into(source)
202
        tree.commit('revision 2', rev_id='2', allow_pointless=True)
203
        self.assertFalse(source.has_revision('2'))
204
        target = source.bzrdir.clone(self.get_url('target'), basis=tree.bzrdir)
205
        self.assertTrue(target.open_repository().has_revision('2'))
206
1534.6.5 by Robert Collins
Cloning of repos preserves shared and make-working-tree attributes.
207
    def test_clone_shared_no_tree(self):
208
        # cloning a shared repository keeps it shared
209
        # and preserves the make_working_tree setting.
210
        made_control = self.make_bzrdir('source')
211
        try:
212
            made_repo = made_control.create_repository(shared=True)
213
        except errors.IncompatibleFormat:
214
            # not all repository formats understand being shared, or
215
            # may only be shared in some circumstances.
216
            return
217
        made_repo.set_make_working_trees(False)
218
        result = made_control.clone(self.get_url('target'))
219
        self.failUnless(isinstance(made_repo, repository.Repository))
220
        self.assertEqual(made_control, made_repo.bzrdir)
221
        self.assertTrue(result.open_repository().is_shared())
222
        self.assertFalse(result.open_repository().make_working_trees())
223
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
224
    def test_upgrade_preserves_signatures(self):
225
        wt = self.make_branch_and_tree('source')
226
        wt.commit('A', allow_pointless=True, rev_id='A')
227
        wt.branch.repository.sign_revision('A',
228
            bzrlib.gpg.LoopbackGPGStrategy(None))
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
229
        old_signature = wt.branch.repository.get_signature_text('A')
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
230
        try:
231
            old_format = bzrdir.BzrDirFormat.get_default_format()
232
            # This gives metadir branches something they can convert to.
233
            # it would be nice to have a 'latest' vs 'default' concept.
234
            bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
235
            try:
236
                upgrade(wt.basedir)
237
            finally:
238
                bzrdir.BzrDirFormat.set_default_format(old_format)
239
        except errors.UpToDateFormat:
240
            # this is in the most current format already.
241
            return
242
        wt = WorkingTree.open(wt.basedir)
1563.2.31 by Robert Collins
Convert Knit repositories to use knits.
243
        new_signature = wt.branch.repository.get_signature_text('A')
1556.1.4 by Robert Collins
Add a new format for what will become knit, and the surrounding logic to upgrade repositories within metadirs, and tests for the same.
244
        self.assertEqual(old_signature, new_signature)
245
1594.2.23 by Robert Collins
Test versioned file storage handling of clean/dirty status for accessed versioned files.
246
    def test_exposed_versioned_files_are_marked_dirty(self):
247
        repo = self.make_repository('.')
248
        repo.lock_write()
249
        inv = repo.get_inventory_weave()
250
        repo.unlock()
251
        self.assertRaises(errors.OutSideTransaction, inv.add_lines, 'foo', [], [])
252
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
253
    def test_format_description(self):
254
        repo = self.make_repository('.')
255
        text = repo._format.get_format_description()
256
        self.failUnless(len(text))
257
1666.1.6 by Robert Collins
Make knit the default format.
258
    def assertMessageRoundtrips(self, message):
259
        """Assert that message roundtrips to a repository and back intact."""
260
        tree = self.make_branch_and_tree('.')
261
        tree.commit(message, rev_id='a', allow_pointless=True)
262
        rev = tree.branch.repository.get_revision('a')
263
        # we have to manually escape this as we dont try to
264
        # roundtrip xml invalid characters at this point.
265
        # when escaping is moved to the serialiser, this test
266
        # can check against the literal message rather than
267
        # this escaped version.
268
        escaped_message, escape_count = re.subn(
269
            u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
270
            lambda match: match.group(0).encode('unicode_escape'),
271
            message)
272
        escaped_message= re.sub('\r', '\n', escaped_message)
273
        self.assertEqual(rev.message, escaped_message)
274
        # insist the class is unicode no matter what came in for 
275
        # consistency.
276
        self.assertIsInstance(rev.message, unicode)
277
278
    def test_commit_unicode_message(self):
279
        # a siple unicode message should be preserved
280
        self.assertMessageRoundtrips(u'foo bar gamm\xae plop')
281
282
    def test_commit_unicode_control_characters(self):
283
        # a unicode message with control characters should roundtrip too.
284
        self.assertMessageRoundtrips(
285
            "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)]))
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
286
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
287
    def test_check_repository(self):
288
        """Check a fairly simple repository's history"""
289
        tree = self.make_branch_and_tree('.')
290
        tree.commit('initial empty commit', rev_id='a-rev',
291
                    allow_pointless=True)
292
        result = tree.branch.repository.check(['a-rev'])
293
        # writes to log; should accept both verbose or non-verbose
294
        result.report_results(verbose=True)
295
        result.report_results(verbose=False)
296
1756.1.5 by Aaron Bentley
Test get_revisions with all repository types (and fix bug...)
297
    def test_get_revisions(self):
298
        tree = self.make_branch_and_tree('.')
299
        tree.commit('initial empty commit', rev_id='a-rev',
300
                    allow_pointless=True)
301
        tree.commit('second empty commit', rev_id='b-rev',
302
                    allow_pointless=True)
303
        tree.commit('third empty commit', rev_id='c-rev',
304
                    allow_pointless=True)
305
        repo = tree.branch.repository
306
        revision_ids = ['a-rev', 'b-rev', 'c-rev']
307
        revisions = repo.get_revisions(revision_ids)
308
        assert len(revisions) == 3, repr(revisions)
309
        zipped = zip(revisions, revision_ids)
310
        self.assertEqual(len(zipped), 3)
311
        for revision, revision_id in zipped:
312
            self.assertEqual(revision.revision_id, revision_id)
313
            self.assertEqual(revision, repo.get_revision(revision_id))
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
314
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
315
class TestCaseWithComplexRepository(TestCaseWithRepository):
316
317
    def setUp(self):
318
        super(TestCaseWithComplexRepository, self).setUp()
319
        tree_a = self.make_branch_and_tree('a')
320
        self.bzrdir = tree_a.branch.bzrdir
321
        # add a corrupt inventory 'orphan'
1534.1.34 by Robert Collins
Move missing_revision_ids from Repository to InterRepository, and eliminate the now unused Repository._compatible_formats method.
322
        # this may need some generalising for knits.
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
323
        inv_file = tree_a.branch.repository.control_weaves.get_weave(
324
            'inventory', 
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
325
            tree_a.branch.repository.get_transaction())
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
326
        inv_file.add_lines('orphan', [], [])
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
327
        # add a real revision 'rev1'
328
        tree_a.commit('rev1', rev_id='rev1', allow_pointless=True)
329
        # add a real revision 'rev2' based on rev1
330
        tree_a.commit('rev2', rev_id='rev2', allow_pointless=True)
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
331
        # add a reference to a ghost
332
        tree_a.add_pending_merge('ghost1')
333
        tree_a.commit('rev3', rev_id='rev3', allow_pointless=True)
334
        # add another reference to a ghost, and a second ghost.
335
        tree_a.add_pending_merge('ghost1')
336
        tree_a.add_pending_merge('ghost2')
337
        tree_a.commit('rev4', rev_id='rev4', allow_pointless=True)
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
338
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
339
    def test_revision_trees(self):
340
        revision_ids = ['rev1', 'rev2', 'rev3', 'rev4']
341
        repository = self.bzrdir.open_repository()
342
        trees1 = list(repository.revision_trees(revision_ids))
343
        trees2 = [repository.revision_tree(t) for t in revision_ids]
344
        assert len(trees1) == len(trees2)
345
        for tree1, tree2 in zip(trees1, trees2):
346
            delta = compare_trees(tree1, tree2)
347
            assert not delta.has_changed()
348
1756.3.22 by Aaron Bentley
Tweaks from review
349
    def test_get_deltas_for_revisions(self):
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
350
        repository = self.bzrdir.open_repository()
351
        revisions = [repository.get_revision(r) for r in 
352
                     ['rev1', 'rev2', 'rev3', 'rev4']]
1756.3.22 by Aaron Bentley
Tweaks from review
353
        deltas1 = list(repository.get_deltas_for_revisions(revisions))
1756.3.20 by Aaron Bentley
Tests for get_revision_deltas and revisions_trees
354
        deltas2 = [repository.get_revision_delta(r.revision_id) for r in
355
                   revisions]
356
        assert deltas1 == deltas2
357
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
358
    def test_all_revision_ids(self):
359
        # all_revision_ids -> all revisions
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
360
        self.assertEqual(['rev1', 'rev2', 'rev3', 'rev4'],
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
361
                         self.bzrdir.open_repository().all_revision_ids())
362
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
363
    def test_get_ancestry_missing_revision(self):
1534.1.34 by Robert Collins
Move missing_revision_ids from Repository to InterRepository, and eliminate the now unused Repository._compatible_formats method.
364
        # get_ancestry(revision that is in some data but not fully installed
365
        # -> NoSuchRevision
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
366
        self.assertRaises(errors.NoSuchRevision,
367
                          self.bzrdir.open_repository().get_ancestry, 'orphan')
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
368
1590.1.1 by Robert Collins
Improve common_ancestor performance.
369
    def test_get_revision_graph(self):
370
        # we can get a mapping of id->parents for the entire revision graph or bits thereof.
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
371
        self.assertEqual({'rev1':[],
372
                          'rev2':['rev1'],
373
                          'rev3':['rev2'],
374
                          'rev4':['rev3'],
375
                          },
1590.1.1 by Robert Collins
Improve common_ancestor performance.
376
                         self.bzrdir.open_repository().get_revision_graph(None))
377
        self.assertEqual({'rev1':[]},
378
                         self.bzrdir.open_repository().get_revision_graph('rev1'))
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
379
        self.assertEqual({'rev1':[],
380
                          'rev2':['rev1']},
1590.1.1 by Robert Collins
Improve common_ancestor performance.
381
                         self.bzrdir.open_repository().get_revision_graph('rev2'))
382
        self.assertRaises(NoSuchRevision,
383
                          self.bzrdir.open_repository().get_revision_graph,
384
                          'orphan')
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
385
        # and ghosts are not mentioned
386
        self.assertEqual({'rev1':[],
387
                          'rev2':['rev1'],
388
                          'rev3':['rev2'],
389
                          },
390
                         self.bzrdir.open_repository().get_revision_graph('rev3'))
391
392
    def test_get_revision_graph_with_ghosts(self):
393
        # we can get a graph object with roots, ghosts, ancestors and
394
        # descendants.
395
        repo = self.bzrdir.open_repository()
396
        graph = repo.get_revision_graph_with_ghosts([])
397
        self.assertEqual(set(['rev1']), graph.roots)
398
        self.assertEqual(set(['ghost1', 'ghost2']), graph.ghosts)
399
        self.assertEqual({'rev1':[],
400
                          'rev2':['rev1'],
401
                          'rev3':['rev2', 'ghost1'],
402
                          'rev4':['rev3', 'ghost1', 'ghost2'],
403
                          },
404
                          graph.get_ancestors())
405
        self.assertEqual({'ghost1':{'rev3':1, 'rev4':1},
406
                          'ghost2':{'rev4':1},
407
                          'rev1':{'rev2':1},
408
                          'rev2':{'rev3':1},
409
                          'rev3':{'rev4':1},
410
                          'rev4':{},
411
                          },
412
                          graph.get_descendants())
1590.1.1 by Robert Collins
Improve common_ancestor performance.
413
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
414
415
class TestCaseWithCorruptRepository(TestCaseWithRepository):
416
417
    def setUp(self):
418
        super(TestCaseWithCorruptRepository, self).setUp()
419
        # a inventory with no parents and the revision has parents..
420
        # i.e. a ghost.
421
        repo = self.make_repository('inventory_with_unnecessary_ghost')
422
        inv = bzrlib.tree.EmptyTree().inventory
423
        sha1 = repo.add_inventory('ghost', inv, [])
424
        rev = bzrlib.revision.Revision(timestamp=0,
425
                                       timezone=None,
426
                                       committer="Foo Bar <foo@example.com>",
427
                                       message="Message",
428
                                       inventory_sha1=sha1,
429
                                       revision_id='ghost')
430
        rev.parent_ids = ['the_ghost']
431
        repo.add_revision('ghost', rev)
432
         
433
        sha1 = repo.add_inventory('the_ghost', inv, [])
434
        rev = bzrlib.revision.Revision(timestamp=0,
435
                                       timezone=None,
436
                                       committer="Foo Bar <foo@example.com>",
437
                                       message="Message",
438
                                       inventory_sha1=sha1,
439
                                       revision_id='the_ghost')
440
        rev.parent_ids = []
441
        repo.add_revision('the_ghost', rev)
442
        # check its setup usefully
443
        inv_weave = repo.get_inventory_weave()
1563.2.30 by Robert Collins
Remove all but fetch references to revision_store, making the repository references that are weave specific use the RevisionTextStore.text_store attribute.
444
        self.assertEqual(['ghost'], inv_weave.get_ancestry(['ghost']))
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
445
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
446
    def test_corrupt_revision_access_asserts_if_reported_wrong(self):
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
447
        repo = repository.Repository.open('inventory_with_unnecessary_ghost')
1594.2.10 by Robert Collins
Teach knit fetching and branching to only duplicate relevant data avoiding unnecessary reconciles.
448
        reported_wrong = False
449
        try:
450
            if repo.get_ancestry('ghost') != [None, 'the_ghost', 'ghost']:
451
                reported_wrong = True
452
        except errors.CorruptRepository:
453
            # caught the bad data:
454
            return
455
        if not reported_wrong:
456
            return
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
457
        self.assertRaises(errors.CorruptRepository, repo.get_revision, 'ghost')
458
1594.2.3 by Robert Collins
bugfix revision.MultipleRevisionSources.get_revision_graph to integrate ghosts between sources. [slow on weaves, fast on knits.
459
    def test_corrupt_revision_get_revision_reconcile(self):
1570.1.13 by Robert Collins
Check for incorrect revision parentage in the weave during revision access.
460
        repo = repository.Repository.open('inventory_with_unnecessary_ghost')
461
        repo.get_revision_reconcile('ghost')