/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
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
#
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
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
#
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
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
2819.2.5 by Andrew Bennetts
Make reconcile abort gracefully if the revision index has bad parents.
17
"""Tests for reconciliation of repositories."""
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
18
19
20
import bzrlib
21
import bzrlib.errors as errors
2745.6.43 by Andrew Bennetts
Tidy imports, docstrings, comments and variable names.
22
from bzrlib.inventory import Inventory
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
23
from bzrlib.reconcile import reconcile, Reconciler
2819.2.5 by Andrew Bennetts
Make reconcile abort gracefully if the revision index has bad parents.
24
from bzrlib.repofmt.knitrepo import RepositoryFormatKnit
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
25
from bzrlib.revision import Revision
2819.2.5 by Andrew Bennetts
Make reconcile abort gracefully if the revision index has bad parents.
26
from bzrlib.tests import TestSkipped, TestNotApplicable
27
from bzrlib.tests.repository_implementations.helpers import (
28
    TestCaseWithBrokenRevisionIndex,
29
    )
2745.6.32 by Andrew Bennetts
Some testing notes, test reorganisation, XXX comments and some failing tests.
30
from bzrlib.tests.repository_implementations.test_repository import (
31
    TestCaseWithRepository,
32
    )
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
33
from bzrlib.transport import get_transport
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
34
from bzrlib.uncommit import uncommit
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
35
36
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
37
class TestReconcile(TestCaseWithRepository):
38
39
    def checkUnreconciled(self, d, reconciler):
40
        """Check that d did not get reconciled."""
41
        # nothing should have been fixed yet:
42
        self.assertEqual(0, reconciler.inconsistent_parents)
43
        # and no garbage inventories
44
        self.assertEqual(0, reconciler.garbage_inventories)
45
        self.checkNoBackupInventory(d)
46
47
    def checkNoBackupInventory(self, aBzrDir):
48
        """Check that there is no backup inventory in aBzrDir."""
49
        repo = aBzrDir.open_repository()
50
        self.assertRaises(errors.NoSuchFile,
51
                          repo.control_weaves.get_weave,
52
                          'inventory.backup',
53
                          repo.get_transaction())
54
55
56
class TestsNeedingReweave(TestReconcile):
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
57
58
    def setUp(self):
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
59
        super(TestsNeedingReweave, self).setUp()
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
60
        
61
        t = get_transport(self.get_url())
62
        # an empty inventory with no revision for testing with.
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
63
        repo = self.make_repository('inventory_without_revision')
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
64
        repo.lock_write()
65
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
66
        inv = Inventory(revision_id='missing')
67
        inv.root.revision = 'missing'
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
68
        repo.add_inventory('missing', inv, [])
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
69
        repo.commit_write_group()
70
        repo.unlock()
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
71
72
        # an empty inventory with no revision for testing with.
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
73
        # this is referenced by 'references_missing' to let us test
74
        # that all the cached data is correctly converted into ghost links
75
        # and the referenced inventory still cleaned.
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
76
        repo = self.make_repository('inventory_without_revision_and_ghost')
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
77
        repo.lock_write()
78
        repo.start_write_group()
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
79
        repo.add_inventory('missing', inv, [])
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
80
        inv = Inventory(revision_id='references_missing')
81
        inv.root.revision = 'references_missing'
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
82
        sha1 = repo.add_inventory('references_missing', inv, ['missing'])
83
        rev = Revision(timestamp=0,
84
                       timezone=None,
85
                       committer="Foo Bar <foo@example.com>",
86
                       message="Message",
87
                       inventory_sha1=sha1,
88
                       revision_id='references_missing')
89
        rev.parent_ids = ['missing']
90
        repo.add_revision('references_missing', rev)
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
91
        repo.commit_write_group()
92
        repo.unlock()
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
93
94
        # a inventory with no parents and the revision has parents..
95
        # i.e. a ghost.
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
96
        repo = self.make_repository('inventory_one_ghost')
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
97
        repo.lock_write()
98
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
99
        inv = Inventory(revision_id='ghost')
100
        inv.root.revision = 'ghost'
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
101
        sha1 = repo.add_inventory('ghost', inv, [])
102
        rev = Revision(timestamp=0,
103
                       timezone=None,
104
                       committer="Foo Bar <foo@example.com>",
105
                       message="Message",
106
                       inventory_sha1=sha1,
107
                       revision_id='ghost')
108
        rev.parent_ids = ['the_ghost']
109
        repo.add_revision('ghost', rev)
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
110
        repo.commit_write_group()
111
        repo.unlock()
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
112
         
113
        # a inventory with a ghost that can be corrected now.
114
        t.copy_tree('inventory_one_ghost', 'inventory_ghost_present')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
115
        bzrdir_url = self.get_url('inventory_ghost_present')
116
        bzrdir = bzrlib.bzrdir.BzrDir.open(bzrdir_url)
117
        repo = bzrdir.open_repository()
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
118
        repo.lock_write()
119
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
120
        inv = Inventory(revision_id='the_ghost')
121
        inv.root.revision = 'the_ghost'
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
122
        sha1 = repo.add_inventory('the_ghost', inv, [])
123
        rev = Revision(timestamp=0,
124
                       timezone=None,
125
                       committer="Foo Bar <foo@example.com>",
126
                       message="Message",
127
                       inventory_sha1=sha1,
128
                       revision_id='the_ghost')
129
        rev.parent_ids = []
130
        repo.add_revision('the_ghost', rev)
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
131
        repo.commit_write_group()
132
        repo.unlock()
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
133
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
134
    def checkEmptyReconcile(self, **kwargs):
135
        """Check a reconcile on an empty repository."""
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
136
        self.make_repository('empty')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
137
        d = bzrlib.bzrdir.BzrDir.open(self.get_url('empty'))
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
138
        # calling on a empty repository should do nothing
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
139
        reconciler = d.find_repository().reconcile(**kwargs)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
140
        # no inconsistent parents should have been found
141
        self.assertEqual(0, reconciler.inconsistent_parents)
142
        # and no garbage inventories
143
        self.assertEqual(0, reconciler.garbage_inventories)
144
        # and no backup weave should have been needed/made.
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
145
        self.checkNoBackupInventory(d)
146
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
147
    def test_reconcile_empty(self):
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
148
        # in an empty repo, theres nothing to do.
149
        self.checkEmptyReconcile()
150
2671.4.2 by Robert Collins
Review feedback.
151
    def test_repo_has_reconcile_does_inventory_gc_attribute(self):
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
152
        repo = self.make_repository('repo')
2671.4.2 by Robert Collins
Review feedback.
153
        self.assertNotEqual(None, repo._reconcile_does_inventory_gc)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
154
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
155
    def test_reconcile_empty_thorough(self):
156
        # reconcile should accept thorough=True
157
        self.checkEmptyReconcile(thorough=True)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
158
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
159
    def test_convenience_reconcile_inventory_without_revision_reconcile(self):
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
160
        # smoke test for the all in one ui tool
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
161
        bzrdir_url = self.get_url('inventory_without_revision')
162
        bzrdir = bzrlib.bzrdir.BzrDir.open(bzrdir_url)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
163
        repo = bzrdir.open_repository()
2671.4.2 by Robert Collins
Review feedback.
164
        if not repo._reconcile_does_inventory_gc:
165
            raise TestSkipped('Irrelevant test')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
166
        reconcile(bzrdir)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
167
        # now the backup should have it but not the current inventory
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
168
        repo = bzrdir.open_repository()
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
169
        self.check_missing_was_removed(repo)
170
171
    def test_reweave_inventory_without_revision(self):
172
        # an excess inventory on its own is only reconciled by using thorough
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
173
        d_url = self.get_url('inventory_without_revision')
174
        d = bzrlib.bzrdir.BzrDir.open(d_url)
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
175
        repo = d.open_repository()
2671.4.2 by Robert Collins
Review feedback.
176
        if not repo._reconcile_does_inventory_gc:
177
            raise TestSkipped('Irrelevant test')
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
178
        self.checkUnreconciled(d, repo.reconcile())
179
        reconciler = repo.reconcile(thorough=True)
180
        # no bad parents
181
        self.assertEqual(0, reconciler.inconsistent_parents)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
182
        # and one garbage inventory
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
183
        self.assertEqual(1, reconciler.garbage_inventories)
184
        self.check_missing_was_removed(repo)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
185
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
186
    def check_thorough_reweave_missing_revision(self, aBzrDir, reconcile,
187
            **kwargs):
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
188
        # actual low level test.
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
189
        repo = aBzrDir.open_repository()
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
190
        if ([None, 'missing', 'references_missing']
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
191
            != repo.get_ancestry('references_missing')):
192
            # the repo handles ghosts without corruption, so reconcile has
2671.4.3 by Robert Collins
Reformat comment to be more presentable.
193
            # nothing to do here. Specifically, this test has the inventory
194
            # 'missing' present and the revision 'missing' missing, so clearly
195
            # 'missing' cannot be reported in the present ancestry -> missing
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
196
            # is something that can be filled as a ghost.
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
197
            expected_inconsistent_parents = 0
198
        else:
199
            expected_inconsistent_parents = 1
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
200
        reconciler = reconcile(**kwargs)
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
201
        # some number of inconsistent parents should have been found
202
        self.assertEqual(expected_inconsistent_parents,
203
                         reconciler.inconsistent_parents)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
204
        # and one garbage inventories
205
        self.assertEqual(1, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
206
        # now the backup should have it but not the current inventory
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
207
        repo = aBzrDir.open_repository()
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
208
        self.check_missing_was_removed(repo)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
209
        # and the parent list for 'references_missing' should have that
210
        # revision a ghost now.
211
        self.assertEqual([None, 'references_missing'],
212
                         repo.get_ancestry('references_missing'))
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
213
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
214
    def check_missing_was_removed(self, repo):
215
        backup = repo.control_weaves.get_weave('inventory.backup',
216
                                               repo.get_transaction())
217
        self.assertTrue('missing' in backup.versions())
218
        self.assertRaises(errors.RevisionNotPresent,
219
                          repo.get_inventory, 'missing')
220
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
221
    def test_reweave_inventory_without_revision_reconciler(self):
222
        # smoke test for the all in one Reconciler class,
223
        # other tests use the lower level repo.reconcile()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
224
        d_url = self.get_url('inventory_without_revision_and_ghost')
225
        d = bzrlib.bzrdir.BzrDir.open(d_url)
2671.4.2 by Robert Collins
Review feedback.
226
        if not d.open_repository()._reconcile_does_inventory_gc:
227
            raise TestSkipped('Irrelevant test')
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
228
        def reconcile():
229
            reconciler = Reconciler(d)
230
            reconciler.reconcile()
231
            return reconciler
232
        self.check_thorough_reweave_missing_revision(d, reconcile)
233
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
234
    def test_reweave_inventory_without_revision_and_ghost(self):
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
235
        # actual low level test.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
236
        d_url = self.get_url('inventory_without_revision_and_ghost')
237
        d = bzrlib.bzrdir.BzrDir.open(d_url)
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
238
        repo = d.open_repository()
2671.4.2 by Robert Collins
Review feedback.
239
        if not repo._reconcile_does_inventory_gc:
240
            raise TestSkipped('Irrelevant test')
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
241
        # nothing should have been altered yet : inventories without
242
        # revisions are not data loss incurring for current format
243
        self.check_thorough_reweave_missing_revision(d, repo.reconcile,
244
            thorough=True)
245
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
246
    def test_reweave_inventory_preserves_a_revision_with_ghosts(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
247
        d = bzrlib.bzrdir.BzrDir.open(self.get_url('inventory_one_ghost'))
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
248
        reconciler = d.open_repository().reconcile(thorough=True)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
249
        # no inconsistent parents should have been found: 
250
        # the lack of a parent for ghost is normal
251
        self.assertEqual(0, reconciler.inconsistent_parents)
252
        # and one garbage inventories
253
        self.assertEqual(0, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
254
        # now the current inventory should still have 'ghost'
255
        repo = d.open_repository()
256
        repo.get_inventory('ghost')
257
        self.assertEqual([None, 'ghost'], repo.get_ancestry('ghost'))
258
        
259
    def test_reweave_inventory_fixes_ancestryfor_a_present_ghost(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
260
        d = bzrlib.bzrdir.BzrDir.open(self.get_url('inventory_ghost_present'))
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
261
        repo = d.open_repository()
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
262
        ghost_ancestry = repo.get_ancestry('ghost')
263
        if ghost_ancestry == [None, 'the_ghost', 'ghost']:
264
            # the repo handles ghosts without corruption, so reconcile has
265
            # nothing to do
266
            return
267
        self.assertEqual([None, 'ghost'], ghost_ancestry)
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
268
        reconciler = repo.reconcile()
1692.1.3 by Robert Collins
Finish the reconcile tweak: filled in ghosts are a data loss issue and need to be checked during fast reconciles.
269
        # this is a data corrupting error, so a normal reconcile should fix it.
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
270
        # one inconsistent parents should have been found : the
271
        # available but not reference parent for ghost.
272
        self.assertEqual(1, reconciler.inconsistent_parents)
273
        # and no garbage inventories
274
        self.assertEqual(0, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
275
        # now the current inventory should still have 'ghost'
276
        repo = d.open_repository()
277
        repo.get_inventory('ghost')
278
        repo.get_inventory('the_ghost')
279
        self.assertEqual([None, 'the_ghost', 'ghost'], repo.get_ancestry('ghost'))
280
        self.assertEqual([None, 'the_ghost'], repo.get_ancestry('the_ghost'))
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
281
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
282
283
class TestReconcileWithIncorrectRevisionCache(TestReconcile):
284
    """Ancestry data gets cached in knits and weaves should be reconcilable.
285
286
    This class tests that reconcile can correct invalid caches (such as after
287
    a reconcile).
288
    """
289
290
    def setUp(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
291
        self.reduceLockdirTimeout()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
292
        super(TestReconcileWithIncorrectRevisionCache, self).setUp()
293
        
294
        t = get_transport(self.get_url())
295
        # we need a revision with two parents in the wrong order
296
        # which should trigger reinsertion.
297
        # and another with the first one correct but the other two not
298
        # which should not trigger reinsertion.
299
        # these need to be in different repositories so that we don't
300
        # trigger a reconcile based on the other case.
301
        # there is no api to construct a broken knit repository at
302
        # this point. if we ever encounter a bad graph in a knit repo
303
        # we should add a lower level api to allow constructing such cases.
304
        
305
        # first off the common logic:
306
        tree = self.make_branch_and_tree('wrong-first-parent')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
307
        second_tree = self.make_branch_and_tree('reversed-secondary-parents')
308
        for t in [tree, second_tree]:
309
            t.commit('1', rev_id='1')
310
            uncommit(t.branch, tree=t)
311
            t.commit('2', rev_id='2')
312
            uncommit(t.branch, tree=t)
313
            t.commit('3', rev_id='3')
314
            uncommit(t.branch, tree=t)
315
        #second_tree = self.make_branch_and_tree('reversed-secondary-parents')
316
        #second_tree.pull(tree) # XXX won't copy the repo?
317
        repo_secondary = second_tree.branch.repository
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
318
319
        # now setup the wrong-first parent case
320
        repo = tree.branch.repository
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
321
        repo.lock_write()
322
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
323
        inv = Inventory(revision_id='wrong-first-parent')
324
        inv.root.revision = 'wrong-first-parent'
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
325
        sha1 = repo.add_inventory('wrong-first-parent', inv, ['2', '1'])
326
        rev = Revision(timestamp=0,
327
                       timezone=None,
328
                       committer="Foo Bar <foo@example.com>",
329
                       message="Message",
330
                       inventory_sha1=sha1,
331
                       revision_id='wrong-first-parent')
332
        rev.parent_ids = ['1', '2']
333
        repo.add_revision('wrong-first-parent', rev)
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
334
        repo.commit_write_group()
335
        repo.unlock()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
336
337
        # now setup the wrong-secondary parent case
338
        repo = repo_secondary
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
339
        repo.lock_write()
340
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
341
        inv = Inventory(revision_id='wrong-secondary-parent')
342
        inv.root.revision = 'wrong-secondary-parent'
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
343
        sha1 = repo.add_inventory('wrong-secondary-parent', inv, ['1', '3', '2'])
344
        rev = Revision(timestamp=0,
345
                       timezone=None,
346
                       committer="Foo Bar <foo@example.com>",
347
                       message="Message",
348
                       inventory_sha1=sha1,
349
                       revision_id='wrong-secondary-parent')
350
        rev.parent_ids = ['1', '2', '3']
351
        repo.add_revision('wrong-secondary-parent', rev)
2617.6.4 by Robert Collins
Update tests with things that break when a repository requires write groups to be used.
352
        repo.commit_write_group()
353
        repo.unlock()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
354
355
    def test_reconcile_wrong_order(self):
356
        # a wrong order in primary parents is optionally correctable
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
357
        t = get_transport(self.get_url()).clone('wrong-first-parent')
358
        d = bzrlib.bzrdir.BzrDir.open_from_transport(t)
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
359
        repo = d.open_repository()
360
        g = repo.get_revision_graph()
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
361
        if tuple(g['wrong-first-parent']) == ('1', '2'):
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
362
            raise TestSkipped('wrong-first-parent is not setup for testing')
363
        self.checkUnreconciled(d, repo.reconcile())
364
        # nothing should have been altered yet : inventories without
365
        # revisions are not data loss incurring for current format
366
        reconciler = repo.reconcile(thorough=True)
367
        # these show up as inconsistent parents
368
        self.assertEqual(1, reconciler.inconsistent_parents)
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
369
        # and no garbage inventories
370
        self.assertEqual(0, reconciler.garbage_inventories)
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
371
        # and should have been fixed:
372
        g = repo.get_revision_graph()
2625.8.1 by Robert Collins
LIBRARY API BREAKS:
373
        self.assertEqual(('1', '2'), g['wrong-first-parent'])
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
374
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
375
    def test_reconcile_wrong_order_secondary_inventory(self):
376
        # a wrong order in the parents for inventories is ignored.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
377
        t = get_transport(self.get_url()).clone('reversed-secondary-parents')
378
        d = bzrlib.bzrdir.BzrDir.open_from_transport(t)
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
379
        repo = d.open_repository()
380
        self.checkUnreconciled(d, repo.reconcile())
381
        self.checkUnreconciled(d, repo.reconcile(thorough=True))
2745.6.11 by Aaron Bentley
Fix knit file parents to follow parentage from revision/inventory XML
382
2819.2.5 by Andrew Bennetts
Make reconcile abort gracefully if the revision index has bad parents.
383
384
class TestBadRevisionParents(TestCaseWithBrokenRevisionIndex):
385
386
    def test_aborts_if_bad_parents_in_index(self):
387
        """Reconcile refuses to proceed if the revision index is wrong when
388
        checked against the revision texts, so that it does not generate broken
389
        data.
390
391
        Ideally reconcile would fix this, but until we implement that we just
392
        make sure we safely detect this problem.
393
        """
394
        repo = self.make_repo_with_extra_ghost_index()
395
        reconciler = repo.reconcile(thorough=True)
396
        self.assertTrue(reconciler.aborted,
397
            "reconcile should have aborted due to bad parents.")
398
399
    def test_does_not_abort_on_clean_repo(self):
400
        repo = self.make_repository('.')
401
        reconciler = repo.reconcile(thorough=True)
402
        self.assertFalse(reconciler.aborted,
403
            "reconcile should not have aborted on an unbroken repository.")
404