/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
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
63
            repo.texts.add_lines((root_id, revision_id), [], [])
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
64
        repo.add_inventory(revision_id, inv, parent_ids)
65
        revision = Revision(revision_id, committer='jrandom@example.com',
66
            timestamp=0, inventory_sha1='', timezone=0, message='foo',
67
            parent_ids=parent_ids)
68
        repo.add_revision(revision_id,revision, inv)
69
70
    def make_one_file_inventory(self, repo, revision, parents,
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
71
                                inv_revision=None, root_revision=None,
2927.2.4 by Andrew Bennetts
Don't create a 'rev3' file version in the test.
72
                                file_contents=None, make_file_version=True):
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
73
        """Make an inventory containing a version of a file with ID 'a-file'.
74
75
        The file's ID will be 'a-file', and its filename will be 'a file name',
76
        stored at the tree root.
77
78
        :param repo: a repository to add the new file version to.
79
        :param revision: the revision ID of the new inventory.
80
        :param parents: the parents for this revision of 'a-file'.
81
        :param inv_revision: if not None, the revision ID to store in the
82
            inventory entry.  Otherwise, this defaults to revision.
83
        :param root_revision: if not None, the inventory's root.revision will
84
            be set to this.
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
85
        :param file_contents: if not None, the contents of this file version.
86
            Otherwise a unique default (based on revision ID) will be
87
            generated.
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
88
        """
89
        inv = Inventory(revision_id=revision)
90
        if root_revision is not None:
91
            inv.root.revision = root_revision
92
        file_id = 'a-file-id'
93
        entry = InventoryFile(file_id, 'a file name', 'TREE_ROOT')
94
        if inv_revision is not None:
95
            entry.revision = inv_revision
96
        else:
97
            entry.revision = revision
98
        entry.text_size = 0
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
99
        if file_contents is None:
100
            file_contents = '%sline\n' % entry.revision
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
101
        entry.text_sha1 = sha.sha(file_contents).hexdigest()
102
        inv.add(entry)
2927.2.4 by Andrew Bennetts
Don't create a 'rev3' file version in the test.
103
        if make_file_version:
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
104
            repo.texts.add_lines((file_id, revision),
105
                [(file_id, parent) for parent in parents], [file_contents])
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
106
        return inv
107
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
108
    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.
109
        if not repo._reconcile_fixes_text_parents:
110
            raise TestNotApplicable(
111
                    "Format does not support text parent reconciliation")
112
113
    def file_parents(self, repo, revision_id):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
114
        key = ('a-file-id', revision_id)
115
        parent_map = repo.texts.get_parent_map([key])
116
        return tuple(parent[-1] for parent in parent_map[key])
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
117
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
118
    def assertFileVersionAbsent(self, repo, revision_id):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
119
        self.assertEqual({},
120
            repo.texts.get_parent_map([('a-file-id', revision_id)]))
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
121
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
122
    def assertParentsMatch(self, expected_parents_for_versions, repo,
123
                           when_description):
124
        for expected_parents, version in expected_parents_for_versions:
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
125
            if expected_parents is None:
126
                self.assertFileVersionAbsent(repo, version)
127
            else:
128
                found_parents = self.file_parents(repo, version)
129
                self.assertEqual(expected_parents, found_parents,
2927.2.7 by Andrew Bennetts
Condense assertion message.
130
                    "%s reconcile %s has parents %s, should have %s."
131
                    % (when_description, version, found_parents,
132
                       expected_parents))
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
133
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
134
    def prepare_test_repository(self):
135
        """Prepare a repository to test with from the test scenario.
136
137
        :return: A repository, and the scenario instance.
138
        """
139
        scenario = self.scenario_class(self)
140
        repo = self.make_populated_repository(scenario.populate_repository)
141
        self.require_repo_suffers_text_parent_corruption(repo)
142
        return repo, scenario
143
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
144
    def shas_for_versions_of_file(self, repo, versions):
145
        """Get the SHA-1 hashes of the versions of 'a-file' in the repository.
146
        
147
        :param repo: the repository to get the hashes from.
148
        :param versions: a list of versions to get hashes for.
149
150
        :returns: A dict of `{version: hash}`.
151
        """
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
152
        keys = [('a-file-id', version) for version in versions]
3350.8.3 by Robert Collins
VF.get_sha1s needed changing to be stackable.
153
        return repo.texts.get_sha1s(keys)
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
154
155
    def test_reconcile_behaviour(self):
156
        """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.
157
        and after.
158
        """
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
159
        repo, scenario = self.prepare_test_repository()
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
160
        repo.lock_read()
161
        try:
162
            self.assertParentsMatch(scenario.populated_parents(), repo,
163
                'before')
164
            vf_shas = self.shas_for_versions_of_file(
165
                repo, scenario.all_versions_after_reconcile())
166
        finally:
167
            repo.unlock()
2745.6.42 by Andrew Bennetts
Use TestScenarioApplier to more cleanly parameterise check and reconcile tests.
168
        result = repo.reconcile(thorough=True)
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
169
        repo.lock_read()
170
        try:
171
            self.assertParentsMatch(scenario.corrected_parents(), repo,
172
                'after')
173
            # The contents of the versions in the versionedfile should be the
174
            # same after the reconcile.
175
            self.assertEqual(
176
                vf_shas,
177
                self.shas_for_versions_of_file(
178
                    repo, scenario.all_versions_after_reconcile()))
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
179
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
180
            # Scenario.corrected_fulltexts contains texts which the test wants
181
            # to assert are now fulltexts. However this is an abstraction
182
            # violation; really we care that:
183
            # - the text is reconstructable
184
            # - it has an empty parents list
185
            # (we specify it this way because a store can use arbitrary
186
            # compression pointers in principle.
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
187
            for file_version in scenario.corrected_fulltexts():
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
188
                key = ('a-file-id', file_version)
189
                self.assertEqual({key:()}, repo.texts.get_parent_map([key]))
190
                self.assertIsInstance(
191
                    repo.texts.get_record_stream([key], 'unordered',
192
                        True).next().get_bytes_as('fulltext'),
193
                    str)
2951.1.4 by Robert Collins
Lock correctness for check/reconcile tests.
194
        finally:
195
            repo.unlock()
2927.2.3 by Andrew Bennetts
Add fulltexts to avoid bug 155730.
196
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
197
    def test_check_behaviour(self):
198
        """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.
199
        repo, scenario = self.prepare_test_repository()
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
200
        check_result = repo.check()
201
        check_result.report_results(verbose=True)
2951.1.6 by Robert Collins
All check/reconcile tests passing now.
202
        for pattern in scenario.check_regexes(repo):
2745.6.46 by Andrew Bennetts
Improvements to check/reconcile tests suggested by review.
203
            self.assertContainsRe(
204
                self._get_log(keep_log_file=True),
205
                pattern)
206
2988.1.2 by Robert Collins
New Repository API find_text_key_references for use by reconcile and check.
207
    def test_find_text_key_references(self):
208
        """Test that find_text_key_references finds erroneous references."""
209
        repo, scenario = self.prepare_test_repository()
210
        repo.lock_read()
211
        self.addCleanup(repo.unlock)
212
        self.assertEqual(scenario.repository_text_key_references(),
213
            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.
214
215
    def test__generate_text_key_index(self):
216
        """Test that the generated text key index has all entries."""
217
        repo, scenario = self.prepare_test_repository()
218
        repo.lock_read()
219
        self.addCleanup(repo.unlock)
220
        self.assertEqual(scenario.repository_text_key_index(),
221
            repo._generate_text_key_index())