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