/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')
2592.3.38 by Robert Collins
All experimental format tests passing again.
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'
2592.3.119 by Robert Collins
Merge some test fixes from Martin.
68
        repo.add_inventory('missing', inv, [])
2592.3.38 by Robert Collins
All experimental format tests passing again.
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
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
72
        def add_commit(repo, revision_id, parent_ids):
73
            repo.lock_write()
74
            repo.start_write_group()
75
            inv = Inventory(revision_id=revision_id)
76
            inv.root.revision = revision_id
77
            root_id = inv.root.file_id
78
            sha1 = repo.add_inventory(revision_id, inv, parent_ids)
79
            vf = repo.weave_store.get_weave_or_empty(root_id,
80
                repo.get_transaction())
81
            vf.add_lines(revision_id, [], [])
82
            rev = bzrlib.revision.Revision(timestamp=0,
83
                                           timezone=None,
84
                                           committer="Foo Bar <foo@example.com>",
85
                                           message="Message",
86
                                           inventory_sha1=sha1,
87
                                           revision_id=revision_id)
88
            rev.parent_ids = parent_ids
89
            repo.add_revision(revision_id, rev)
90
            repo.commit_write_group()
91
            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.
92
        # an empty inventory with no revision for testing with.
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
93
        # this is referenced by 'references_missing' to let us test
94
        # that all the cached data is correctly converted into ghost links
95
        # 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.
96
        repo = self.make_repository('inventory_without_revision_and_ghost')
2592.3.38 by Robert Collins
All experimental format tests passing again.
97
        repo.lock_write()
98
        repo.start_write_group()
2592.3.119 by Robert Collins
Merge some test fixes from Martin.
99
        repo.add_inventory('missing', inv, [])
2592.3.38 by Robert Collins
All experimental format tests passing again.
100
        repo.commit_write_group()
101
        repo.unlock()
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
102
        add_commit(repo, 'references_missing', ['missing'])
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
103
104
        # a inventory with no parents and the revision has parents..
105
        # i.e. a ghost.
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
106
        repo = self.make_repository('inventory_one_ghost')
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
107
        add_commit(repo, 'ghost', ['the_ghost'])
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
108
         
109
        # a inventory with a ghost that can be corrected now.
110
        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.
111
        bzrdir_url = self.get_url('inventory_ghost_present')
112
        bzrdir = bzrlib.bzrdir.BzrDir.open(bzrdir_url)
113
        repo = bzrdir.open_repository()
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
114
        add_commit(repo, 'the_ghost', [])
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
115
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
116
    def checkEmptyReconcile(self, **kwargs):
117
        """Check a reconcile on an empty repository."""
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
118
        self.make_repository('empty')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
119
        d = bzrlib.bzrdir.BzrDir.open(self.get_url('empty'))
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
120
        # calling on a empty repository should do nothing
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
121
        reconciler = d.find_repository().reconcile(**kwargs)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
122
        # no inconsistent parents should have been found
123
        self.assertEqual(0, reconciler.inconsistent_parents)
124
        # and no garbage inventories
125
        self.assertEqual(0, reconciler.garbage_inventories)
126
        # 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
127
        self.checkNoBackupInventory(d)
128
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
129
    def test_reconcile_empty(self):
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
130
        # in an empty repo, theres nothing to do.
131
        self.checkEmptyReconcile()
132
2671.4.2 by Robert Collins
Review feedback.
133
    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``
134
        repo = self.make_repository('repo')
2671.4.2 by Robert Collins
Review feedback.
135
        self.assertNotEqual(None, repo._reconcile_does_inventory_gc)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
136
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
137
    def test_reconcile_empty_thorough(self):
138
        # reconcile should accept thorough=True
139
        self.checkEmptyReconcile(thorough=True)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
140
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.
141
    def test_convenience_reconcile_inventory_without_revision_reconcile(self):
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
142
        # 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.
143
        bzrdir_url = self.get_url('inventory_without_revision')
144
        bzrdir = bzrlib.bzrdir.BzrDir.open(bzrdir_url)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
145
        repo = bzrdir.open_repository()
2671.4.2 by Robert Collins
Review feedback.
146
        if not repo._reconcile_does_inventory_gc:
147
            raise TestSkipped('Irrelevant test')
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
148
        reconcile(bzrdir)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
149
        # 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.
150
        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.
151
        self.check_missing_was_removed(repo)
152
153
    def test_reweave_inventory_without_revision(self):
154
        # 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.
155
        d_url = self.get_url('inventory_without_revision')
156
        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.
157
        repo = d.open_repository()
2671.4.2 by Robert Collins
Review feedback.
158
        if not repo._reconcile_does_inventory_gc:
159
            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.
160
        self.checkUnreconciled(d, repo.reconcile())
161
        reconciler = repo.reconcile(thorough=True)
162
        # no bad parents
163
        self.assertEqual(0, reconciler.inconsistent_parents)
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
164
        # 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.
165
        self.assertEqual(1, reconciler.garbage_inventories)
166
        self.check_missing_was_removed(repo)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
167
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
168
    def check_thorough_reweave_missing_revision(self, aBzrDir, reconcile,
169
            **kwargs):
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
170
        # actual low level test.
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
171
        repo = aBzrDir.open_repository()
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
172
        if ([None, 'missing', 'references_missing']
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
173
            != repo.get_ancestry('references_missing')):
174
            # the repo handles ghosts without corruption, so reconcile has
2671.4.3 by Robert Collins
Reformat comment to be more presentable.
175
            # nothing to do here. Specifically, this test has the inventory
176
            # 'missing' present and the revision 'missing' missing, so clearly
177
            # 'missing' cannot be reported in the present ancestry -> missing
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
178
            # 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.
179
            expected_inconsistent_parents = 0
180
        else:
181
            expected_inconsistent_parents = 1
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
182
        reconciler = reconcile(**kwargs)
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
183
        # some number of inconsistent parents should have been found
184
        self.assertEqual(expected_inconsistent_parents,
185
                         reconciler.inconsistent_parents)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
186
        # and one garbage inventories
187
        self.assertEqual(1, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
188
        # 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
189
        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.
190
        self.check_missing_was_removed(repo)
1570.1.14 by Robert Collins
Enforce repository consistency during 'fetch' operations.
191
        # and the parent list for 'references_missing' should have that
192
        # revision a ghost now.
193
        self.assertEqual([None, 'references_missing'],
194
                         repo.get_ancestry('references_missing'))
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
195
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.
196
    def check_missing_was_removed(self, repo):
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
197
        if repo._reconcile_backsup_inventory:
198
            backup = repo.control_weaves.get_weave('inventory.backup',
199
                                                   repo.get_transaction())
200
            self.assertTrue('missing' in backup.versions())
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.
201
        self.assertRaises(errors.RevisionNotPresent,
202
                          repo.get_inventory, 'missing')
203
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
204
    def test_reweave_inventory_without_revision_reconciler(self):
205
        # smoke test for the all in one Reconciler class,
206
        # other tests use the lower level repo.reconcile()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
207
        d_url = self.get_url('inventory_without_revision_and_ghost')
208
        d = bzrlib.bzrdir.BzrDir.open(d_url)
2671.4.2 by Robert Collins
Review feedback.
209
        if not d.open_repository()._reconcile_does_inventory_gc:
210
            raise TestSkipped('Irrelevant test')
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
211
        def reconcile():
212
            reconciler = Reconciler(d)
213
            reconciler.reconcile()
214
            return reconciler
215
        self.check_thorough_reweave_missing_revision(d, reconcile)
216
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.
217
    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
218
        # actual low level test.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
219
        d_url = self.get_url('inventory_without_revision_and_ghost')
220
        d = bzrlib.bzrdir.BzrDir.open(d_url)
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
221
        repo = d.open_repository()
2671.4.2 by Robert Collins
Review feedback.
222
        if not repo._reconcile_does_inventory_gc:
223
            raise TestSkipped('Irrelevant test')
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
224
        # nothing should have been altered yet : inventories without
225
        # revisions are not data loss incurring for current format
226
        self.check_thorough_reweave_missing_revision(d, repo.reconcile,
227
            thorough=True)
228
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
229
    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.
230
        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
231
        reconciler = d.open_repository().reconcile(thorough=True)
1570.1.8 by Robert Collins
Only reconcile if doing so will perform gc or correct ancestry.
232
        # no inconsistent parents should have been found: 
233
        # the lack of a parent for ghost is normal
234
        self.assertEqual(0, reconciler.inconsistent_parents)
235
        # and one garbage inventories
236
        self.assertEqual(0, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
237
        # now the current inventory should still have 'ghost'
238
        repo = d.open_repository()
239
        repo.get_inventory('ghost')
240
        self.assertEqual([None, 'ghost'], repo.get_ancestry('ghost'))
241
        
242
    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.
243
        d = bzrlib.bzrdir.BzrDir.open(self.get_url('inventory_ghost_present'))
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
244
        repo = d.open_repository()
1594.2.9 by Robert Collins
Teach Knit repositories how to handle ghosts without corrupting at all.
245
        ghost_ancestry = repo.get_ancestry('ghost')
246
        if ghost_ancestry == [None, 'the_ghost', 'ghost']:
247
            # the repo handles ghosts without corruption, so reconcile has
248
            # nothing to do
249
            return
250
        self.assertEqual([None, 'ghost'], ghost_ancestry)
1594.2.7 by Robert Collins
Add versionedfile.fix_parents api for correcting data post hoc.
251
        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.
252
        # 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.
253
        # one inconsistent parents should have been found : the
254
        # available but not reference parent for ghost.
255
        self.assertEqual(1, reconciler.inconsistent_parents)
256
        # and no garbage inventories
257
        self.assertEqual(0, reconciler.garbage_inventories)
1570.1.2 by Robert Collins
Import bzrtools' 'fix' command as 'bzr reconcile.'
258
        # now the current inventory should still have 'ghost'
259
        repo = d.open_repository()
260
        repo.get_inventory('ghost')
261
        repo.get_inventory('the_ghost')
262
        self.assertEqual([None, 'the_ghost', 'ghost'], repo.get_ancestry('ghost'))
263
        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
264
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
265
266
class TestReconcileWithIncorrectRevisionCache(TestReconcile):
267
    """Ancestry data gets cached in knits and weaves should be reconcilable.
268
269
    This class tests that reconcile can correct invalid caches (such as after
270
    a reconcile).
271
    """
272
273
    def setUp(self):
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
274
        self.reduceLockdirTimeout()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
275
        super(TestReconcileWithIncorrectRevisionCache, self).setUp()
276
        
277
        t = get_transport(self.get_url())
278
        # we need a revision with two parents in the wrong order
279
        # which should trigger reinsertion.
280
        # and another with the first one correct but the other two not
281
        # which should not trigger reinsertion.
282
        # these need to be in different repositories so that we don't
283
        # trigger a reconcile based on the other case.
284
        # there is no api to construct a broken knit repository at
285
        # this point. if we ever encounter a bad graph in a knit repo
286
        # we should add a lower level api to allow constructing such cases.
287
        
288
        # first off the common logic:
289
        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.
290
        second_tree = self.make_branch_and_tree('reversed-secondary-parents')
291
        for t in [tree, second_tree]:
292
            t.commit('1', rev_id='1')
293
            uncommit(t.branch, tree=t)
294
            t.commit('2', rev_id='2')
295
            uncommit(t.branch, tree=t)
296
            t.commit('3', rev_id='3')
297
            uncommit(t.branch, tree=t)
298
        #second_tree = self.make_branch_and_tree('reversed-secondary-parents')
299
        #second_tree.pull(tree) # XXX won't copy the repo?
300
        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.
301
302
        # now setup the wrong-first parent case
303
        repo = tree.branch.repository
2592.3.38 by Robert Collins
All experimental format tests passing again.
304
        repo.lock_write()
305
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
306
        inv = Inventory(revision_id='wrong-first-parent')
307
        inv.root.revision = 'wrong-first-parent'
2592.3.119 by Robert Collins
Merge some test fixes from Martin.
308
        sha1 = repo.add_inventory('wrong-first-parent', inv, ['2', '1'])
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
309
        rev = Revision(timestamp=0,
310
                       timezone=None,
311
                       committer="Foo Bar <foo@example.com>",
312
                       message="Message",
313
                       inventory_sha1=sha1,
314
                       revision_id='wrong-first-parent')
315
        rev.parent_ids = ['1', '2']
316
        repo.add_revision('wrong-first-parent', rev)
2592.3.38 by Robert Collins
All experimental format tests passing again.
317
        repo.commit_write_group()
318
        repo.unlock()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
319
320
        # now setup the wrong-secondary parent case
321
        repo = repo_secondary
2592.3.38 by Robert Collins
All experimental format tests passing again.
322
        repo.lock_write()
323
        repo.start_write_group()
1910.2.23 by Aaron Bentley
Fix up test cases that manually construct inventories
324
        inv = Inventory(revision_id='wrong-secondary-parent')
325
        inv.root.revision = 'wrong-secondary-parent'
2951.1.6 by Robert Collins
All check/reconcile tests passing now.
326
        if repo.supports_rich_root():
327
            root_id = inv.root.file_id
328
            vf = repo.weave_store.get_weave_or_empty(root_id,
329
                repo.get_transaction())
330
            vf.add_lines('wrong-secondary-parent', [], [])
2592.3.119 by Robert Collins
Merge some test fixes from Martin.
331
        sha1 = repo.add_inventory('wrong-secondary-parent', inv, ['1', '3', '2'])
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
332
        rev = Revision(timestamp=0,
333
                       timezone=None,
334
                       committer="Foo Bar <foo@example.com>",
335
                       message="Message",
336
                       inventory_sha1=sha1,
337
                       revision_id='wrong-secondary-parent')
338
        rev.parent_ids = ['1', '2', '3']
339
        repo.add_revision('wrong-secondary-parent', rev)
2592.3.38 by Robert Collins
All experimental format tests passing again.
340
        repo.commit_write_group()
341
        repo.unlock()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
342
343
    def test_reconcile_wrong_order(self):
344
        # 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.
345
        t = get_transport(self.get_url()).clone('wrong-first-parent')
346
        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.
347
        repo = d.open_repository()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
348
        repo.lock_read()
349
        try:
350
            g = repo.get_graph()
351
            if g.get_parent_map(['wrong-first-parent'])['wrong-first-parent'] \
352
                == ('1', '2'):
353
                raise TestSkipped('wrong-first-parent is not setup for testing')
354
        finally:
355
            repo.unlock()
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
356
        self.checkUnreconciled(d, repo.reconcile())
357
        # nothing should have been altered yet : inventories without
358
        # revisions are not data loss incurring for current format
359
        reconciler = repo.reconcile(thorough=True)
360
        # these show up as inconsistent parents
361
        self.assertEqual(1, reconciler.inconsistent_parents)
1692.1.1 by Robert Collins
* Repository.reconcile now takes a thorough keyword parameter to allow
362
        # and no garbage inventories
363
        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.
364
        # and should have been fixed:
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
365
        repo.lock_read()
366
        self.addCleanup(repo.unlock)
367
        g = repo.get_graph()
368
        self.assertEqual(
369
            {'wrong-first-parent':('1', '2')},
370
            g.get_parent_map(['wrong-first-parent']))
1692.1.2 by Robert Collins
Teach reconcile to check the left-most parent is correct in the revision graph.
371
2671.4.1 by Robert Collins
* Add a new method ``bzrlib.repository.Repository.reconcile_actions``
372
    def test_reconcile_wrong_order_secondary_inventory(self):
373
        # 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.
374
        t = get_transport(self.get_url()).clone('reversed-secondary-parents')
375
        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.
376
        repo = d.open_repository()
377
        self.checkUnreconciled(d, repo.reconcile())
378
        self.checkUnreconciled(d, repo.reconcile(thorough=True))
2745.6.11 by Aaron Bentley
Fix knit file parents to follow parentage from revision/inventory XML
379
2819.2.5 by Andrew Bennetts
Make reconcile abort gracefully if the revision index has bad parents.
380
381
class TestBadRevisionParents(TestCaseWithBrokenRevisionIndex):
382
383
    def test_aborts_if_bad_parents_in_index(self):
384
        """Reconcile refuses to proceed if the revision index is wrong when
385
        checked against the revision texts, so that it does not generate broken
386
        data.
387
388
        Ideally reconcile would fix this, but until we implement that we just
389
        make sure we safely detect this problem.
390
        """
391
        repo = self.make_repo_with_extra_ghost_index()
392
        reconciler = repo.reconcile(thorough=True)
393
        self.assertTrue(reconciler.aborted,
394
            "reconcile should have aborted due to bad parents.")
395
396
    def test_does_not_abort_on_clean_repo(self):
397
        repo = self.make_repository('.')
398
        reconciler = repo.reconcile(thorough=True)
399
        self.assertFalse(reconciler.aborted,
400
            "reconcile should not have aborted on an unbroken repository.")
401
2951.2.8 by Robert Collins
Test that reconciling a repository can be done twice in a row.
402
403
class TestRepeatedReconcile(TestReconcile):
404
405
    def test_trivial_two_reconciles_no_error(self):
406
        tree = self.make_branch_and_tree('.')
407
        tree.commit('first post')
408
        tree.branch.repository.reconcile(thorough=True)
409
        tree.branch.repository.reconcile(thorough=True)