~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/repository_implementations/test_reconcile.py

 * New 'reconcile' command will check branch consistency and repair indexes
   that can become out of sync in pre 0.8 formats. (Robert Collins,
   Aaron Bentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006 by Canonical Ltd
 
2
 
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
 
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
 
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Tests for reconiliation of repositories."""
 
18
 
 
19
 
 
20
import bzrlib
 
21
import bzrlib.errors as errors
 
22
from bzrlib.reconcile import reconcile, Reconciler, RepoReconciler
 
23
from bzrlib.revision import Revision
 
24
from bzrlib.tests.repository_implementations.test_repository import TestCaseWithRepository
 
25
from bzrlib.transport import get_transport
 
26
from bzrlib.tree import EmptyTree
 
27
from bzrlib.workingtree import WorkingTree
 
28
 
 
29
 
 
30
class TestsNeedingReweave(TestCaseWithRepository):
 
31
 
 
32
    def setUp(self):
 
33
        super(TestsNeedingReweave, self).setUp()
 
34
        
 
35
        t = get_transport(self.get_url())
 
36
        # an empty inventory with no revision for testing with.
 
37
        # this is referenced by 'references_missing' to let us test
 
38
        # that all the cached data is correctly converted into ghost links
 
39
        # and the referenced inventory still cleaned.
 
40
        repo = self.make_repository('inventory_without_revision')
 
41
        inv = EmptyTree().inventory
 
42
        repo.add_inventory('missing', inv, [])
 
43
        sha1 = repo.add_inventory('references_missing', inv, ['missing'])
 
44
        rev = Revision(timestamp=0,
 
45
                       timezone=None,
 
46
                       committer="Foo Bar <foo@example.com>",
 
47
                       message="Message",
 
48
                       inventory_sha1=sha1,
 
49
                       revision_id='references_missing')
 
50
        rev.parent_ids = ['missing']
 
51
        repo.add_revision('references_missing', rev)
 
52
 
 
53
        # a inventory with no parents and the revision has parents..
 
54
        # i.e. a ghost.
 
55
        repo = self.make_repository('inventory_one_ghost')
 
56
        sha1 = repo.add_inventory('ghost', inv, [])
 
57
        rev = Revision(timestamp=0,
 
58
                       timezone=None,
 
59
                       committer="Foo Bar <foo@example.com>",
 
60
                       message="Message",
 
61
                       inventory_sha1=sha1,
 
62
                       revision_id='ghost')
 
63
        rev.parent_ids = ['the_ghost']
 
64
        repo.add_revision('ghost', rev)
 
65
         
 
66
        # a inventory with a ghost that can be corrected now.
 
67
        t.copy_tree('inventory_one_ghost', 'inventory_ghost_present')
 
68
        repo = bzrlib.repository.Repository.open('inventory_ghost_present')
 
69
        sha1 = repo.add_inventory('the_ghost', inv, [])
 
70
        rev = Revision(timestamp=0,
 
71
                       timezone=None,
 
72
                       committer="Foo Bar <foo@example.com>",
 
73
                       message="Message",
 
74
                       inventory_sha1=sha1,
 
75
                       revision_id='the_ghost')
 
76
        rev.parent_ids = []
 
77
        repo.add_revision('the_ghost', rev)
 
78
 
 
79
    def test_reweave_empty(self):
 
80
        self.make_repository('empty')
 
81
        d = bzrlib.bzrdir.BzrDir.open('empty')
 
82
        # calling on a empty repository should do nothing
 
83
        reconciler = RepoReconciler(d.find_repository())
 
84
        reconciler.reconcile()
 
85
        # no inconsistent parents should have been found
 
86
        self.assertEqual(0, reconciler.inconsistent_parents)
 
87
        # and no garbage inventories
 
88
        self.assertEqual(0, reconciler.garbage_inventories)
 
89
        # and no backup weave should have been needed/made.
 
90
        repo = d.open_repository()
 
91
        self.assertRaises(errors.NoSuchFile,
 
92
                          repo.control_weaves.get_weave,
 
93
                          'inventory.backup',
 
94
                          repo.get_transaction())
 
95
 
 
96
    def test_reweave_inventory_without_revision_reconcile(self):
 
97
        # smoke test for the all in one ui tool
 
98
        d = bzrlib.bzrdir.BzrDir.open('inventory_without_revision')
 
99
        reconcile(d)
 
100
        # now the backup should have it but not the current inventory
 
101
        repo = d.open_repository()
 
102
        backup = repo.control_weaves.get_weave('inventory.backup',
 
103
                                               repo.get_transaction())
 
104
        self.assertTrue('missing' in backup.names())
 
105
        self.assertRaises(errors.WeaveRevisionNotPresent,
 
106
                          repo.get_inventory, 'missing')
 
107
 
 
108
    def test_reweave_inventory_without_revision_reconciler(self):
 
109
        # smoke test for the all in one Reconciler class,
 
110
        # other tests use the lower level RepoReconciler.
 
111
        d = bzrlib.bzrdir.BzrDir.open('inventory_without_revision')
 
112
        reconciler = Reconciler(d)
 
113
        reconciler.reconcile()
 
114
        # no inconsistent parents should have been found
 
115
        self.assertEqual(1, reconciler.inconsistent_parents)
 
116
        # and one garbage inventories
 
117
        self.assertEqual(1, reconciler.garbage_inventories)
 
118
        # now the backup should have it but not the current inventory
 
119
        repo = d.open_repository()
 
120
        backup = repo.control_weaves.get_weave('inventory.backup',
 
121
                                               repo.get_transaction())
 
122
        self.assertTrue('missing' in backup.names())
 
123
        self.assertRaises(errors.WeaveRevisionNotPresent,
 
124
                          repo.get_inventory, 'missing')
 
125
 
 
126
    def test_reweave_inventory_without_revision(self):
 
127
        # actual low level test.
 
128
        d = bzrlib.bzrdir.BzrDir.open('inventory_without_revision')
 
129
        reconciler = RepoReconciler(d.open_repository())
 
130
        reconciler.reconcile()
 
131
        # no inconsistent parents should have been found
 
132
        self.assertEqual(1, reconciler.inconsistent_parents)
 
133
        # and one garbage inventories
 
134
        self.assertEqual(1, reconciler.garbage_inventories)
 
135
        # now the backup should have it but not the current inventory
 
136
        repo = d.open_repository()
 
137
        backup = repo.control_weaves.get_weave('inventory.backup',
 
138
                                               repo.get_transaction())
 
139
        self.assertTrue('missing' in backup.names())
 
140
        self.assertRaises(errors.WeaveRevisionNotPresent,
 
141
                          repo.get_inventory, 'missing')
 
142
        # and the parent list for 'references_missing' should have that
 
143
        # revision a ghost now.
 
144
        self.assertEqual([None, 'references_missing'],
 
145
                         repo.get_ancestry('references_missing'))
 
146
 
 
147
    def test_reweave_inventory_preserves_a_revision_with_ghosts(self):
 
148
        d = bzrlib.bzrdir.BzrDir.open('inventory_one_ghost')
 
149
        reconciler = RepoReconciler(d.open_repository())
 
150
        reconciler.reconcile()
 
151
        # no inconsistent parents should have been found: 
 
152
        # the lack of a parent for ghost is normal
 
153
        self.assertEqual(0, reconciler.inconsistent_parents)
 
154
        # and one garbage inventories
 
155
        self.assertEqual(0, reconciler.garbage_inventories)
 
156
        # now the current inventory should still have 'ghost'
 
157
        repo = d.open_repository()
 
158
        repo.get_inventory('ghost')
 
159
        self.assertEqual([None, 'ghost'], repo.get_ancestry('ghost'))
 
160
        
 
161
    def test_reweave_inventory_fixes_ancestryfor_a_present_ghost(self):
 
162
        d = bzrlib.bzrdir.BzrDir.open('inventory_ghost_present')
 
163
        repo = d.open_repository()
 
164
        self.assertEqual([None, 'ghost'], repo.get_ancestry('ghost'))
 
165
        reconciler = RepoReconciler(repo)
 
166
        reconciler.reconcile()
 
167
        # one inconsistent parents should have been found : the
 
168
        # available but not reference parent for ghost.
 
169
        self.assertEqual(1, reconciler.inconsistent_parents)
 
170
        # and no garbage inventories
 
171
        self.assertEqual(0, reconciler.garbage_inventories)
 
172
        # now the current inventory should still have 'ghost'
 
173
        repo = d.open_repository()
 
174
        repo.get_inventory('ghost')
 
175
        repo.get_inventory('the_ghost')
 
176
        self.assertEqual([None, 'the_ghost', 'ghost'], repo.get_ancestry('ghost'))
 
177
        self.assertEqual([None, 'the_ghost'], repo.get_ancestry('the_ghost'))