/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
1
# Copyright (C) 2007 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
2745.6.44 by Andrew Bennetts
More docstring and formatting tweaks.
17
"""Tests that use BrokenRepoScenario objects.
18
19
That is, tests for reconcile and check.
20
"""
21
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
22
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
23
import sha
24
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
25
from bzrlib.inventory import Inventory, InventoryFile
26
from bzrlib.revision import Revision
27
from bzrlib.tests import TestNotApplicable
28
from bzrlib.tests.repository_implementations import TestCaseWithRepository
29
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
30
31
class TestFileParentReconciliation(TestCaseWithRepository):
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
32
    """Tests for how reconcile corrects errors in parents of file versions."""
33
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
34
    def make_populated_repository(self, factory):
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
35
        """Create a new repository populated by the given factory."""
36
        repo = self.make_repository('broken-repo')
37
        repo.lock_write()
38
        try:
39
            repo.start_write_group()
40
            try:
41
                factory(repo)
42
                repo.commit_write_group()
43
                return repo
44
            except:
45
                repo.abort_write_group()
46
                raise
47
        finally:
48
            repo.unlock()
49
50
    def add_revision(self, repo, revision_id, inv, parent_ids):
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
51
        """Add a revision with a given inventory and parents to a repository.
52
        
53
        :param repo: a repository.
54
        :param revision_id: the revision ID for the new revision.
55
        :param inv: an inventory (such as created by
56
            `make_one_file_inventory`).
57
        :param parent_ids: the parents for the new revision.
58
        """
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
59
        inv.revision_id = revision_id
60
        inv.root.revision = revision_id
2951.1.5 by Robert Collins
Some work towards including the correct changes for TREE_ROOT in check parameterised tests.
61
        if repo.supports_rich_root():
62
            root_id = inv.root.file_id
63
            vf = repo.weave_store.get_weave_or_empty(root_id,
64
                repo.get_transaction())
65
            vf.add_lines(revision_id, [], [])
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
66
        repo.add_inventory(revision_id, inv, parent_ids)
67
        revision = Revision(revision_id, committer='jrandom@example.com',
68
            timestamp=0, inventory_sha1='', timezone=0, message='foo',
69
            parent_ids=parent_ids)
70
        repo.add_revision(revision_id,revision, inv)
71
72
    def make_one_file_inventory(self, repo, revision, parents,
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
73
                                inv_revision=None, root_revision=None,
2927.2.4 by Andrew Bennetts
Don't create a 'rev3' file version in the test.
74
                                file_contents=None, make_file_version=True):
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
75
        """Make an inventory containing a version of a file with ID 'a-file'.
76
77
        The file's ID will be 'a-file', and its filename will be 'a file name',
78
        stored at the tree root.
79
80
        :param repo: a repository to add the new file version to.
81
        :param revision: the revision ID of the new inventory.
82
        :param parents: the parents for this revision of 'a-file'.
83
        :param inv_revision: if not None, the revision ID to store in the
84
            inventory entry.  Otherwise, this defaults to revision.
85
        :param root_revision: if not None, the inventory's root.revision will
86
            be set to this.
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
87
        :param file_contents: if not None, the contents of this file version.
88
            Otherwise a unique default (based on revision ID) will be
89
            generated.
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
90
        """
91
        inv = Inventory(revision_id=revision)
92
        if root_revision is not None:
93
            inv.root.revision = root_revision
94
        file_id = 'a-file-id'
95
        entry = InventoryFile(file_id, 'a file name', 'TREE_ROOT')
96
        if inv_revision is not None:
97
            entry.revision = inv_revision
98
        else:
99
            entry.revision = revision
100
        entry.text_size = 0
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
101
        if file_contents is None:
102
            file_contents = '%sline\n' % entry.revision
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
103
        entry.text_sha1 = sha.sha(file_contents).hexdigest()
104
        inv.add(entry)
2927.2.4 by Andrew Bennetts
Don't create a 'rev3' file version in the test.
105
        if make_file_version:
106
            vf = repo.weave_store.get_weave_or_empty(file_id,
107
                                                     repo.get_transaction())
108
            vf.add_lines(revision, parents, [file_contents])
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
109
        return inv
110
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
111
    def require_repo_suffers_text_parent_corruption(self, repo):
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
112
        if not repo._reconcile_fixes_text_parents:
113
            raise TestNotApplicable(
114
                    "Format does not support text parent reconciliation")
115
116
    def file_parents(self, repo, revision_id):
3287.5.2 by Robert Collins
Deprecate VersionedFile.get_parents, breaking pulling from a ghost containing knit or pack repository to weaves, which improves correctness and allows simplification of core code.
117
        return repo.weave_store.get_weave('a-file-id',
118
            repo.get_transaction()).get_parent_map([revision_id])[revision_id]
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
119
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
120
    def assertFileVersionAbsent(self, repo, revision_id):
121
        self.assertFalse(repo.weave_store.get_weave('a-file-id',
122
            repo.get_transaction()).has_version(revision_id),
123
            'File version %s wrongly present.' % (revision_id,))
124
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
125
    def assertParentsMatch(self, expected_parents_for_versions, repo,
126
                           when_description):
127
        for expected_parents, version in expected_parents_for_versions:
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
128
            if expected_parents is None:
129
                self.assertFileVersionAbsent(repo, version)
130
            else:
131
                found_parents = self.file_parents(repo, version)
132
                self.assertEqual(expected_parents, found_parents,
2927.2.7 by Andrew Bennetts
Condense assertion message.
133
                    "%s reconcile %s has parents %s, should have %s."
134
                    % (when_description, version, found_parents,
135
                       expected_parents))
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
136
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
137
    def prepare_test_repository(self):
138
        """Prepare a repository to test with from the test scenario.
139
140
        :return: A repository, and the scenario instance.
141
        """
142
        scenario = self.scenario_class(self)
143
        repo = self.make_populated_repository(scenario.populate_repository)
144
        self.require_repo_suffers_text_parent_corruption(repo)
145
        return repo, scenario
146
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
147
    def shas_for_versions_of_file(self, repo, versions):
148
        """Get the SHA-1 hashes of the versions of 'a-file' in the repository.
149
        
150
        :param repo: the repository to get the hashes from.
151
        :param versions: a list of versions to get hashes for.
152
153
        :returns: A dict of `{version: hash}`.
154
        """
155
        vf = repo.weave_store.get_weave('a-file-id', repo.get_transaction())
3316.2.9 by Robert Collins
* ``VersionedFile.get_sha1`` is deprecated, please use
156
        return dict(zip(versions, vf.get_sha1s(versions)))
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
157
158
    def test_reconcile_behaviour(self):
159
        """Populate a repository and reconcile it, verifying the state before
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
160
        and after.
161
        """
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
162
        repo, scenario = self.prepare_test_repository()
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
163
        repo.lock_read()
164
        try:
165
            self.assertParentsMatch(scenario.populated_parents(), repo,
166
                'before')
167
            vf_shas = self.shas_for_versions_of_file(
168
                repo, scenario.all_versions_after_reconcile())
169
        finally:
170
            repo.unlock()
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
171
        result = repo.reconcile(thorough=True)
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
172
        repo.lock_read()
173
        try:
174
            self.assertParentsMatch(scenario.corrected_parents(), repo,
175
                'after')
176
            # The contents of the versions in the versionedfile should be the
177
            # same after the reconcile.
178
            self.assertEqual(
179
                vf_shas,
180
                self.shas_for_versions_of_file(
181
                    repo, scenario.all_versions_after_reconcile()))
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
182
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
183
            for file_version in scenario.corrected_fulltexts():
184
                vf = repo.weave_store.get_weave(
185
                    'a-file-id', repo.get_transaction())
186
                self.assertEqual('fulltext',
187
                    vf._index.get_method(file_version),
188
                    '%r should be fulltext' % (file_version,))
189
        finally:
190
            repo.unlock()
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
191
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
192
    def test_check_behaviour(self):
193
        """Populate a repository and check it, and verify the output."""
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
194
        repo, scenario = self.prepare_test_repository()
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
195
        check_result = repo.check()
196
        check_result.report_results(verbose=True)
2951.1.6 by Robert Collins
All check/reconcile tests passing now.
197
        for pattern in scenario.check_regexes(repo):
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
198
            self.assertContainsRe(
199
                self._get_log(keep_log_file=True),
200
                pattern)
201
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
202
    def test_find_text_key_references(self):
203
        """Test that find_text_key_references finds erroneous references."""
204
        repo, scenario = self.prepare_test_repository()
205
        repo.lock_read()
206
        self.addCleanup(repo.unlock)
207
        self.assertEqual(scenario.repository_text_key_references(),
208
            repo.find_text_key_references())
2988.1.3 by Robert Collins
Add a new repositoy method _generate_text_key_index for use by reconcile/check.
209
210
    def test__generate_text_key_index(self):
211
        """Test that the generated text key index has all entries."""
212
        repo, scenario = self.prepare_test_repository()
213
        repo.lock_read()
214
        self.addCleanup(repo.unlock)
215
        self.assertEqual(scenario.repository_text_key_index(),
216
            repo._generate_text_key_index())