/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5590.1.1 by John Arbash Meinel
Stop using tuned_gzip, it seems to give incorrect results on python 2.7
1
# Copyright (C) 2006-2011 Canonical Ltd
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
16
17
"""Tests for Knit data structure"""
18
5590.1.1 by John Arbash Meinel
Stop using tuned_gzip, it seems to give incorrect results on python 2.7
19
import gzip
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
20
from io import BytesIO
2484.1.17 by John Arbash Meinel
Workaround for Pyrex <0.9.5 and python >=2.5 incompatibilities.
21
import sys
1563.2.4 by Robert Collins
First cut at including the knit implementation of versioned_file.
22
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
23
from .. import (
2196.2.5 by John Arbash Meinel
Add an exception class when the knit index storage method is unknown, and properly test for it
24
    errors,
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
25
    multiparent,
3734.2.4 by Vincent Ladeuil
Fix python2.6 deprecation warnings related to hashlib.
26
    osutils,
4913.2.24 by John Arbash Meinel
Track down a few more import typos.
27
    tests,
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
28
    transport,
2196.2.5 by John Arbash Meinel
Add an exception class when the knit index storage method is unknown, and properly test for it
29
    )
6670.4.1 by Jelmer Vernooij
Update imports.
30
from ..bzr import (
31
    knit,
32
    pack,
33
    )
34
from ..bzr.index import *
35
from ..bzr.knit import (
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
36
    AnnotatedKnitContent,
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
37
    KnitContent,
6729.7.2 by Jelmer Vernooij
Finish move.
38
    KnitCorrupt,
39
    KnitDataStreamIncompatible,
40
    KnitDataStreamUnknown,
6729.7.1 by Jelmer Vernooij
Move some knit errors.
41
    KnitHeaderError,
6729.7.2 by Jelmer Vernooij
Finish move.
42
    KnitIndexUnknownMethod,
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.
43
    KnitVersionedFiles,
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
44
    PlainKnitContent,
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
45
    _VFContentMapGenerator,
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.
46
    _KndxIndex,
47
    _KnitGraphIndex,
48
    _KnitKeyAccess,
49
    make_file_factory,
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
50
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
51
from ..patiencediff import PatienceSequenceMatcher
6670.4.5 by Jelmer Vernooij
Move breezy.repofmt contents to breezy.bzr.
52
from ..bzr import (
5757.8.11 by Jelmer Vernooij
Merge knitpackrepo-6.
53
    knitpack_repo,
54
    pack_repo,
55
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
56
from . import (
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
57
    TestCase,
58
    TestCaseWithMemoryTransport,
59
    TestCaseWithTransport,
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
60
    TestNotApplicable,
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
61
    )
6670.4.1 by Jelmer Vernooij
Update imports.
62
from ..bzr.versionedfile import (
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
63
    AbsentContentFactory,
3350.8.2 by Robert Collins
stacked get_parent_map.
64
    ConstantMapper,
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
65
    network_bytes_to_kind_and_offset,
3350.8.2 by Robert Collins
stacked get_parent_map.
66
    RecordingVersionedFilesDecorator,
67
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
68
from . import (
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
69
    features,
70
    )
71
72
73
compiled_knit_feature = features.ModuleAvailableFeature(
6670.4.1 by Jelmer Vernooij
Update imports.
74
    'breezy.bzr._knit_load_data_pyx')
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
75
76
6729.7.2 by Jelmer Vernooij
Finish move.
77
class ErrorTests(TestCase):
78
79
    def test_knit_data_stream_incompatible(self):
80
        error = KnitDataStreamIncompatible(
81
            'stream format', 'target format')
82
        self.assertEqual('Cannot insert knit data stream of format '
83
                         '"stream format" into knit of format '
84
                         '"target format".', str(error))
85
86
    def test_knit_data_stream_unknown(self):
87
        error = KnitDataStreamUnknown(
88
            'stream format')
89
        self.assertEqual('Cannot parse knit data stream of format '
90
                         '"stream format".', str(error))
91
92
    def test_knit_header_error(self):
93
        error = KnitHeaderError('line foo\n', 'path/to/file')
94
        self.assertEqual("Knit header error: 'line foo\\n' unexpected"
95
                         " for file \"path/to/file\".", str(error))
96
97
    def test_knit_index_unknown_method(self):
98
        error = KnitIndexUnknownMethod('http://host/foo.kndx',
99
                                       ['bad', 'no-eol'])
100
        self.assertEqual("Knit index http://host/foo.kndx does not have a"
101
                         " known method in options: ['bad', 'no-eol']",
102
                         str(error))
103
104
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
105
class KnitContentTestsMixin(object):
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
106
107
    def test_constructor(self):
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
108
        content = self._make_content([])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
109
110
    def test_text(self):
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
111
        content = self._make_content([])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
112
        self.assertEqual(content.text(), [])
113
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
114
        content = self._make_content([(b"origin1", b"text1"), (b"origin2", b"text2")])
115
        self.assertEqual(content.text(), [b"text1", b"text2"])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
116
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
117
    def test_copy(self):
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
118
        content = self._make_content([(b"origin1", b"text1"), (b"origin2", b"text2")])
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
119
        copy = content.copy()
120
        self.assertIsInstance(copy, content.__class__)
121
        self.assertEqual(copy.annotate(), content.annotate())
122
123
    def assertDerivedBlocksEqual(self, source, target, noeol=False):
124
        """Assert that the derived matching blocks match real output"""
125
        source_lines = source.splitlines(True)
126
        target_lines = target.splitlines(True)
127
        def nl(line):
128
            if noeol and not line.endswith('\n'):
129
                return line + '\n'
130
            else:
131
                return line
132
        source_content = self._make_content([(None, nl(l)) for l in source_lines])
133
        target_content = self._make_content([(None, nl(l)) for l in target_lines])
134
        line_delta = source_content.line_delta(target_content)
135
        delta_blocks = list(KnitContent.get_line_delta_blocks(line_delta,
136
            source_lines, target_lines))
5279.1.1 by Andrew Bennetts
lazy_import most things in merge.py; add a few representative modules to the import tariff tests; tweak a couple of other modules so that patiencediff is not necessarily imported; remove a bunch of unused imports from test_knit.py.
137
        matcher = PatienceSequenceMatcher(None, source_lines, target_lines)
138
        matcher_blocks = list(matcher.get_matching_blocks())
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
139
        self.assertEqual(matcher_blocks, delta_blocks)
140
141
    def test_get_line_delta_blocks(self):
142
        self.assertDerivedBlocksEqual('a\nb\nc\n', 'q\nc\n')
143
        self.assertDerivedBlocksEqual(TEXT_1, TEXT_1)
144
        self.assertDerivedBlocksEqual(TEXT_1, TEXT_1A)
145
        self.assertDerivedBlocksEqual(TEXT_1, TEXT_1B)
146
        self.assertDerivedBlocksEqual(TEXT_1B, TEXT_1A)
147
        self.assertDerivedBlocksEqual(TEXT_1A, TEXT_1B)
148
        self.assertDerivedBlocksEqual(TEXT_1A, '')
149
        self.assertDerivedBlocksEqual('', TEXT_1A)
150
        self.assertDerivedBlocksEqual('', '')
151
        self.assertDerivedBlocksEqual('a\nb\nc', 'a\nb\nc\nd')
152
153
    def test_get_line_delta_blocks_noeol(self):
154
        """Handle historical knit deltas safely
155
156
        Some existing knit deltas don't consider the last line to differ
157
        when the only difference whether it has a final newline.
158
159
        New knit deltas appear to always consider the last line to differ
160
        in this case.
161
        """
162
        self.assertDerivedBlocksEqual('a\nb\nc', 'a\nb\nc\nd\n', noeol=True)
163
        self.assertDerivedBlocksEqual('a\nb\nc\nd\n', 'a\nb\nc', noeol=True)
164
        self.assertDerivedBlocksEqual('a\nb\nc\n', 'a\nb\nc', noeol=True)
165
        self.assertDerivedBlocksEqual('a\nb\nc', 'a\nb\nc\n', noeol=True)
166
167
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.
168
TEXT_1 = """\
169
Banana cup cakes:
170
171
- bananas
172
- eggs
173
- broken tea cups
174
"""
175
176
TEXT_1A = """\
177
Banana cup cake recipe
178
(serves 6)
179
180
- bananas
181
- eggs
182
- broken tea cups
183
- self-raising flour
184
"""
185
186
TEXT_1B = """\
187
Banana cup cake recipe
188
189
- bananas (do not use plantains!!!)
190
- broken tea cups
191
- flour
192
"""
193
194
delta_1_1a = """\
195
0,1,2
196
Banana cup cake recipe
197
(serves 6)
198
5,5,1
199
- self-raising flour
200
"""
201
202
TEXT_2 = """\
203
Boeuf bourguignon
204
205
- beef
206
- red wine
207
- small onions
208
- carrot
209
- mushrooms
210
"""
211
212
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
213
class TestPlainKnitContent(TestCase, KnitContentTestsMixin):
214
215
    def _make_content(self, lines):
216
        annotated_content = AnnotatedKnitContent(lines)
217
        return PlainKnitContent(annotated_content.text(), 'bogus')
218
219
    def test_annotate(self):
220
        content = self._make_content([])
221
        self.assertEqual(content.annotate(), [])
222
223
        content = self._make_content([("origin1", "text1"), ("origin2", "text2")])
224
        self.assertEqual(content.annotate(),
225
            [("bogus", "text1"), ("bogus", "text2")])
226
227
    def test_line_delta(self):
228
        content1 = self._make_content([("", "a"), ("", "b")])
229
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
230
        self.assertEqual(content1.line_delta(content2),
231
            [(1, 2, 2, ["a", "c"])])
232
233
    def test_line_delta_iter(self):
234
        content1 = self._make_content([("", "a"), ("", "b")])
235
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
236
        it = content1.line_delta_iter(content2)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
237
        self.assertEqual(next(it), (1, 2, 2, ["a", "c"]))
238
        self.assertRaises(StopIteration, next, it)
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
239
240
241
class TestAnnotatedKnitContent(TestCase, KnitContentTestsMixin):
242
243
    def _make_content(self, lines):
244
        return AnnotatedKnitContent(lines)
245
246
    def test_annotate(self):
247
        content = self._make_content([])
248
        self.assertEqual(content.annotate(), [])
249
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
250
        content = self._make_content([(b"origin1", b"text1"), (b"origin2", b"text2")])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
251
        self.assertEqual(content.annotate(),
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
252
            [(b"origin1", b"text1"), (b"origin2", b"text2")])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
253
254
    def test_line_delta(self):
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
255
        content1 = self._make_content([("", "a"), ("", "b")])
256
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
257
        self.assertEqual(content1.line_delta(content2),
258
            [(1, 2, 2, [("", "a"), ("", "c")])])
259
260
    def test_line_delta_iter(self):
2794.1.2 by Robert Collins
Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.
261
        content1 = self._make_content([("", "a"), ("", "b")])
262
        content2 = self._make_content([("", "a"), ("", "a"), ("", "c")])
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
263
        it = content1.line_delta_iter(content2)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
264
        self.assertEqual(next(it), (1, 2, 2, [("", "a"), ("", "c")]))
265
        self.assertRaises(StopIteration, next, it)
2151.1.1 by John Arbash Meinel
(Dmitry Vasiliev) Tune KnitContent and add tests
266
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
267
268
class MockTransport(object):
269
270
    def __init__(self, file_lines=None):
271
        self.file_lines = file_lines
272
        self.calls = []
2196.2.3 by John Arbash Meinel
Update tests and code to pass after merging bzr.dev
273
        # We have no base directory for the MockTransport
274
        self.base = ''
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
275
276
    def get(self, filename):
277
        if self.file_lines is None:
6729.7.2 by Jelmer Vernooij
Finish move.
278
            raise errors.NoSuchFile(filename)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
279
        else:
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
280
            return BytesIO(b"\n".join(self.file_lines))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
281
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
282
    def readv(self, relpath, offsets):
283
        fp = self.get(relpath)
284
        for offset, size in offsets:
285
            fp.seek(offset)
286
            yield offset, fp.read(size)
287
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
288
    def __getattr__(self, name):
289
        def queue_call(*args, **kwargs):
290
            self.calls.append((name, args, kwargs))
291
        return queue_call
292
293
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
294
class MockReadvFailingTransport(MockTransport):
295
    """Fail in the middle of a readv() result.
296
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
297
    This Transport will successfully yield the first two requested hunks, but
298
    raise NoSuchFile for the rest.
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
299
    """
300
301
    def readv(self, relpath, offsets):
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
302
        count = 0
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
303
        for result in MockTransport.readv(self, relpath, offsets):
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
304
            count += 1
305
            # we use 2 because the first offset is the pack header, the second
306
            # is the first actual content requset
307
            if count > 2:
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
308
                raise errors.NoSuchFile(relpath)
309
            yield result
310
311
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
312
class KnitRecordAccessTestsMixin(object):
313
    """Tests for getting and putting knit records."""
314
315
    def test_add_raw_records(self):
316
        """Add_raw_records adds records retrievable later."""
317
        access = self.get_access()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
318
        memos = access.add_raw_records([(b'key', 10)], b'1234567890')
319
        self.assertEqual([b'1234567890'], list(access.get_raw_records(memos)))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
320
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
321
    def test_add_several_raw_records(self):
322
        """add_raw_records with many records and read some back."""
323
        access = self.get_access()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
324
        memos = access.add_raw_records([(b'key', 10), (b'key2', 2), (b'key3', 5)],
325
            b'12345678901234567')
326
        self.assertEqual([b'1234567890', b'12', b'34567'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
327
            list(access.get_raw_records(memos)))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
328
        self.assertEqual([b'1234567890'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
329
            list(access.get_raw_records(memos[0:1])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
330
        self.assertEqual([b'12'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
331
            list(access.get_raw_records(memos[1:2])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
332
        self.assertEqual([b'34567'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
333
            list(access.get_raw_records(memos[2:3])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
334
        self.assertEqual([b'1234567890', b'34567'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
335
            list(access.get_raw_records(memos[0:1] + memos[2:3])))
336
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
337
338
class TestKnitKnitAccess(TestCaseWithMemoryTransport, KnitRecordAccessTestsMixin):
339
    """Tests for the .kndx implementation."""
340
341
    def get_access(self):
342
        """Get a .knit style access instance."""
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.
343
        mapper = ConstantMapper("foo")
344
        access = _KnitKeyAccess(self.get_transport(), mapper)
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
345
        return access
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
346
347
348
class _TestException(Exception):
349
    """Just an exception for local tests to use."""
350
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
351
352
class TestPackKnitAccess(TestCaseWithMemoryTransport, KnitRecordAccessTestsMixin):
353
    """Tests for the pack based access."""
354
355
    def get_access(self):
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
356
        return self._get_access()[0]
357
358
    def _get_access(self, packname='packfile', index='FOO'):
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
359
        transport = self.get_transport()
360
        def write_data(bytes):
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
361
            transport.append_bytes(packname, bytes)
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
362
        writer = pack.ContainerWriter(write_data)
363
        writer.begin()
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
364
        access = pack_repo._DirectPackAccess({})
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.
365
        access.set_writer(writer, index, (transport, packname))
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
366
        return access, writer
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
367
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
368
    def make_pack_file(self):
369
        """Create a pack file with 2 records."""
370
        access, writer = self._get_access(packname='packname', index='foo')
371
        memos = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
372
        memos.extend(access.add_raw_records([(b'key1', 10)], b'1234567890'))
373
        memos.extend(access.add_raw_records([(b'key2', 5)], b'12345'))
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
374
        writer.end()
375
        return memos
376
5050.64.1 by Andrew Bennetts
Add reload-and-retry logic to RepositoryPackCollection.pack when a concurrent pack happens.
377
    def test_pack_collection_pack_retries(self):
378
        """An explicit pack of a pack collection succeeds even when a
379
        concurrent pack happens.
380
        """
381
        builder = self.make_branch_builder('.')
382
        builder.start_series()
6816.2.1 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
383
        builder.build_snapshot(None, [
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
384
            ('add', ('', b'root-id', 'directory', None)),
385
            ('add', ('file', b'file-id', 'file', b'content\nrev 1\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
386
            ], revision_id=b'rev-1')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
387
        builder.build_snapshot([b'rev-1'], [
388
            ('modify', ('file', b'content\nrev 2\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
389
            ], revision_id=b'rev-2')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
390
        builder.build_snapshot([b'rev-2'], [
391
            ('modify', ('file', b'content\nrev 3\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
392
            ], revision_id=b'rev-3')
5050.64.1 by Andrew Bennetts
Add reload-and-retry logic to RepositoryPackCollection.pack when a concurrent pack happens.
393
        self.addCleanup(builder.finish_series)
394
        b = builder.get_branch()
395
        self.addCleanup(b.lock_write().unlock)
396
        repo = b.repository
397
        collection = repo._pack_collection
398
        # Concurrently repack the repo.
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
399
        reopened_repo = repo.controldir.open_repository()
5050.64.1 by Andrew Bennetts
Add reload-and-retry logic to RepositoryPackCollection.pack when a concurrent pack happens.
400
        reopened_repo.pack()
401
        # Pack the new pack.
402
        collection.pack()
403
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
404
    def make_vf_for_retrying(self):
3789.2.10 by John Arbash Meinel
The first function for KnitVersionedFiles can now retry on request.
405
        """Create 3 packs and a reload function.
406
407
        Originally, 2 pack files will have the data, but one will be missing.
408
        And then the third will be used in place of the first two if reload()
409
        is called.
410
411
        :return: (versioned_file, reload_counter)
412
            versioned_file  a KnitVersionedFiles using the packs for access
413
        """
4617.7.1 by Robert Collins
Lock the format knit retry tests depend on - knits aren't used for 2a formats.
414
        builder = self.make_branch_builder('.', format="1.9")
4454.3.59 by John Arbash Meinel
Track down why the annotate retry code was failing.
415
        builder.start_series()
6816.2.1 by Jelmer Vernooij
Migrate some build_snapshot code over to having revision_id as keyword argument.
416
        builder.build_snapshot(None, [
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
417
            ('add', ('', b'root-id', 'directory', None)),
418
            ('add', ('file', b'file-id', 'file', b'content\nrev 1\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
419
            ], revision_id=b'rev-1')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
420
        builder.build_snapshot([b'rev-1'], [
421
            ('modify', ('file', b'content\nrev 2\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
422
            ], revision_id=b'rev-2')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
423
        builder.build_snapshot([b'rev-2'], [
424
            ('modify', ('file', b'content\nrev 3\n')),
6973.5.2 by Jelmer Vernooij
Add more bees.
425
            ], revision_id=b'rev-3')
4454.3.59 by John Arbash Meinel
Track down why the annotate retry code was failing.
426
        builder.finish_series()
427
        b = builder.get_branch()
428
        b.lock_write()
429
        self.addCleanup(b.unlock)
4145.1.6 by Robert Collins
More test fallout, but all caught now.
430
        # Pack these three revisions into another pack file, but don't remove
431
        # the originals
4454.3.59 by John Arbash Meinel
Track down why the annotate retry code was failing.
432
        repo = b.repository
4145.1.6 by Robert Collins
More test fallout, but all caught now.
433
        collection = repo._pack_collection
434
        collection.ensure_loaded()
435
        orig_packs = collection.packs
5757.7.3 by Jelmer Vernooij
Move more knitpack-specific functionality out of Packer.
436
        packer = knitpack_repo.KnitPacker(collection, orig_packs, '.testpack')
4145.1.6 by Robert Collins
More test fallout, but all caught now.
437
        new_pack = packer.pack()
438
        # forget about the new pack
439
        collection.reset()
440
        repo.refresh_data()
4454.3.59 by John Arbash Meinel
Track down why the annotate retry code was failing.
441
        vf = repo.revisions
3789.2.10 by John Arbash Meinel
The first function for KnitVersionedFiles can now retry on request.
442
        # Set up a reload() function that switches to using the new pack file
443
        new_index = new_pack.revision_index
444
        access_tuple = new_pack.access_tuple()
445
        reload_counter = [0, 0, 0]
446
        def reload():
447
            reload_counter[0] += 1
448
            if reload_counter[1] > 0:
449
                # We already reloaded, nothing more to do
450
                reload_counter[2] += 1
451
                return False
452
            reload_counter[1] += 1
453
            vf._index._graph_index._indices[:] = [new_index]
454
            vf._access._indices.clear()
455
            vf._access._indices[new_index] = access_tuple
456
            return True
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
457
        # Delete one of the pack files so the data will need to be reloaded. We
3789.2.12 by John Arbash Meinel
iter_lines_added_or_present now retries.
458
        # will delete the file with 'rev-2' in it
3789.2.10 by John Arbash Meinel
The first function for KnitVersionedFiles can now retry on request.
459
        trans, name = orig_packs[1].access_tuple()
460
        trans.delete(name)
461
        # We don't have the index trigger reloading because we want to test
462
        # that we reload when the .pack disappears
463
        vf._access._reload_func = reload
464
        return vf, reload_counter
465
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
466
    def make_reload_func(self, return_val=True):
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
467
        reload_called = [0]
468
        def reload():
469
            reload_called[0] += 1
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
470
            return return_val
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
471
        return reload_called, reload
472
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
473
    def make_retry_exception(self):
474
        # We raise a real exception so that sys.exc_info() is properly
475
        # populated
476
        try:
477
            raise _TestException('foobar')
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
478
        except _TestException as e:
3789.2.29 by John Arbash Meinel
RetryWithNewPacks requires another argument.
479
            retry_exc = errors.RetryWithNewPacks(None, reload_occurred=False,
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
480
                                                 exc_info=sys.exc_info())
5340.15.2 by John Arbash Meinel
supercede 2.4-613247-cleanup-tests
481
        # GZ 2010-08-10: Cycle with exc_info affects 3 tests
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
482
        return retry_exc
483
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
484
    def test_read_from_several_packs(self):
485
        access, writer = self._get_access()
486
        memos = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
487
        memos.extend(access.add_raw_records([(b'key', 10)], b'1234567890'))
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
488
        writer.end()
489
        access, writer = self._get_access('pack2', 'FOOBAR')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
490
        memos.extend(access.add_raw_records([(b'key', 5)], b'12345'))
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
491
        writer.end()
492
        access, writer = self._get_access('pack3', 'BAZ')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
493
        memos.extend(access.add_raw_records([(b'key', 5)], b'alpha'))
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
494
        writer.end()
495
        transport = self.get_transport()
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
496
        access = pack_repo._DirectPackAccess({"FOO":(transport, 'packfile'),
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
497
            "FOOBAR":(transport, 'pack2'),
498
            "BAZ":(transport, 'pack3')})
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
499
        self.assertEqual([b'1234567890', b'12345', b'alpha'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
500
            list(access.get_raw_records(memos)))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
501
        self.assertEqual([b'1234567890'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
502
            list(access.get_raw_records(memos[0:1])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
503
        self.assertEqual([b'12345'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
504
            list(access.get_raw_records(memos[1:2])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
505
        self.assertEqual([b'alpha'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
506
            list(access.get_raw_records(memos[2:3])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
507
        self.assertEqual([b'1234567890', b'alpha'],
2592.3.67 by Robert Collins
More tests for bzrlib.knit._PackAccess.
508
            list(access.get_raw_records(memos[0:1] + memos[2:3])))
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
509
2592.3.70 by Robert Collins
Allow setting a writer after creating a knit._PackAccess object.
510
    def test_set_writer(self):
511
        """The writer should be settable post construction."""
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
512
        access = pack_repo._DirectPackAccess({})
2592.3.70 by Robert Collins
Allow setting a writer after creating a knit._PackAccess object.
513
        transport = self.get_transport()
514
        packname = 'packfile'
515
        index = 'foo'
516
        def write_data(bytes):
517
            transport.append_bytes(packname, bytes)
518
        writer = pack.ContainerWriter(write_data)
519
        writer.begin()
520
        access.set_writer(writer, index, (transport, packname))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
521
        memos = access.add_raw_records([(b'key', 10)], b'1234567890')
2592.3.70 by Robert Collins
Allow setting a writer after creating a knit._PackAccess object.
522
        writer.end()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
523
        self.assertEqual([b'1234567890'], list(access.get_raw_records(memos)))
2592.3.70 by Robert Collins
Allow setting a writer after creating a knit._PackAccess object.
524
3789.2.1 by John Arbash Meinel
_DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.
525
    def test_missing_index_raises_retry(self):
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
526
        memos = self.make_pack_file()
3789.2.1 by John Arbash Meinel
_DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.
527
        transport = self.get_transport()
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
528
        reload_called, reload_func = self.make_reload_func()
529
        # Note that the index key has changed from 'foo' to 'bar'
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
530
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')},
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
531
                                   reload_func=reload_func)
3789.2.1 by John Arbash Meinel
_DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.
532
        e = self.assertListRaises(errors.RetryWithNewPacks,
533
                                  access.get_raw_records, memos)
534
        # Because a key was passed in which does not match our index list, we
535
        # assume that the listing was already reloaded
536
        self.assertTrue(e.reload_occurred)
537
        self.assertIsInstance(e.exc_info, tuple)
538
        self.assertIs(e.exc_info[0], KeyError)
539
        self.assertIsInstance(e.exc_info[1], KeyError)
540
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
541
    def test_missing_index_raises_key_error_with_no_reload(self):
542
        memos = self.make_pack_file()
543
        transport = self.get_transport()
544
        # Note that the index key has changed from 'foo' to 'bar'
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
545
        access = pack_repo._DirectPackAccess({'bar':(transport, 'packname')})
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
546
        e = self.assertListRaises(KeyError, access.get_raw_records, memos)
547
3789.2.1 by John Arbash Meinel
_DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.
548
    def test_missing_file_raises_retry(self):
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
549
        memos = self.make_pack_file()
550
        transport = self.get_transport()
551
        reload_called, reload_func = self.make_reload_func()
552
        # Note that the 'filename' has been changed to 'different-packname'
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
553
        access = pack_repo._DirectPackAccess(
5757.8.1 by Jelmer Vernooij
Avoid bzrlib.knit imports when using groupcompress repositories.
554
            {'foo':(transport, 'different-packname')},
555
            reload_func=reload_func)
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
556
        e = self.assertListRaises(errors.RetryWithNewPacks,
557
                                  access.get_raw_records, memos)
558
        # The file has gone missing, so we assume we need to reload
559
        self.assertFalse(e.reload_occurred)
560
        self.assertIsInstance(e.exc_info, tuple)
561
        self.assertIs(e.exc_info[0], errors.NoSuchFile)
562
        self.assertIsInstance(e.exc_info[1], errors.NoSuchFile)
563
        self.assertEqual('different-packname', e.exc_info[1].path)
564
565
    def test_missing_file_raises_no_such_file_with_no_reload(self):
566
        memos = self.make_pack_file()
567
        transport = self.get_transport()
568
        # Note that the 'filename' has been changed to 'different-packname'
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
569
        access = pack_repo._DirectPackAccess(
5757.5.2 by Jelmer Vernooij
merge bzr.dev.
570
            {'foo': (transport, 'different-packname')})
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
571
        e = self.assertListRaises(errors.NoSuchFile,
3789.2.1 by John Arbash Meinel
_DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.
572
                                  access.get_raw_records, memos)
573
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
574
    def test_failing_readv_raises_retry(self):
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
575
        memos = self.make_pack_file()
576
        transport = self.get_transport()
577
        failing_transport = MockReadvFailingTransport(
578
                                [transport.get_bytes('packname')])
579
        reload_called, reload_func = self.make_reload_func()
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
580
        access = pack_repo._DirectPackAccess(
5757.5.2 by Jelmer Vernooij
merge bzr.dev.
581
            {'foo': (failing_transport, 'packname')},
5757.8.1 by Jelmer Vernooij
Avoid bzrlib.knit imports when using groupcompress repositories.
582
            reload_func=reload_func)
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
583
        # Asking for a single record will not trigger the Mock failure
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
584
        self.assertEqual([b'1234567890'],
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
585
            list(access.get_raw_records(memos[:1])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
586
        self.assertEqual([b'12345'],
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
587
            list(access.get_raw_records(memos[1:2])))
588
        # A multiple offset readv() will fail mid-way through
589
        e = self.assertListRaises(errors.RetryWithNewPacks,
590
                                  access.get_raw_records, memos)
591
        # The file has gone missing, so we assume we need to reload
592
        self.assertFalse(e.reload_occurred)
593
        self.assertIsInstance(e.exc_info, tuple)
594
        self.assertIs(e.exc_info[0], errors.NoSuchFile)
595
        self.assertIsInstance(e.exc_info[1], errors.NoSuchFile)
596
        self.assertEqual('packname', e.exc_info[1].path)
597
598
    def test_failing_readv_raises_no_such_file_with_no_reload(self):
599
        memos = self.make_pack_file()
600
        transport = self.get_transport()
601
        failing_transport = MockReadvFailingTransport(
602
                                [transport.get_bytes('packname')])
603
        reload_called, reload_func = self.make_reload_func()
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
604
        access = pack_repo._DirectPackAccess(
5757.8.1 by Jelmer Vernooij
Avoid bzrlib.knit imports when using groupcompress repositories.
605
            {'foo':(failing_transport, 'packname')})
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
606
        # Asking for a single record will not trigger the Mock failure
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
607
        self.assertEqual([b'1234567890'],
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
608
            list(access.get_raw_records(memos[:1])))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
609
        self.assertEqual([b'12345'],
3789.2.3 by John Arbash Meinel
Change the mocking a bit, so we can be sure it is failing at the right time.
610
            list(access.get_raw_records(memos[1:2])))
611
        # A multiple offset readv() will fail mid-way through
3789.2.5 by John Arbash Meinel
Change _DirectPackAccess to only raise Retry when _reload_func is defined.
612
        e = self.assertListRaises(errors.NoSuchFile,
3789.2.2 by John Arbash Meinel
Test that a readv() failing after yielding data will still raise Retry
613
                                  access.get_raw_records, memos)
614
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
615
    def test_reload_or_raise_no_reload(self):
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
616
        access = pack_repo._DirectPackAccess({}, reload_func=None)
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
617
        retry_exc = self.make_retry_exception()
618
        # Without a reload_func, we will just re-raise the original exception
619
        self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
620
621
    def test_reload_or_raise_reload_changed(self):
622
        reload_called, reload_func = self.make_reload_func(return_val=True)
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
623
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
624
        retry_exc = self.make_retry_exception()
625
        access.reload_or_raise(retry_exc)
626
        self.assertEqual([1], reload_called)
627
        retry_exc.reload_occurred=True
628
        access.reload_or_raise(retry_exc)
629
        self.assertEqual([2], reload_called)
630
631
    def test_reload_or_raise_reload_no_change(self):
632
        reload_called, reload_func = self.make_reload_func(return_val=False)
5757.5.1 by Jelmer Vernooij
Move _DirectPackAccess to bzrlib.repofmt.pack_repo.
633
        access = pack_repo._DirectPackAccess({}, reload_func=reload_func)
3789.2.6 by John Arbash Meinel
Make _DirectPackAccess.reload_or_raise maintain the logic.
634
        retry_exc = self.make_retry_exception()
635
        # If reload_occurred is False, then we consider it an error to have
636
        # reload_func() return False (no changes).
637
        self.assertRaises(_TestException, access.reload_or_raise, retry_exc)
638
        self.assertEqual([1], reload_called)
639
        retry_exc.reload_occurred=True
640
        # If reload_occurred is True, then we assume nothing changed because
641
        # it had changed earlier, but didn't change again
642
        access.reload_or_raise(retry_exc)
643
        self.assertEqual([2], reload_called)
644
3789.2.13 by John Arbash Meinel
KnitVersionedFile.annotate() now retries when appropriate.
645
    def test_annotate_retries(self):
646
        vf, reload_counter = self.make_vf_for_retrying()
647
        # It is a little bit bogus to annotate the Revision VF, but it works,
648
        # as we have ancestry stored there
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
649
        key = (b'rev-3',)
3789.2.13 by John Arbash Meinel
KnitVersionedFile.annotate() now retries when appropriate.
650
        reload_lines = vf.annotate(key)
651
        self.assertEqual([1, 1, 0], reload_counter)
652
        plain_lines = vf.annotate(key)
653
        self.assertEqual([1, 1, 0], reload_counter) # No extra reloading
654
        if reload_lines != plain_lines:
655
            self.fail('Annotation was not identical with reloading.')
656
        # Now delete the packs-in-use, which should trigger another reload, but
657
        # this time we just raise an exception because we can't recover
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
658
        for trans, name in vf._access._indices.values():
3789.2.13 by John Arbash Meinel
KnitVersionedFile.annotate() now retries when appropriate.
659
            trans.delete(name)
660
        self.assertRaises(errors.NoSuchFile, vf.annotate, key)
661
        self.assertEqual([2, 1, 1], reload_counter)
662
3789.2.10 by John Arbash Meinel
The first function for KnitVersionedFiles can now retry on request.
663
    def test__get_record_map_retries(self):
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
664
        vf, reload_counter = self.make_vf_for_retrying()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
665
        keys = [(b'rev-1',), (b'rev-2',), (b'rev-3',)]
3789.2.10 by John Arbash Meinel
The first function for KnitVersionedFiles can now retry on request.
666
        records = vf._get_record_map(keys)
667
        self.assertEqual(keys, sorted(records.keys()))
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
668
        self.assertEqual([1, 1, 0], reload_counter)
669
        # Now delete the packs-in-use, which should trigger another reload, but
670
        # this time we just raise an exception because we can't recover
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
671
        for trans, name in vf._access._indices.values():
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
672
            trans.delete(name)
673
        self.assertRaises(errors.NoSuchFile, vf._get_record_map, keys)
674
        self.assertEqual([2, 1, 1], reload_counter)
675
676
    def test_get_record_stream_retries(self):
677
        vf, reload_counter = self.make_vf_for_retrying()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
678
        keys = [(b'rev-1',), (b'rev-2',), (b'rev-3',)]
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
679
        record_stream = vf.get_record_stream(keys, 'topological', False)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
680
        record = next(record_stream)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
681
        self.assertEqual((b'rev-1',), record.key)
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
682
        self.assertEqual([0, 0, 0], reload_counter)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
683
        record = next(record_stream)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
684
        self.assertEqual((b'rev-2',), record.key)
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
685
        self.assertEqual([1, 1, 0], reload_counter)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
686
        record = next(record_stream)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
687
        self.assertEqual((b'rev-3',), record.key)
3789.2.12 by John Arbash Meinel
iter_lines_added_or_present now retries.
688
        self.assertEqual([1, 1, 0], reload_counter)
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
689
        # Now delete all pack files, and see that we raise the right error
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
690
        for trans, name in vf._access._indices.values():
3789.2.11 by John Arbash Meinel
KnitVersionedFile.get_record_stream now retries *and* fails correctly.
691
            trans.delete(name)
692
        self.assertListRaises(errors.NoSuchFile,
693
            vf.get_record_stream, keys, 'topological', False)
694
3789.2.12 by John Arbash Meinel
iter_lines_added_or_present now retries.
695
    def test_iter_lines_added_or_present_in_keys_retries(self):
696
        vf, reload_counter = self.make_vf_for_retrying()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
697
        keys = [(b'rev-1',), (b'rev-2',), (b'rev-3',)]
3789.2.12 by John Arbash Meinel
iter_lines_added_or_present now retries.
698
        # Unfortunately, iter_lines_added_or_present_in_keys iterates the
699
        # result in random order (determined by the iteration order from a
700
        # set()), so we don't have any solid way to trigger whether data is
701
        # read before or after. However we tried to delete the middle node to
702
        # exercise the code well.
703
        # What we care about is that all lines are always yielded, but not
704
        # duplicated
705
        count = 0
706
        reload_lines = sorted(vf.iter_lines_added_or_present_in_keys(keys))
707
        self.assertEqual([1, 1, 0], reload_counter)
708
        # Now do it again, to make sure the result is equivalent
709
        plain_lines = sorted(vf.iter_lines_added_or_present_in_keys(keys))
710
        self.assertEqual([1, 1, 0], reload_counter) # No extra reloading
711
        self.assertEqual(plain_lines, reload_lines)
712
        self.assertEqual(21, len(plain_lines))
713
        # Now delete all pack files, and see that we raise the right error
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
714
        for trans, name in vf._access._indices.values():
3789.2.12 by John Arbash Meinel
iter_lines_added_or_present now retries.
715
            trans.delete(name)
716
        self.assertListRaises(errors.NoSuchFile,
717
            vf.iter_lines_added_or_present_in_keys, keys)
718
        self.assertEqual([2, 1, 1], reload_counter)
719
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
720
    def test_get_record_stream_yields_disk_sorted_order(self):
721
        # if we get 'unordered' pick a semi-optimal order for reading. The
722
        # order should be grouped by pack file, and then by position in file
723
        repo = self.make_repository('test', format='pack-0.92')
724
        repo.lock_write()
725
        self.addCleanup(repo.unlock)
726
        repo.start_write_group()
727
        vf = repo.texts
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
728
        vf.add_lines((b'f-id', b'rev-5'), [(b'f-id', b'rev-4')], [b'lines\n'])
729
        vf.add_lines((b'f-id', b'rev-1'), [], [b'lines\n'])
730
        vf.add_lines((b'f-id', b'rev-2'), [(b'f-id', b'rev-1')], [b'lines\n'])
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
731
        repo.commit_write_group()
732
        # We inserted them as rev-5, rev-1, rev-2, we should get them back in
733
        # the same order
6973.13.2 by Jelmer Vernooij
Fix some more tests.
734
        stream = vf.get_record_stream([(b'f-id', b'rev-1'), (b'f-id', b'rev-5'),
735
                                       (b'f-id', b'rev-2')], 'unordered', False)
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
736
        keys = [r.key for r in stream]
6973.13.2 by Jelmer Vernooij
Fix some more tests.
737
        self.assertEqual([(b'f-id', b'rev-5'), (b'f-id', b'rev-1'),
738
                          (b'f-id', b'rev-2')], keys)
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
739
        repo.start_write_group()
6973.13.2 by Jelmer Vernooij
Fix some more tests.
740
        vf.add_lines((b'f-id', b'rev-4'), [(b'f-id', b'rev-3')], [b'lines\n'])
741
        vf.add_lines((b'f-id', b'rev-3'), [(b'f-id', b'rev-2')], [b'lines\n'])
742
        vf.add_lines((b'f-id', b'rev-6'), [(b'f-id', b'rev-5')], [b'lines\n'])
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
743
        repo.commit_write_group()
744
        # Request in random order, to make sure the output order isn't based on
745
        # the request
6973.13.2 by Jelmer Vernooij
Fix some more tests.
746
        request_keys = set((b'f-id', b'rev-%d' % i) for i in range(1, 7))
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
747
        stream = vf.get_record_stream(request_keys, 'unordered', False)
748
        keys = [r.key for r in stream]
749
        # We want to get the keys back in disk order, but it doesn't matter
750
        # which pack we read from first. So this can come back in 2 orders
6973.13.2 by Jelmer Vernooij
Fix some more tests.
751
        alt1 = [(b'f-id', b'rev-%d' % i) for i in [4, 3, 6, 5, 1, 2]]
752
        alt2 = [(b'f-id', b'rev-%d' % i) for i in [5, 1, 2, 4, 3, 6]]
3878.1.1 by John Arbash Meinel
KVF.get_record_stream('unordered') now returns the records based on I/O ordering.
753
        if keys != alt1 and keys != alt2:
754
            self.fail('Returned key order did not match either expected order.'
755
                      ' expected %s or %s, not %s'
756
                      % (alt1, alt2, keys))
757
2592.3.66 by Robert Collins
Allow adaption of KnitData to pack files.
758
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
759
class LowLevelKnitDataTests(TestCase):
760
761
    def create_gz_content(self, text):
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
762
        sio = BytesIO()
6973.14.6 by Jelmer Vernooij
Fix some more tests.
763
        with gzip.GzipFile(mode='wb', fileobj=sio) as gz_file:
764
            gz_file.write(text)
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
765
        return sio.getvalue()
766
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
767
    def make_multiple_records(self):
768
        """Create the content for multiple records."""
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
769
        sha1sum = osutils.sha_string(b'foo\nbar\n')
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
770
        total_txt = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
771
        gz_txt = self.create_gz_content(b'version rev-id-1 2 %s\n'
772
                                        b'foo\n'
773
                                        b'bar\n'
774
                                        b'end rev-id-1\n'
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
775
                                        % (sha1sum,))
776
        record_1 = (0, len(gz_txt), sha1sum)
777
        total_txt.append(gz_txt)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
778
        sha1sum = osutils.sha_string(b'baz\n')
779
        gz_txt = self.create_gz_content(b'version rev-id-2 1 %s\n'
780
                                        b'baz\n'
781
                                        b'end rev-id-2\n'
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
782
                                        % (sha1sum,))
783
        record_2 = (record_1[1], len(gz_txt), sha1sum)
784
        total_txt.append(gz_txt)
785
        return total_txt, record_1, record_2
786
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
787
    def test_valid_knit_data(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
788
        sha1sum = osutils.sha_string(b'foo\nbar\n')
789
        gz_txt = self.create_gz_content(b'version rev-id-1 2 %s\n'
790
                                        b'foo\n'
791
                                        b'bar\n'
792
                                        b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
793
                                        % (sha1sum,))
794
        transport = MockTransport([gz_txt])
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.
795
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
796
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
797
        records = [((b'rev-id-1',), ((b'rev-id-1',), 0, len(gz_txt)))]
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.
798
799
        contents = list(knit._read_records_iter(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
800
        self.assertEqual([((b'rev-id-1',), [b'foo\n', b'bar\n'],
801
            b'4e48e2c9a3d2ca8a708cb0cc545700544efb5021')], contents)
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.
802
803
        raw_contents = list(knit._read_records_iter_raw(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
804
        self.assertEqual([((b'rev-id-1',), gz_txt, sha1sum)], raw_contents)
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
805
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
806
    def test_multiple_records_valid(self):
807
        total_txt, record_1, record_2 = self.make_multiple_records()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
808
        transport = MockTransport([b''.join(total_txt)])
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
809
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
810
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
811
        records = [((b'rev-id-1',), ((b'rev-id-1',), record_1[0], record_1[1])),
812
                   ((b'rev-id-2',), ((b'rev-id-2',), record_2[0], record_2[1]))]
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
813
814
        contents = list(knit._read_records_iter(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
815
        self.assertEqual([((b'rev-id-1',), [b'foo\n', b'bar\n'], record_1[2]),
816
                          ((b'rev-id-2',), [b'baz\n'], record_2[2])],
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
817
                         contents)
818
819
        raw_contents = list(knit._read_records_iter_raw(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
820
        self.assertEqual([((b'rev-id-1',), total_txt[0], record_1[2]),
821
                          ((b'rev-id-2',), total_txt[1], record_2[2])],
3789.2.4 by John Arbash Meinel
Add a multiple-record test, though it isn't quite what we want for the readv tests.
822
                         raw_contents)
823
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
824
    def test_not_enough_lines(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
825
        sha1sum = osutils.sha_string(b'foo\n')
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
826
        # record says 2 lines data says 1
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
827
        gz_txt = self.create_gz_content(b'version rev-id-1 2 %s\n'
828
                                        b'foo\n'
829
                                        b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
830
                                        % (sha1sum,))
831
        transport = MockTransport([gz_txt])
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.
832
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
833
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
834
        records = [((b'rev-id-1',), ((b'rev-id-1',), 0, len(gz_txt)))]
6729.7.2 by Jelmer Vernooij
Finish move.
835
        self.assertRaises(KnitCorrupt, list,
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.
836
            knit._read_records_iter(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
837
838
        # read_records_iter_raw won't detect that sort of mismatch/corruption
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.
839
        raw_contents = list(knit._read_records_iter_raw(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
840
        self.assertEqual([((b'rev-id-1',),  gz_txt, sha1sum)], raw_contents)
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
841
842
    def test_too_many_lines(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
843
        sha1sum = osutils.sha_string(b'foo\nbar\n')
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
844
        # record says 1 lines data says 2
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
845
        gz_txt = self.create_gz_content(b'version rev-id-1 1 %s\n'
846
                                        b'foo\n'
847
                                        b'bar\n'
848
                                        b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
849
                                        % (sha1sum,))
850
        transport = MockTransport([gz_txt])
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.
851
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
852
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
853
        records = [((b'rev-id-1',), ((b'rev-id-1',), 0, len(gz_txt)))]
6729.7.2 by Jelmer Vernooij
Finish move.
854
        self.assertRaises(KnitCorrupt, list,
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.
855
            knit._read_records_iter(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
856
857
        # read_records_iter_raw won't detect that sort of mismatch/corruption
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.
858
        raw_contents = list(knit._read_records_iter_raw(records))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
859
        self.assertEqual([((b'rev-id-1',), gz_txt, sha1sum)], raw_contents)
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
860
861
    def test_mismatched_version_id(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
862
        sha1sum = osutils.sha_string(b'foo\nbar\n')
863
        gz_txt = self.create_gz_content(b'version rev-id-1 2 %s\n'
864
                                        b'foo\n'
865
                                        b'bar\n'
866
                                        b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
867
                                        % (sha1sum,))
868
        transport = MockTransport([gz_txt])
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.
869
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
870
        knit = KnitVersionedFiles(None, access)
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
871
        # We are asking for rev-id-2, but the data is rev-id-1
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
872
        records = [((b'rev-id-2',), ((b'rev-id-2',), 0, len(gz_txt)))]
6729.7.2 by Jelmer Vernooij
Finish move.
873
        self.assertRaises(KnitCorrupt, list,
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.
874
            knit._read_records_iter(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
875
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.
876
        # read_records_iter_raw detects mismatches in the header
6729.7.2 by Jelmer Vernooij
Finish move.
877
        self.assertRaises(KnitCorrupt, list,
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.
878
            knit._read_records_iter_raw(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
879
880
    def test_uncompressed_data(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
881
        sha1sum = osutils.sha_string(b'foo\nbar\n')
882
        txt = (b'version rev-id-1 2 %s\n'
883
               b'foo\n'
884
               b'bar\n'
885
               b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
886
               % (sha1sum,))
887
        transport = MockTransport([txt])
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.
888
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
889
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
890
        records = [((b'rev-id-1',), ((b'rev-id-1',), 0, len(txt)))]
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
891
892
        # We don't have valid gzip data ==> corrupt
6729.7.2 by Jelmer Vernooij
Finish move.
893
        self.assertRaises(KnitCorrupt, list,
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.
894
            knit._read_records_iter(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
895
896
        # read_records_iter_raw will notice the bad data
6729.7.2 by Jelmer Vernooij
Finish move.
897
        self.assertRaises(KnitCorrupt, list,
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.
898
            knit._read_records_iter_raw(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
899
900
    def test_corrupted_data(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
901
        sha1sum = osutils.sha_string(b'foo\nbar\n')
902
        gz_txt = self.create_gz_content(b'version rev-id-1 2 %s\n'
903
                                        b'foo\n'
904
                                        b'bar\n'
905
                                        b'end rev-id-1\n'
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
906
                                        % (sha1sum,))
907
        # Change 2 bytes in the middle to \xff
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
908
        gz_txt = gz_txt[:10] + b'\xff\xff' + gz_txt[12:]
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
909
        transport = MockTransport([gz_txt])
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.
910
        access = _KnitKeyAccess(transport, ConstantMapper('filename'))
911
        knit = KnitVersionedFiles(None, access)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
912
        records = [((b'rev-id-1',), ((b'rev-id-1',), 0, len(gz_txt)))]
6729.7.2 by Jelmer Vernooij
Finish move.
913
        self.assertRaises(KnitCorrupt, list,
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.
914
            knit._read_records_iter(records))
915
        # read_records_iter_raw will barf on bad gz data
6729.7.2 by Jelmer Vernooij
Finish move.
916
        self.assertRaises(KnitCorrupt, list,
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.
917
            knit._read_records_iter_raw(records))
2329.1.1 by John Arbash Meinel
Update _KnitData parser to raise more helpful errors when it detects corruption.
918
919
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
920
class LowLevelKnitIndexTests(TestCase):
921
7027.1.2 by Martin
Fixup low level knit tests for Python 3
922
    @property
923
    def _load_data(self):
6670.4.3 by Jelmer Vernooij
Fix more imports.
924
        from ..bzr._knit_load_data_py import _load_data_py
7027.1.2 by Martin
Fixup low level knit tests for Python 3
925
        return _load_data_py
926
927
    def get_knit_index(self, transport, name, mode):
928
        mapper = ConstantMapper(name)
929
        self.overrideAttr(knit, '_load_data', self._load_data)
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.
930
        allow_writes = lambda: 'w' in mode
7027.1.2 by Martin
Fixup low level knit tests for Python 3
931
        return _KndxIndex(transport, mapper, lambda: None, allow_writes, lambda: True)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
932
933
    def test_create_file(self):
934
        transport = MockTransport()
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.
935
        index = self.get_knit_index(transport, "filename", "w")
936
        index.keys()
937
        call = transport.calls.pop(0)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
938
        # call[1][1] is a BytesIO - we can't test it by simple equality.
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.
939
        self.assertEqual('put_file_non_atomic', call[0])
940
        self.assertEqual('filename.kndx', call[1][0])
941
        # With no history, _KndxIndex writes a new index:
942
        self.assertEqual(_KndxIndex.HEADER,
943
            call[1][1].getvalue())
944
        self.assertEqual({'create_parent_dir': True}, call[2])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
945
946
    def test_read_utf8_version_id(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
947
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
948
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
949
        transport = MockTransport([
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.
950
            _KndxIndex.HEADER,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
951
            b'%s option 0 1 :' % (utf8_revision_id,)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
952
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
953
        index = self.get_knit_index(transport, "filename", "r")
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.
954
        # _KndxIndex is a private class, and deals in utf8 revision_ids, not
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
955
        # Unicode revision_ids.
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.
956
        self.assertEqual({(utf8_revision_id,):()},
957
            index.get_parent_map(index.keys()))
958
        self.assertFalse((unicode_revision_id,) in index.keys())
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
959
960
    def test_read_utf8_parents(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
961
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
962
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
963
        transport = MockTransport([
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.
964
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
965
            b"version option 0 1 .%s :" % (utf8_revision_id,)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
966
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
967
        index = self.get_knit_index(transport, "filename", "r")
7027.1.2 by Martin
Fixup low level knit tests for Python 3
968
        self.assertEqual({(b"version",): ((utf8_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.
969
            index.get_parent_map(index.keys()))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
970
971
    def test_read_ignore_corrupted_lines(self):
972
        transport = MockTransport([
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.
973
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
974
            b"corrupted",
975
            b"corrupted options 0 1 .b .c ",
976
            b"version options 0 1 :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
977
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
978
        index = self.get_knit_index(transport, "filename", "r")
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.
979
        self.assertEqual(1, len(index.keys()))
7027.1.2 by Martin
Fixup low level knit tests for Python 3
980
        self.assertEqual({(b"version",)}, index.keys())
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
981
982
    def test_read_corrupted_header(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
983
        transport = MockTransport([b'not a bzr knit index header\n'])
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.
984
        index = self.get_knit_index(transport, "filename", "r")
985
        self.assertRaises(KnitHeaderError, index.keys)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
986
987
    def test_read_duplicate_entries(self):
988
        transport = MockTransport([
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.
989
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
990
            b"parent options 0 1 :",
991
            b"version options1 0 1 0 :",
992
            b"version options2 1 2 .other :",
993
            b"version options3 3 4 0 .other :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
994
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
995
        index = self.get_knit_index(transport, "filename", "r")
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.
996
        self.assertEqual(2, len(index.keys()))
2592.3.8 by Robert Collins
Remove unneeded pulib method lookup on private class _KnitIndex.
997
        # check that the index used is the first one written. (Specific
998
        # to KnitIndex style indices.
7027.1.2 by Martin
Fixup low level knit tests for Python 3
999
        self.assertEqual(b"1", index._dictionary_compress([(b"version",)]))
1000
        self.assertEqual(((b"version",), 3, 4), index.get_position((b"version",)))
1001
        self.assertEqual([b"options3"], index.get_options((b"version",)))
1002
        self.assertEqual({(b"version",): ((b"parent",), (b"other",))},
1003
            index.get_parent_map([(b"version",)]))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1004
1005
    def test_read_compressed_parents(self):
1006
        transport = MockTransport([
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.
1007
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1008
            b"a option 0 1 :",
1009
            b"b option 0 1 0 :",
1010
            b"c option 0 1 1 0 :",
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1011
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1012
        index = self.get_knit_index(transport, "filename", "r")
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1013
        self.assertEqual({(b"b",):((b"a",),), (b"c",):((b"b",), (b"a",))},
1014
            index.get_parent_map([(b"b",), (b"c",)]))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1015
1016
    def test_write_utf8_version_id(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
1017
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
1018
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1019
        transport = MockTransport([
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.
1020
            _KndxIndex.HEADER
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1021
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1022
        index = self.get_knit_index(transport, "filename", "r")
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.
1023
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1024
            ((utf8_revision_id,), [b"option"], ((utf8_revision_id,), 0, 1), [])])
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.
1025
        call = transport.calls.pop(0)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
1026
        # call[1][1] is a BytesIO - we can't test it by simple equality.
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.
1027
        self.assertEqual('put_file_non_atomic', call[0])
1028
        self.assertEqual('filename.kndx', call[1][0])
1029
        # With no history, _KndxIndex writes a new index:
1030
        self.assertEqual(_KndxIndex.HEADER +
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1031
            b"\n%s option 0 1  :" % (utf8_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.
1032
            call[1][1].getvalue())
1033
        self.assertEqual({'create_parent_dir': True}, call[2])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1034
1035
    def test_write_utf8_parents(self):
2249.5.12 by John Arbash Meinel
Change the APIs for VersionedFile, Store, and some of Repository into utf-8
1036
        unicode_revision_id = u"version-\N{CYRILLIC CAPITAL LETTER A}"
1037
        utf8_revision_id = unicode_revision_id.encode('utf-8')
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1038
        transport = MockTransport([
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.
1039
            _KndxIndex.HEADER
1040
            ])
1041
        index = self.get_knit_index(transport, "filename", "r")
1042
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1043
            ((b"version",), [b"option"], ((b"version",), 0, 1), [(utf8_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.
1044
        call = transport.calls.pop(0)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
1045
        # call[1][1] is a BytesIO - we can't test it by simple equality.
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.
1046
        self.assertEqual('put_file_non_atomic', call[0])
1047
        self.assertEqual('filename.kndx', call[1][0])
1048
        # With no history, _KndxIndex writes a new index:
1049
        self.assertEqual(_KndxIndex.HEADER +
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1050
            b"\nversion option 0 1 .%s :" % (utf8_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.
1051
            call[1][1].getvalue())
1052
        self.assertEqual({'create_parent_dir': True}, call[2])
1053
1054
    def test_keys(self):
1055
        transport = MockTransport([
1056
            _KndxIndex.HEADER
1057
            ])
1058
        index = self.get_knit_index(transport, "filename", "r")
1059
1060
        self.assertEqual(set(), index.keys())
1061
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1062
        index.add_records([((b"a",), [b"option"], ((b"a",), 0, 1), [])])
1063
        self.assertEqual({(b"a",)}, index.keys())
1064
1065
        index.add_records([((b"a",), [b"option"], ((b"a",), 0, 1), [])])
1066
        self.assertEqual({(b"a",)}, index.keys())
1067
1068
        index.add_records([((b"b",), [b"option"], ((b"b",), 0, 1), [])])
1069
        self.assertEqual({(b"a",), (b"b",)}, index.keys())
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.
1070
1071
    def add_a_b(self, index, random_id=None):
1072
        kwargs = {}
1073
        if random_id is not None:
1074
            kwargs["random_id"] = random_id
1075
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1076
            ((b"a",), [b"option"], ((b"a",), 0, 1), [(b"b",)]),
1077
            ((b"a",), [b"opt"], ((b"a",), 1, 2), [(b"c",)]),
1078
            ((b"b",), [b"option"], ((b"b",), 2, 3), [(b"a",)])
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.
1079
            ], **kwargs)
1080
1081
    def assertIndexIsAB(self, index):
1082
        self.assertEqual({
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1083
            (b'a',): ((b'c',),),
1084
            (b'b',): ((b'a',),),
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.
1085
            },
1086
            index.get_parent_map(index.keys()))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1087
        self.assertEqual(((b"a",), 1, 2), index.get_position((b"a",)))
1088
        self.assertEqual(((b"b",), 2, 3), index.get_position((b"b",)))
1089
        self.assertEqual([b"opt"], index.get_options((b"a",)))
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.
1090
1091
    def test_add_versions(self):
1092
        transport = MockTransport([
1093
            _KndxIndex.HEADER
1094
            ])
1095
        index = self.get_knit_index(transport, "filename", "r")
1096
1097
        self.add_a_b(index)
1098
        call = transport.calls.pop(0)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
1099
        # call[1][1] is a BytesIO - we can't test it by simple equality.
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.
1100
        self.assertEqual('put_file_non_atomic', call[0])
1101
        self.assertEqual('filename.kndx', call[1][0])
1102
        # With no history, _KndxIndex writes a new index:
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1103
        self.assertEqual(
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.
1104
            _KndxIndex.HEADER +
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1105
            b"\na option 0 1 .b :"
1106
            b"\na opt 1 2 .c :"
1107
            b"\nb option 2 3 0 :",
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.
1108
            call[1][1].getvalue())
1109
        self.assertEqual({'create_parent_dir': True}, call[2])
1110
        self.assertIndexIsAB(index)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1111
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
1112
    def test_add_versions_random_id_is_accepted(self):
1113
        transport = MockTransport([
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.
1114
            _KndxIndex.HEADER
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
1115
            ])
1116
        index = self.get_knit_index(transport, "filename", "r")
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.
1117
        self.add_a_b(index, random_id=True)
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
1118
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1119
    def test_delay_create_and_add_versions(self):
1120
        transport = MockTransport()
1121
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.
1122
        index = self.get_knit_index(transport, "filename", "w")
1123
        # dir_mode=0777)
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1124
        self.assertEqual([], transport.calls)
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.
1125
        self.add_a_b(index)
1126
        #self.assertEqual(
1127
        #[    {"dir_mode": 0777, "create_parent_dir": True, "mode": "wb"},
1128
        #    kwargs)
1129
        # Two calls: one during which we load the existing index (and when its
1130
        # missing create it), then a second where we write the contents out.
1131
        self.assertEqual(2, len(transport.calls))
1132
        call = transport.calls.pop(0)
1133
        self.assertEqual('put_file_non_atomic', call[0])
1134
        self.assertEqual('filename.kndx', call[1][0])
1135
        # With no history, _KndxIndex writes a new index:
1136
        self.assertEqual(_KndxIndex.HEADER, call[1][1].getvalue())
1137
        self.assertEqual({'create_parent_dir': True}, call[2])
1138
        call = transport.calls.pop(0)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
1139
        # call[1][1] is a BytesIO - we can't test it by simple equality.
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.
1140
        self.assertEqual('put_file_non_atomic', call[0])
1141
        self.assertEqual('filename.kndx', call[1][0])
1142
        # With no history, _KndxIndex writes a new index:
1143
        self.assertEqual(
1144
            _KndxIndex.HEADER +
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1145
            b"\na option 0 1 .b :"
1146
            b"\na opt 1 2 .c :"
1147
            b"\nb option 2 3 0 :",
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.
1148
            call[1][1].getvalue())
1149
        self.assertEqual({'create_parent_dir': True}, call[2])
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1150
4039.3.5 by John Arbash Meinel
Add direct tests for _get_total_build_size.
1151
    def assertTotalBuildSize(self, size, keys, positions):
1152
        self.assertEqual(size,
1153
                         knit._get_total_build_size(None, keys, positions))
1154
1155
    def test__get_total_build_size(self):
1156
        positions = {
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1157
            (b'a',): (('fulltext', False), ((b'a',), 0, 100), None),
1158
            (b'b',): (('line-delta', False), ((b'b',), 100, 21), (b'a',)),
1159
            (b'c',): (('line-delta', False), ((b'c',), 121, 35), (b'b',)),
1160
            (b'd',): (('line-delta', False), ((b'd',), 156, 12), (b'b',)),
4039.3.5 by John Arbash Meinel
Add direct tests for _get_total_build_size.
1161
            }
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1162
        self.assertTotalBuildSize(100, [(b'a',)], positions)
1163
        self.assertTotalBuildSize(121, [(b'b',)], positions)
4039.3.5 by John Arbash Meinel
Add direct tests for _get_total_build_size.
1164
        # c needs both a & b
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1165
        self.assertTotalBuildSize(156, [(b'c',)], positions)
4039.3.5 by John Arbash Meinel
Add direct tests for _get_total_build_size.
1166
        # we shouldn't count 'b' twice
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1167
        self.assertTotalBuildSize(156, [(b'b',), (b'c',)], positions)
1168
        self.assertTotalBuildSize(133, [(b'd',)], positions)
1169
        self.assertTotalBuildSize(168, [(b'c',), (b'd',)], positions)
4039.3.5 by John Arbash Meinel
Add direct tests for _get_total_build_size.
1170
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1171
    def test_get_position(self):
1172
        transport = MockTransport([
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.
1173
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1174
            b"a option 0 1 :",
1175
            b"b option 1 2 :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1176
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1177
        index = self.get_knit_index(transport, "filename", "r")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1178
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1179
        self.assertEqual(((b"a",), 0, 1), index.get_position((b"a",)))
1180
        self.assertEqual(((b"b",), 1, 2), index.get_position((b"b",)))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1181
1182
    def test_get_method(self):
1183
        transport = MockTransport([
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.
1184
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1185
            b"a fulltext,unknown 0 1 :",
1186
            b"b unknown,line-delta 1 2 :",
1187
            b"c bad 3 4 :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1188
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1189
        index = self.get_knit_index(transport, "filename", "r")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1190
7027.1.2 by Martin
Fixup low level knit tests for Python 3
1191
        self.assertEqual("fulltext", index.get_method(b"a"))
1192
        self.assertEqual("line-delta", index.get_method(b"b"))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1193
        self.assertRaises(knit.KnitIndexUnknownMethod, index.get_method, b"c")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1194
1195
    def test_get_options(self):
1196
        transport = MockTransport([
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.
1197
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1198
            b"a opt1 0 1 :",
1199
            b"b opt2,opt3 1 2 :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1200
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1201
        index = self.get_knit_index(transport, "filename", "r")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1202
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1203
        self.assertEqual([b"opt1"], index.get_options(b"a"))
1204
        self.assertEqual([b"opt2", b"opt3"], index.get_options(b"b"))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1205
3287.5.6 by Robert Collins
Remove _KnitIndex.get_parents.
1206
    def test_get_parent_map(self):
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1207
        transport = MockTransport([
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.
1208
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1209
            b"a option 0 1 :",
1210
            b"b option 1 2 0 .c :",
1211
            b"c option 1 2 1 0 .e :"
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1212
            ])
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1213
        index = self.get_knit_index(transport, "filename", "r")
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1214
3287.5.6 by Robert Collins
Remove _KnitIndex.get_parents.
1215
        self.assertEqual({
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1216
            (b"a",): (),
1217
            (b"b",): ((b"a",), (b"c",)),
1218
            (b"c",): ((b"b",), (b"a",), (b"e",)),
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.
1219
            }, index.get_parent_map(index.keys()))
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1220
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1221
    def test_impossible_parent(self):
1222
        """Test we get KnitCorrupt if the parent couldn't possibly exist."""
1223
        transport = MockTransport([
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.
1224
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1225
            b"a option 0 1 :",
1226
            b"b option 0 1 4 :"  # We don't have a 4th record
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1227
            ])
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.
1228
        index = self.get_knit_index(transport, 'filename', 'r')
6729.7.2 by Jelmer Vernooij
Finish move.
1229
        self.assertRaises(KnitCorrupt, index.keys)
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1230
1231
    def test_corrupted_parent(self):
1232
        transport = MockTransport([
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.
1233
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1234
            b"a option 0 1 :",
1235
            b"b option 0 1 :",
1236
            b"c option 0 1 1v :", # Can't have a parent of '1v'
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1237
            ])
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.
1238
        index = self.get_knit_index(transport, 'filename', 'r')
6729.7.2 by Jelmer Vernooij
Finish move.
1239
        self.assertRaises(KnitCorrupt, index.keys)
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1240
1241
    def test_corrupted_parent_in_list(self):
1242
        transport = MockTransport([
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.
1243
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1244
            b"a option 0 1 :",
1245
            b"b option 0 1 :",
1246
            b"c option 0 1 1 v :", # Can't have a parent of 'v'
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1247
            ])
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.
1248
        index = self.get_knit_index(transport, 'filename', 'r')
6729.7.2 by Jelmer Vernooij
Finish move.
1249
        self.assertRaises(KnitCorrupt, index.keys)
2484.1.13 by John Arbash Meinel
Add a test that KnitCorrupt is raised when parent strings are invalid.
1250
2484.1.18 by John Arbash Meinel
Test that we properly verify the size and position strings.
1251
    def test_invalid_position(self):
1252
        transport = MockTransport([
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.
1253
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1254
            b"a option 1v 1 :",
2484.1.18 by John Arbash Meinel
Test that we properly verify the size and position strings.
1255
            ])
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.
1256
        index = self.get_knit_index(transport, 'filename', 'r')
6729.7.2 by Jelmer Vernooij
Finish move.
1257
        self.assertRaises(KnitCorrupt, index.keys)
2484.1.18 by John Arbash Meinel
Test that we properly verify the size and position strings.
1258
1259
    def test_invalid_size(self):
1260
        transport = MockTransport([
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.
1261
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1262
            b"a option 1 1v :",
2484.1.18 by John Arbash Meinel
Test that we properly verify the size and position strings.
1263
            ])
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.
1264
        index = self.get_knit_index(transport, 'filename', 'r')
6729.7.2 by Jelmer Vernooij
Finish move.
1265
        self.assertRaises(KnitCorrupt, index.keys)
2484.1.18 by John Arbash Meinel
Test that we properly verify the size and position strings.
1266
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1267
    def test_scan_unvalidated_index_not_implemented(self):
1268
        transport = MockTransport()
1269
        index = self.get_knit_index(transport, 'filename', 'r')
1270
        self.assertRaises(
1271
            NotImplementedError, index.scan_unvalidated_index,
1272
            'dummy graph_index')
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1273
        self.assertRaises(
1274
            NotImplementedError, index.get_missing_compression_parents)
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1275
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1276
    def test_short_line(self):
1277
        transport = MockTransport([
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.
1278
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1279
            b"a option 0 10  :",
1280
            b"b option 10 10 0", # This line isn't terminated, ignored
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1281
            ])
1282
        index = self.get_knit_index(transport, "filename", "r")
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1283
        self.assertEqual({(b'a',)}, index.keys())
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1284
1285
    def test_skip_incomplete_record(self):
1286
        # A line with bogus data should just be skipped
1287
        transport = MockTransport([
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.
1288
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1289
            b"a option 0 10  :",
1290
            b"b option 10 10 0", # This line isn't terminated, ignored
1291
            b"c option 20 10 0 :", # Properly terminated, and starts with '\n'
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1292
            ])
1293
        index = self.get_knit_index(transport, "filename", "r")
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1294
        self.assertEqual({(b'a',), (b'c',)}, index.keys())
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1295
1296
    def test_trailing_characters(self):
1297
        # A line with bogus data should just be skipped
1298
        transport = MockTransport([
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.
1299
            _KndxIndex.HEADER,
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1300
            b"a option 0 10  :",
1301
            b"b option 10 10 0 :a", # This line has extra trailing characters
1302
            b"c option 20 10 0 :", # Properly terminated, and starts with '\n'
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1303
            ])
1304
        index = self.get_knit_index(transport, "filename", "r")
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1305
        self.assertEqual({(b'a',), (b'c',)}, index.keys())
2484.1.24 by John Arbash Meinel
Add direct tests of how we handle incomplete/'broken' lines
1306
2158.3.1 by Dmitry Vasiliev
KnitIndex tests/fixes/optimizations
1307
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1308
class LowLevelKnitIndexTests_c(LowLevelKnitIndexTests):
1309
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1310
    _test_needs_features = [compiled_knit_feature]
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1311
7027.1.2 by Martin
Fixup low level knit tests for Python 3
1312
    @property
1313
    def _load_data(self):
6670.4.3 by Jelmer Vernooij
Fix more imports.
1314
        from ..bzr._knit_load_data_pyx import _load_data_c
7027.1.2 by Martin
Fixup low level knit tests for Python 3
1315
        return _load_data_c
2484.1.1 by John Arbash Meinel
Add an initial function to read knit indexes in pyrex.
1316
1317
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1318
class Test_KnitAnnotator(TestCaseWithMemoryTransport):
1319
1320
    def make_annotator(self):
1321
        factory = knit.make_pack_factory(True, True, 1)
1322
        vf = factory(self.get_transport())
1323
        return knit._KnitAnnotator(vf)
1324
1325
    def test__expand_fulltext(self):
1326
        ann = self.make_annotator()
6963.2.4 by Jelmer Vernooij
Add bees.
1327
        rev_key = (b'rev-id',)
4454.3.36 by John Arbash Meinel
Only cache the content objects that we will reuse.
1328
        ann._num_compression_children[rev_key] = 1
6963.2.4 by Jelmer Vernooij
Add bees.
1329
        res = ann._expand_record(rev_key, ((b'parent-id',),), None,
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1330
                           [b'line1\n', b'line2\n'], ('fulltext', True))
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1331
        # The content object and text lines should be cached appropriately
6963.2.4 by Jelmer Vernooij
Add bees.
1332
        self.assertEqual([b'line1\n', b'line2'], res)
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1333
        content_obj = ann._content_objects[rev_key]
6963.2.4 by Jelmer Vernooij
Add bees.
1334
        self.assertEqual([b'line1\n', b'line2\n'], content_obj._lines)
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1335
        self.assertEqual(res, content_obj.text())
1336
        self.assertEqual(res, ann._text_cache[rev_key])
1337
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1338
    def test__expand_delta_comp_parent_not_available(self):
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1339
        # Parent isn't available yet, so we return nothing, but queue up this
1340
        # node for later processing
1341
        ann = self.make_annotator()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1342
        rev_key = (b'rev-id',)
1343
        parent_key = (b'parent-id',)
1344
        record = [b'0,1,1\n', b'new-line\n']
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1345
        details = ('line-delta', False)
1346
        res = ann._expand_record(rev_key, (parent_key,), parent_key,
1347
                                 record, details)
1348
        self.assertEqual(None, res)
1349
        self.assertTrue(parent_key in ann._pending_deltas)
1350
        pending = ann._pending_deltas[parent_key]
1351
        self.assertEqual(1, len(pending))
1352
        self.assertEqual((rev_key, (parent_key,), record, details), pending[0])
1353
4454.3.33 by John Arbash Meinel
Change the _expand_record code to pop out old content objects.
1354
    def test__expand_record_tracks_num_children(self):
1355
        ann = self.make_annotator()
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1356
        rev_key = (b'rev-id',)
1357
        rev2_key = (b'rev2-id',)
1358
        parent_key = (b'parent-id',)
1359
        record = [b'0,1,1\n', b'new-line\n']
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1360
        details = ('line-delta', False)
4454.3.33 by John Arbash Meinel
Change the _expand_record code to pop out old content objects.
1361
        ann._num_compression_children[parent_key] = 2
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1362
        ann._expand_record(parent_key, (), None, [b'line1\n', b'line2\n'],
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1363
                           ('fulltext', False))
4454.3.33 by John Arbash Meinel
Change the _expand_record code to pop out old content objects.
1364
        res = ann._expand_record(rev_key, (parent_key,), parent_key,
1365
                                 record, details)
1366
        self.assertEqual({parent_key: 1}, ann._num_compression_children)
1367
        # Expanding the second child should remove the content object, and the
1368
        # num_compression_children entry
1369
        res = ann._expand_record(rev2_key, (parent_key,), parent_key,
1370
                                 record, details)
1371
        self.assertFalse(parent_key in ann._content_objects)
1372
        self.assertEqual({}, ann._num_compression_children)
4454.3.36 by John Arbash Meinel
Only cache the content objects that we will reuse.
1373
        # We should not cache the content_objects for rev2 and rev, because
1374
        # they do not have compression children of their own.
1375
        self.assertEqual({}, ann._content_objects)
4454.3.33 by John Arbash Meinel
Change the _expand_record code to pop out old content objects.
1376
4454.3.37 by John Arbash Meinel
Add tests tha left-matching-blocks gets populated.
1377
    def test__expand_delta_records_blocks(self):
1378
        ann = self.make_annotator()
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1379
        rev_key = (b'rev-id',)
1380
        parent_key = (b'parent-id',)
1381
        record = [b'0,1,1\n', b'new-line\n']
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1382
        details = ('line-delta', True)
4454.3.37 by John Arbash Meinel
Add tests tha left-matching-blocks gets populated.
1383
        ann._num_compression_children[parent_key] = 2
1384
        ann._expand_record(parent_key, (), None,
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1385
                           [b'line1\n', b'line2\n', b'line3\n'],
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1386
                           ('fulltext', False))
4454.3.37 by John Arbash Meinel
Add tests tha left-matching-blocks gets populated.
1387
        ann._expand_record(rev_key, (parent_key,), parent_key, record, details)
4454.3.38 by John Arbash Meinel
Start using left-matching-blocks during the actual annotation.
1388
        self.assertEqual({(rev_key, parent_key): [(1, 1, 1), (3, 3, 0)]},
1389
                         ann._matching_blocks)
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1390
        rev2_key = (b'rev2-id',)
6963.2.4 by Jelmer Vernooij
Add bees.
1391
        record = [b'0,1,1\n', b'new-line\n']
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1392
        details = ('line-delta', False)
4454.3.37 by John Arbash Meinel
Add tests tha left-matching-blocks gets populated.
1393
        ann._expand_record(rev2_key, (parent_key,), parent_key, record, details)
1394
        self.assertEqual([(1, 1, 2), (3, 3, 0)],
4454.3.38 by John Arbash Meinel
Start using left-matching-blocks during the actual annotation.
1395
                         ann._matching_blocks[(rev2_key, parent_key)])
1396
1397
    def test__get_parent_ann_uses_matching_blocks(self):
1398
        ann = self.make_annotator()
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1399
        rev_key = (b'rev-id',)
1400
        parent_key = (b'parent-id',)
4454.3.38 by John Arbash Meinel
Start using left-matching-blocks during the actual annotation.
1401
        parent_ann = [(parent_key,)]*3
1402
        block_key = (rev_key, parent_key)
1403
        ann._annotations_cache[parent_key] = parent_ann
1404
        ann._matching_blocks[block_key] = [(0, 1, 1), (3, 3, 0)]
1405
        # We should not try to access any parent_lines content, because we know
1406
        # we already have the matching blocks
1407
        par_ann, blocks = ann._get_parent_annotations_and_matches(rev_key,
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1408
                                        [b'1\n', b'2\n', b'3\n'], parent_key)
4454.3.38 by John Arbash Meinel
Start using left-matching-blocks during the actual annotation.
1409
        self.assertEqual(parent_ann, par_ann)
1410
        self.assertEqual([(0, 1, 1), (3, 3, 0)], blocks)
1411
        self.assertEqual({}, ann._matching_blocks)
4454.3.37 by John Arbash Meinel
Add tests tha left-matching-blocks gets populated.
1412
4454.3.31 by John Arbash Meinel
Change the processing lines to now handle fallbacks properly.
1413
    def test__process_pending(self):
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1414
        ann = self.make_annotator()
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1415
        rev_key = (b'rev-id',)
1416
        p1_key = (b'p1-id',)
1417
        p2_key = (b'p2-id',)
1418
        record = [b'0,1,1\n', b'new-line\n']
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1419
        details = ('line-delta', False)
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1420
        p1_record = [b'line1\n', b'line2\n']
4454.3.33 by John Arbash Meinel
Change the _expand_record code to pop out old content objects.
1421
        ann._num_compression_children[p1_key] = 1
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
1422
        res = ann._expand_record(rev_key, (p1_key, p2_key), p1_key,
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1423
                                 record, details)
1424
        self.assertEqual(None, res)
1425
        # self.assertTrue(p1_key in ann._pending_deltas)
1426
        self.assertEqual({}, ann._pending_annotation)
1427
        # Now insert p1, and we should be able to expand the delta
1428
        res = ann._expand_record(p1_key, (), None, p1_record,
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1429
                                 ('fulltext', False))
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1430
        self.assertEqual(p1_record, res)
1431
        ann._annotations_cache[p1_key] = [(p1_key,)]*2
1432
        res = ann._process_pending(p1_key)
4454.3.31 by John Arbash Meinel
Change the processing lines to now handle fallbacks properly.
1433
        self.assertEqual([], res)
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1434
        self.assertFalse(p1_key in ann._pending_deltas)
1435
        self.assertTrue(p2_key in ann._pending_annotation)
1436
        self.assertEqual({p2_key: [(rev_key, (p1_key, p2_key))]},
1437
                         ann._pending_annotation)
1438
        # Now fill in parent 2, and pending annotation should be satisfied
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1439
        res = ann._expand_record(p2_key, (), None, [], ('fulltext', False))
4454.3.31 by John Arbash Meinel
Change the processing lines to now handle fallbacks properly.
1440
        ann._annotations_cache[p2_key] = []
1441
        res = ann._process_pending(p2_key)
1442
        self.assertEqual([rev_key], res)
1443
        self.assertEqual({}, ann._pending_annotation)
1444
        self.assertEqual({}, ann._pending_deltas)
4454.3.30 by John Arbash Meinel
add a bit more work to be able to process 'pending_annotations'.
1445
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1446
    def test_record_delta_removes_basis(self):
1447
        ann = self.make_annotator()
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1448
        ann._expand_record((b'parent-id',), (), None,
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
1449
                           [b'line1\n', b'line2\n'], ('fulltext', False))
6963.2.3 by Jelmer Vernooij
Fix some more tests.
1450
        ann._num_compression_children[b'parent-id'] = 2
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1451
4454.3.64 by John Arbash Meinel
Ensure that _KnitAnnotator also supports add_special_text.
1452
    def test_annotate_special_text(self):
1453
        ann = self.make_annotator()
1454
        vf = ann._vf
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1455
        rev1_key = (b'rev-1',)
1456
        rev2_key = (b'rev-2',)
1457
        rev3_key = (b'rev-3',)
1458
        spec_key = (b'special:',)
1459
        vf.add_lines(rev1_key, [], [b'initial content\n'])
1460
        vf.add_lines(rev2_key, [rev1_key], [b'initial content\n',
1461
                                            b'common content\n',
1462
                                            b'content in 2\n'])
1463
        vf.add_lines(rev3_key, [rev1_key], [b'initial content\n',
1464
                                            b'common content\n',
1465
                                            b'content in 3\n'])
1466
        spec_text = (b'initial content\n'
1467
                     b'common content\n'
1468
                     b'content in 2\n'
1469
                     b'content in 3\n')
4454.3.64 by John Arbash Meinel
Ensure that _KnitAnnotator also supports add_special_text.
1470
        ann.add_special_text(spec_key, [rev2_key, rev3_key], spec_text)
1471
        anns, lines = ann.annotate(spec_key)
1472
        self.assertEqual([(rev1_key,),
1473
                          (rev2_key, rev3_key),
1474
                          (rev2_key,),
1475
                          (rev3_key,),
1476
                         ], anns)
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1477
        self.assertEqualDiff(spec_text, b''.join(lines))
4454.3.64 by John Arbash Meinel
Ensure that _KnitAnnotator also supports add_special_text.
1478
4454.3.28 by John Arbash Meinel
Continue breaking things to build it up cleanly.
1479
1684.3.3 by Robert Collins
Add a special cased weaves to knit converter.
1480
class KnitTests(TestCaseWithTransport):
1481
    """Class containing knit test helper routines."""
1563.2.16 by Robert Collins
Change WeaveStore into VersionedFileStore and make its versoined file class parameterisable.
1482
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.
1483
    def make_test_knit(self, annotate=False, name='test'):
1484
        mapper = ConstantMapper(name)
1485
        return make_file_factory(annotate, mapper)(self.get_transport())
1863.1.1 by John Arbash Meinel
Allow Versioned files to do caching if explicitly asked, and implement for Knit
1486
1487
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
1488
class TestBadShaError(KnitTests):
1489
    """Tests for handling of sha errors."""
1490
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
1491
    def test_sha_exception_has_text(self):
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
1492
        # having the failed text included in the error allows for recovery.
1493
        source = self.make_test_knit()
1494
        target = self.make_test_knit(name="target")
1495
        if not source._max_delta_chain:
1496
            raise TestNotApplicable(
1497
                "cannot get delta-caused sha failures without deltas.")
1498
        # create a basis
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1499
        basis = (b'basis',)
1500
        broken = (b'broken',)
1501
        source.add_lines(basis, (), [b'foo\n'])
1502
        source.add_lines(broken, (basis,), [b'foo\n', b'bar\n'])
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
1503
        # Seed target with a bad basis text
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1504
        target.add_lines(basis, (), [b'gam\n'])
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
1505
        target.insert_record_stream(
1506
            source.get_record_stream([broken], 'unordered', False))
6729.7.2 by Jelmer Vernooij
Finish move.
1507
        err = self.assertRaises(KnitCorrupt,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1508
            next(target.get_record_stream([broken], 'unordered', True
1509
            )).get_bytes_as, 'chunked')
1510
        self.assertEqual([b'gam\n', b'bar\n'], err.content)
3787.1.2 by Robert Collins
Ensure SHA1KnitCorrupt formats ok.
1511
        # Test for formatting with live data
1512
        self.assertStartsWith(str(err), "Knit ")
3787.1.1 by Robert Collins
Embed the failed text in sha1 knit errors.
1513
1514
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1515
class TestKnitIndex(KnitTests):
1516
1517
    def test_add_versions_dictionary_compresses(self):
1518
        """Adding versions to the index should update the lookup dict"""
1519
        knit = self.make_test_knit()
1520
        idx = knit._index
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1521
        idx.add_records([((b'a-1',), [b'fulltext'], ((b'a-1',), 0, 0), [])])
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1522
        self.check_file_contents('test.kndx',
6973.10.4 by Jelmer Vernooij
Update python3.passing.
1523
            b'# bzr knit index 8\n'
1524
            b'\n'
1525
            b'a-1 fulltext 0 0  :'
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1526
            )
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.
1527
        idx.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1528
            ((b'a-2',), [b'fulltext'], ((b'a-2',), 0, 0), [(b'a-1',)]),
1529
            ((b'a-3',), [b'fulltext'], ((b'a-3',), 0, 0), [(b'a-2',)]),
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.
1530
            ])
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1531
        self.check_file_contents('test.kndx',
6973.10.4 by Jelmer Vernooij
Update python3.passing.
1532
            b'# bzr knit index 8\n'
1533
            b'\n'
1534
            b'a-1 fulltext 0 0  :\n'
1535
            b'a-2 fulltext 0 0 0 :\n'
1536
            b'a-3 fulltext 0 0 1 :'
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1537
            )
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1538
        self.assertEqual({(b'a-3',), (b'a-1',), (b'a-2',)}, idx.keys())
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.
1539
        self.assertEqual({
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1540
            (b'a-1',): (((b'a-1',), 0, 0), None, (), ('fulltext', False)),
1541
            (b'a-2',): (((b'a-2',), 0, 0), None, ((b'a-1',),), ('fulltext', False)),
1542
            (b'a-3',): (((b'a-3',), 0, 0), None, ((b'a-2',),), ('fulltext', False)),
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.
1543
            }, idx.get_build_details(idx.keys()))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1544
        self.assertEqual({(b'a-1',): (),
1545
            (b'a-2',): ((b'a-1',),),
1546
            (b'a-3',): ((b'a-2',),),},
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.
1547
            idx.get_parent_map(idx.keys()))
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1548
1549
    def test_add_versions_fails_clean(self):
1550
        """If add_versions fails in the middle, it restores a pristine state.
1551
1552
        Any modifications that are made to the index are reset if all versions
1553
        cannot be added.
1554
        """
1555
        # This cheats a little bit by passing in a generator which will
1556
        # raise an exception before the processing finishes
1557
        # Other possibilities would be to have an version with the wrong number
1558
        # of entries, or to make the backing transport unable to write any
1559
        # files.
1560
1561
        knit = self.make_test_knit()
1562
        idx = knit._index
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1563
        idx.add_records([((b'a-1',), [b'fulltext'], ((b'a-1',), 0, 0), [])])
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1564
1565
        class StopEarly(Exception):
1566
            pass
1567
1568
        def generate_failure():
1569
            """Add some entries and then raise an exception"""
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1570
            yield ((b'a-2',), [b'fulltext'], (None, 0, 0), (b'a-1',))
1571
            yield ((b'a-3',), [b'fulltext'], (None, 0, 0), (b'a-2',))
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1572
            raise StopEarly()
1573
1574
        # Assert the pre-condition
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.
1575
        def assertA1Only():
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1576
            self.assertEqual({(b'a-1',)}, set(idx.keys()))
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.
1577
            self.assertEqual(
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1578
                {(b'a-1',): (((b'a-1',), 0, 0), None, (), ('fulltext', False))},
1579
                idx.get_build_details([(b'a-1',)]))
1580
            self.assertEqual({(b'a-1',):()}, idx.get_parent_map(idx.keys()))
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.
1581
1582
        assertA1Only()
1583
        self.assertRaises(StopEarly, idx.add_records, generate_failure())
2102.2.1 by John Arbash Meinel
Fix bug #64789 _KnitIndex.add_versions() should dict compress new revisions
1584
        # And it shouldn't be modified
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.
1585
        assertA1Only()
2171.1.1 by John Arbash Meinel
Knit index files should ignore empty indexes rather than consider them corrupt.
1586
1587
    def test_knit_index_ignores_empty_files(self):
1588
        # There was a race condition in older bzr, where a ^C at the right time
1589
        # could leave an empty .kndx file, which bzr would later claim was a
1590
        # corrupted file since the header was not present. In reality, the file
1591
        # just wasn't created, so it should be ignored.
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1592
        t = transport.get_transport_from_path('.')
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1593
        t.put_bytes('test.kndx', b'')
2171.1.1 by John Arbash Meinel
Knit index files should ignore empty indexes rather than consider them corrupt.
1594
1595
        knit = self.make_test_knit()
1596
1597
    def test_knit_index_checks_header(self):
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
1598
        t = transport.get_transport_from_path('.')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1599
        t.put_bytes('test.kndx', b'# not really a knit header\n\n')
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.
1600
        k = self.make_test_knit()
1601
        self.assertRaises(KnitHeaderError, k.keys)
2592.3.2 by Robert Collins
Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.
1602
1603
1604
class TestGraphIndexKnit(KnitTests):
1605
    """Tests for knits using a GraphIndex rather than a KnitIndex."""
1606
1607
    def make_g_index(self, name, ref_lists=0, nodes=[]):
1608
        builder = GraphIndexBuilder(ref_lists)
1609
        for node, references, value in nodes:
1610
            builder.add_node(node, references, value)
1611
        stream = builder.finish()
1612
        trans = self.get_transport()
2890.2.1 by Robert Collins
* ``bzrlib.index.GraphIndex`` now requires a size parameter to the
1613
        size = trans.put_file(name, stream)
1614
        return GraphIndex(trans, name, size)
2592.3.2 by Robert Collins
Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.
1615
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1616
    def two_graph_index(self, deltas=False, catch_adds=False):
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1617
        """Build a two-graph index.
1618
1619
        :param deltas: If true, use underlying indices with two node-ref
1620
            lists and 'parent' set to a delta-compressed against tail.
1621
        """
2592.3.2 by Robert Collins
Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.
1622
        # build a complex graph across several indices.
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1623
        if deltas:
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1624
            # delta compression inn the index
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1625
            index1 = self.make_g_index('1', 2, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1626
                ((b'tip', ), b'N0 100', ([(b'parent', )], [], )),
1627
                ((b'tail', ), b'', ([], []))])
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1628
            index2 = self.make_g_index('2', 2, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1629
                ((b'parent', ), b' 100 78', ([(b'tail', ), (b'ghost', )], [(b'tail', )])),
1630
                ((b'separate', ), b'', ([], []))])
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1631
        else:
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1632
            # just blob location and graph in the index.
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1633
            index1 = self.make_g_index('1', 1, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1634
                ((b'tip', ), b'N0 100', ([(b'parent', )], )),
1635
                ((b'tail', ), b'', ([], ))])
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1636
            index2 = self.make_g_index('2', 1, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1637
                ((b'parent', ), b' 100 78', ([(b'tail', ), (b'ghost', )], )),
1638
                ((b'separate', ), b'', ([], ))])
2592.3.2 by Robert Collins
Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.
1639
        combined_index = CombinedGraphIndex([index1, index2])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1640
        if catch_adds:
1641
            self.combined_index = combined_index
1642
            self.caught_entries = []
1643
            add_callback = self.catch_add
1644
        else:
1645
            add_callback = None
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.
1646
        return _KnitGraphIndex(combined_index, lambda:True, deltas=deltas,
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1647
            add_callback=add_callback)
2592.3.4 by Robert Collins
Implement get_ancestry/get_ancestry_with_ghosts for KnitGraphIndex.
1648
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.
1649
    def test_keys(self):
1650
        index = self.two_graph_index()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1651
        self.assertEqual({(b'tail',), (b'tip',), (b'parent',), (b'separate',)},
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.
1652
            set(index.keys()))
2592.3.9 by Robert Collins
Implement KnitGraphIndex.has_version.
1653
2592.3.10 by Robert Collins
Implement KnitGraphIndex.get_position.
1654
    def test_get_position(self):
1655
        index = self.two_graph_index()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1656
        self.assertEqual((index._graph_index._indices[0], 0, 100), index.get_position((b'tip',)))
1657
        self.assertEqual((index._graph_index._indices[1], 100, 78), index.get_position((b'parent',)))
2592.3.10 by Robert Collins
Implement KnitGraphIndex.get_position.
1658
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1659
    def test_get_method_deltas(self):
1660
        index = self.two_graph_index(deltas=True)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1661
        self.assertEqual('fulltext', index.get_method((b'tip',)))
1662
        self.assertEqual('line-delta', index.get_method((b'parent',)))
2592.3.11 by Robert Collins
Implement KnitGraphIndex.get_method.
1663
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1664
    def test_get_method_no_deltas(self):
1665
        # check that the parent-history lookup is ignored with deltas=False.
1666
        index = self.two_graph_index(deltas=False)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1667
        self.assertEqual('fulltext', index.get_method((b'tip',)))
1668
        self.assertEqual('fulltext', index.get_method((b'parent',)))
2592.3.13 by Robert Collins
Implement KnitGraphIndex.get_method.
1669
2592.3.14 by Robert Collins
Implement KnitGraphIndex.get_options.
1670
    def test_get_options_deltas(self):
1671
        index = self.two_graph_index(deltas=True)
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1672
        self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1673
        self.assertEqual([b'line-delta'], index.get_options((b'parent',)))
2592.3.14 by Robert Collins
Implement KnitGraphIndex.get_options.
1674
1675
    def test_get_options_no_deltas(self):
1676
        # check that the parent-history lookup is ignored with deltas=False.
1677
        index = self.two_graph_index(deltas=False)
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1678
        self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1679
        self.assertEqual([b'fulltext'], index.get_options((b'parent',)))
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.
1680
1681
    def test_get_parent_map(self):
1682
        index = self.two_graph_index()
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1683
        self.assertEqual({(b'parent',):((b'tail',), (b'ghost',))},
1684
            index.get_parent_map([(b'parent',), (b'ghost',)]))
2592.3.14 by Robert Collins
Implement KnitGraphIndex.get_options.
1685
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1686
    def catch_add(self, entries):
1687
        self.caught_entries.append(entries)
1688
1689
    def test_add_no_callback_errors(self):
1690
        index = self.two_graph_index()
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.
1691
        self.assertRaises(errors.ReadOnlyError, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1692
            [((b'new',), b'fulltext,no-eol', (None, 50, 60), [b'separate'])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1693
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1694
    def test_add_version_smoke(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1695
        index = self.two_graph_index(catch_adds=True)
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1696
        index.add_records([((b'new',), b'fulltext,no-eol', (None, 50, 60),
1697
            [(b'separate',)])])
1698
        self.assertEqual([[((b'new', ), b'N50 60', (((b'separate',),),))]],
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1699
            self.caught_entries)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1700
1701
    def test_add_version_delta_not_delta_index(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1702
        index = self.two_graph_index(catch_adds=True)
6729.7.2 by Jelmer Vernooij
Finish move.
1703
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1704
            [((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1705
        self.assertEqual([], self.caught_entries)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1706
1707
    def test_add_version_same_dup(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1708
        index = self.two_graph_index(catch_adds=True)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1709
        # options can be spelt two different ways
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1710
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
1711
        index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
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.
1712
        # position/length are ignored (because each pack could have fulltext or
1713
        # delta, and be at a different position.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1714
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100),
1715
            [(b'parent',)])])
1716
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000),
1717
            [(b'parent',)])])
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.
1718
        # but neither should have added data:
1719
        self.assertEqual([[], [], [], []], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1720
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1721
    def test_add_version_different_dup(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1722
        index = self.two_graph_index(deltas=True, catch_adds=True)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1723
        # change options
6729.7.2 by Jelmer Vernooij
Finish move.
1724
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1725
            [((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
6729.7.2 by Jelmer Vernooij
Finish move.
1726
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1727
            [((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1728
        # parents
6729.7.2 by Jelmer Vernooij
Finish move.
1729
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1730
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1731
        self.assertEqual([], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1732
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1733
    def test_add_versions_nodeltas(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1734
        index = self.two_graph_index(catch_adds=True)
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.
1735
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1736
                ((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1737
                ((b'new2',), b'fulltext', (None, 0, 6), [(b'new',)]),
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1738
                ])
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1739
        self.assertEqual([((b'new', ), b'N50 60', (((b'separate',),),)),
1740
            ((b'new2', ), b' 0 6', (((b'new',),),))],
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1741
            sorted(self.caught_entries[0]))
1742
        self.assertEqual(1, len(self.caught_entries))
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1743
1744
    def test_add_versions_deltas(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1745
        index = self.two_graph_index(deltas=True, catch_adds=True)
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.
1746
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1747
                ((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)]),
1748
                ((b'new2',), b'line-delta', (None, 0, 6), [(b'new',)]),
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1749
                ])
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1750
        self.assertEqual([((b'new', ), b'N50 60', (((b'separate',),), ())),
1751
            ((b'new2', ), b' 0 6', (((b'new',),), ((b'new',),), ))],
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1752
            sorted(self.caught_entries[0]))
1753
        self.assertEqual(1, len(self.caught_entries))
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1754
1755
    def test_add_versions_delta_not_delta_index(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1756
        index = self.two_graph_index(catch_adds=True)
6729.7.2 by Jelmer Vernooij
Finish move.
1757
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1758
            [((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1759
        self.assertEqual([], self.caught_entries)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1760
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
1761
    def test_add_versions_random_id_accepted(self):
1762
        index = self.two_graph_index(catch_adds=True)
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.
1763
        index.add_records([], random_id=True)
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
1764
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1765
    def test_add_versions_same_dup(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1766
        index = self.two_graph_index(catch_adds=True)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1767
        # options can be spelt two different ways
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1768
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100),
1769
            [(b'parent',)])])
1770
        index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100),
1771
            [(b'parent',)])])
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.
1772
        # position/length are ignored (because each pack could have fulltext or
1773
        # delta, and be at a different position.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1774
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100),
1775
            [(b'parent',)])])
1776
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000),
1777
            [(b'parent',)])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1778
        # but neither should have added data.
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.
1779
        self.assertEqual([[], [], [], []], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1780
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1781
    def test_add_versions_different_dup(self):
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1782
        index = self.two_graph_index(deltas=True, catch_adds=True)
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1783
        # change options
6729.7.2 by Jelmer Vernooij
Finish move.
1784
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1785
            [((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
6729.7.2 by Jelmer Vernooij
Finish move.
1786
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1787
            [((b'tip',), b'fulltext', (None, 0, 100), [(b'parent',)])])
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1788
        # parents
6729.7.2 by Jelmer Vernooij
Finish move.
1789
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1790
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2592.3.17 by Robert Collins
Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.
1791
        # change options in the second record
6729.7.2 by Jelmer Vernooij
Finish move.
1792
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1793
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)]),
1794
             ((b'tip',), b'line-delta', (None, 0, 100), [(b'parent',)])])
2592.3.19 by Robert Collins
Change KnitGraphIndex from returning data to performing a callback on insertions.
1795
        self.assertEqual([], self.caught_entries)
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1796
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1797
    def make_g_index_missing_compression_parent(self):
1798
        graph_index = self.make_g_index('missing_comp', 2,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1799
            [((b'tip', ), b' 100 78',
1800
              ([(b'missing-parent', ), (b'ghost', )], [(b'missing-parent', )]))])
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1801
        return graph_index
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
1802
4257.4.14 by Andrew Bennetts
Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.
1803
    def make_g_index_missing_parent(self):
1804
        graph_index = self.make_g_index('missing_parent', 2,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1805
            [((b'parent', ), b' 100 78', ([], [])),
1806
             ((b'tip', ), b' 100 78',
6973.14.3 by Jelmer Vernooij
Fix handling of eol character.
1807
              ([(b'parent', ), (b'missing-parent', )], [(b'parent', )])),
4257.4.14 by Andrew Bennetts
Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.
1808
              ])
1809
        return graph_index
1810
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1811
    def make_g_index_no_external_refs(self):
1812
        graph_index = self.make_g_index('no_external_refs', 2,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1813
            [((b'rev', ), b' 100 78',
1814
              ([(b'parent', ), (b'ghost', )], []))])
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1815
        return graph_index
1816
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1817
    def test_add_good_unvalidated_index(self):
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1818
        unvalidated = self.make_g_index_no_external_refs()
1819
        combined = CombinedGraphIndex([unvalidated])
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1820
        index = _KnitGraphIndex(combined, lambda: True, deltas=True)
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1821
        index.scan_unvalidated_index(unvalidated)
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1822
        self.assertEqual(frozenset(), index.get_missing_compression_parents())
1823
4257.4.14 by Andrew Bennetts
Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.
1824
    def test_add_missing_compression_parent_unvalidated_index(self):
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1825
        unvalidated = self.make_g_index_missing_compression_parent()
1826
        combined = CombinedGraphIndex([unvalidated])
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1827
        index = _KnitGraphIndex(combined, lambda: True, deltas=True)
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1828
        index.scan_unvalidated_index(unvalidated)
4011.5.6 by Andrew Bennetts
Make sure it's not possible to commit a pack write group when any versioned file has missing compression parents.
1829
        # This also checks that its only the compression parent that is
1830
        # examined, otherwise 'ghost' would also be reported as a missing
1831
        # parent.
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1832
        self.assertEqual(
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1833
            frozenset([(b'missing-parent',)]),
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1834
            index.get_missing_compression_parents())
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1835
4257.4.14 by Andrew Bennetts
Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.
1836
    def test_add_missing_noncompression_parent_unvalidated_index(self):
1837
        unvalidated = self.make_g_index_missing_parent()
1838
        combined = CombinedGraphIndex([unvalidated])
1839
        index = _KnitGraphIndex(combined, lambda: True, deltas=True,
1840
            track_external_parent_refs=True)
1841
        index.scan_unvalidated_index(unvalidated)
1842
        self.assertEqual(
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1843
            frozenset([(b'missing-parent',)]), index.get_missing_parents())
4257.4.14 by Andrew Bennetts
Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.
1844
4257.4.15 by Andrew Bennetts
Add another test for _KnitGraphIndex.get_missing_parents().
1845
    def test_track_external_parent_refs(self):
1846
        g_index = self.make_g_index('empty', 2, [])
1847
        combined = CombinedGraphIndex([g_index])
1848
        index = _KnitGraphIndex(combined, lambda: True, deltas=True,
1849
            add_callback=self.catch_add, track_external_parent_refs=True)
1850
        self.caught_entries = []
1851
        index.add_records([
6973.11.7 by Jelmer Vernooij
Fix more tests.
1852
            ((b'new-key',), b'fulltext,no-eol', (None, 50, 60),
1853
             [(b'parent-1',), (b'parent-2',)])])
4257.4.15 by Andrew Bennetts
Add another test for _KnitGraphIndex.get_missing_parents().
1854
        self.assertEqual(
6973.11.7 by Jelmer Vernooij
Fix more tests.
1855
            frozenset([(b'parent-1',), (b'parent-2',)]),
4257.4.15 by Andrew Bennetts
Add another test for _KnitGraphIndex.get_missing_parents().
1856
            index.get_missing_parents())
1857
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1858
    def test_add_unvalidated_index_with_present_external_references(self):
1859
        index = self.two_graph_index(deltas=True)
4011.5.10 by Andrew Bennetts
Replace XXX with better comment.
1860
        # Ugly hack to get at one of the underlying GraphIndex objects that
1861
        # two_graph_index built.
1862
        unvalidated = index._graph_index._indices[1]
1863
        # 'parent' is an external ref of _indices[1] (unvalidated), but is
1864
        # present in _indices[0].
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1865
        index.scan_unvalidated_index(unvalidated)
4011.5.1 by Andrew Bennetts
Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.
1866
        self.assertEqual(frozenset(), index.get_missing_compression_parents())
1867
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1868
    def make_new_missing_parent_g_index(self, name):
6973.11.7 by Jelmer Vernooij
Fix more tests.
1869
        missing_parent = name.encode('ascii') + b'-missing-parent'
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1870
        graph_index = self.make_g_index(name, 2,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1871
            [((name.encode('ascii') + b'tip', ), b' 100 78',
6973.11.7 by Jelmer Vernooij
Fix more tests.
1872
              ([(missing_parent, ), (b'ghost', )], [(missing_parent, )]))])
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1873
        return graph_index
1874
1875
    def test_add_mulitiple_unvalidated_indices_with_missing_parents(self):
1876
        g_index_1 = self.make_new_missing_parent_g_index('one')
1877
        g_index_2 = self.make_new_missing_parent_g_index('two')
1878
        combined = CombinedGraphIndex([g_index_1, g_index_2])
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1879
        index = _KnitGraphIndex(combined, lambda: True, deltas=True)
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1880
        index.scan_unvalidated_index(g_index_1)
1881
        index.scan_unvalidated_index(g_index_2)
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1882
        self.assertEqual(
6973.11.7 by Jelmer Vernooij
Fix more tests.
1883
            frozenset([(b'one-missing-parent',), (b'two-missing-parent',)]),
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1884
            index.get_missing_compression_parents())
1885
1886
    def test_add_mulitiple_unvalidated_indices_with_mutual_dependencies(self):
1887
        graph_index_a = self.make_g_index('one', 2,
6973.11.7 by Jelmer Vernooij
Fix more tests.
1888
            [((b'parent-one', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1889
             ((b'child-of-two', ), b' 100 78',
1890
              ([(b'parent-two',)], [(b'parent-two',)]))])
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1891
        graph_index_b = self.make_g_index('two', 2,
6973.11.7 by Jelmer Vernooij
Fix more tests.
1892
            [((b'parent-two', ), b' 100 78', ([(b'non-compression-parent',)], [])),
1893
             ((b'child-of-one', ), b' 100 78',
1894
              ([(b'parent-one',)], [(b'parent-one',)]))])
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1895
        combined = CombinedGraphIndex([graph_index_a, graph_index_b])
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1896
        index = _KnitGraphIndex(combined, lambda: True, deltas=True)
4011.5.7 by Andrew Bennetts
Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.
1897
        index.scan_unvalidated_index(graph_index_a)
1898
        index.scan_unvalidated_index(graph_index_b)
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1899
        self.assertEqual(
1900
            frozenset([]), index.get_missing_compression_parents())
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
1901
4011.5.2 by Andrew Bennetts
Add more tests, improve existing tests, add GraphIndex._external_references()
1902
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1903
class TestNoParentsGraphIndexKnit(KnitTests):
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.
1904
    """Tests for knits using _KnitGraphIndex with no parents."""
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1905
1906
    def make_g_index(self, name, ref_lists=0, nodes=[]):
1907
        builder = GraphIndexBuilder(ref_lists)
1908
        for node, references in nodes:
1909
            builder.add_node(node, references)
1910
        stream = builder.finish()
1911
        trans = self.get_transport()
2890.2.1 by Robert Collins
* ``bzrlib.index.GraphIndex`` now requires a size parameter to the
1912
        size = trans.put_file(name, stream)
1913
        return GraphIndex(trans, name, size)
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1914
4011.5.11 by Robert Collins
Polish the KnitVersionedFiles.scan_unvalidated_index api.
1915
    def test_add_good_unvalidated_index(self):
1916
        unvalidated = self.make_g_index('unvalidated')
1917
        combined = CombinedGraphIndex([unvalidated])
1918
        index = _KnitGraphIndex(combined, lambda: True, parents=False)
1919
        index.scan_unvalidated_index(unvalidated)
1920
        self.assertEqual(frozenset(),
1921
            index.get_missing_compression_parents())
1922
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1923
    def test_parents_deltas_incompatible(self):
1924
        index = CombinedGraphIndex([])
6729.7.1 by Jelmer Vernooij
Move some knit errors.
1925
        self.assertRaises(knit.KnitError, _KnitGraphIndex, lambda:True,
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.
1926
            index, deltas=True, parents=False)
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1927
1928
    def two_graph_index(self, catch_adds=False):
1929
        """Build a two-graph index.
1930
1931
        :param deltas: If true, use underlying indices with two node-ref
1932
            lists and 'parent' set to a delta-compressed against tail.
1933
        """
1934
        # put several versions in the index.
1935
        index1 = self.make_g_index('1', 0, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1936
            ((b'tip', ), b'N0 100'),
1937
            ((b'tail', ), b'')])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1938
        index2 = self.make_g_index('2', 0, [
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1939
            ((b'parent', ), b' 100 78'),
1940
            ((b'separate', ), b'')])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1941
        combined_index = CombinedGraphIndex([index1, index2])
1942
        if catch_adds:
1943
            self.combined_index = combined_index
1944
            self.caught_entries = []
1945
            add_callback = self.catch_add
1946
        else:
1947
            add_callback = None
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.
1948
        return _KnitGraphIndex(combined_index, lambda:True, parents=False,
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1949
            add_callback=add_callback)
1950
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.
1951
    def test_keys(self):
1952
        index = self.two_graph_index()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
1953
        self.assertEqual({(b'tail',), (b'tip',), (b'parent',), (b'separate',)},
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.
1954
            set(index.keys()))
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1955
1956
    def test_get_position(self):
1957
        index = self.two_graph_index()
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.
1958
        self.assertEqual((index._graph_index._indices[0], 0, 100),
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1959
            index.get_position((b'tip',)))
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.
1960
        self.assertEqual((index._graph_index._indices[1], 100, 78),
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1961
            index.get_position((b'parent',)))
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1962
1963
    def test_get_method(self):
1964
        index = self.two_graph_index()
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1965
        self.assertEqual('fulltext', index.get_method((b'tip',)))
1966
        self.assertEqual([b'fulltext'], index.get_options((b'parent',)))
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1967
1968
    def test_get_options(self):
1969
        index = self.two_graph_index()
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1970
        self.assertEqual([b'fulltext', b'no-eol'], index.get_options((b'tip',)))
1971
        self.assertEqual([b'fulltext'], index.get_options((b'parent',)))
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.
1972
1973
    def test_get_parent_map(self):
1974
        index = self.two_graph_index()
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1975
        self.assertEqual({(b'parent',):None},
1976
            index.get_parent_map([(b'parent',), (b'ghost',)]))
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1977
1978
    def catch_add(self, entries):
1979
        self.caught_entries.append(entries)
1980
1981
    def test_add_no_callback_errors(self):
1982
        index = self.two_graph_index()
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.
1983
        self.assertRaises(errors.ReadOnlyError, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1984
            [((b'new',), b'fulltext,no-eol', (None, 50, 60), [(b'separate',)])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1985
1986
    def test_add_version_smoke(self):
1987
        index = self.two_graph_index(catch_adds=True)
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1988
        index.add_records([((b'new',), b'fulltext,no-eol', (None, 50, 60), [])])
1989
        self.assertEqual([[((b'new', ), b'N50 60')]],
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1990
            self.caught_entries)
1991
1992
    def test_add_version_delta_not_delta_index(self):
1993
        index = self.two_graph_index(catch_adds=True)
6729.7.2 by Jelmer Vernooij
Finish move.
1994
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
1995
            [((b'new',), b'no-eol,line-delta', (None, 0, 100), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
1996
        self.assertEqual([], self.caught_entries)
1997
1998
    def test_add_version_same_dup(self):
1999
        index = self.two_graph_index(catch_adds=True)
2000
        # options can be spelt two different ways
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2001
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2002
        index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
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.
2003
        # position/length are ignored (because each pack could have fulltext or
2004
        # delta, and be at a different position.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2005
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2006
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2007
        # but neither should have added data.
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.
2008
        self.assertEqual([[], [], [], []], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2009
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2010
    def test_add_version_different_dup(self):
2011
        index = self.two_graph_index(catch_adds=True)
2012
        # change options
6729.7.2 by Jelmer Vernooij
Finish move.
2013
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2014
            [((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2015
        self.assertRaises(KnitCorrupt, index.add_records,
2016
            [((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2017
        self.assertRaises(KnitCorrupt, index.add_records,
2018
            [((b'tip',), b'fulltext', (None, 0, 100), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2019
        # parents
6729.7.2 by Jelmer Vernooij
Finish move.
2020
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2021
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2022
        self.assertEqual([], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2023
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2024
    def test_add_versions(self):
2025
        index = self.two_graph_index(catch_adds=True)
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.
2026
        index.add_records([
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2027
                ((b'new',), b'fulltext,no-eol', (None, 50, 60), []),
2028
                ((b'new2',), b'fulltext', (None, 0, 6), []),
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2029
                ])
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2030
        self.assertEqual([((b'new', ), b'N50 60'), ((b'new2', ), b' 0 6')],
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2031
            sorted(self.caught_entries[0]))
2032
        self.assertEqual(1, len(self.caught_entries))
2033
2034
    def test_add_versions_delta_not_delta_index(self):
2035
        index = self.two_graph_index(catch_adds=True)
6729.7.2 by Jelmer Vernooij
Finish move.
2036
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2037
            [((b'new',), b'no-eol,line-delta', (None, 0, 100), [(b'parent',)])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2038
        self.assertEqual([], self.caught_entries)
2039
2040
    def test_add_versions_parents_not_parents_index(self):
2041
        index = self.two_graph_index(catch_adds=True)
6729.7.2 by Jelmer Vernooij
Finish move.
2042
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2043
            [((b'new',), b'no-eol,fulltext', (None, 0, 100), [(b'parent',)])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2044
        self.assertEqual([], self.caught_entries)
2045
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
2046
    def test_add_versions_random_id_accepted(self):
2047
        index = self.two_graph_index(catch_adds=True)
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.
2048
        index.add_records([], random_id=True)
2841.2.1 by Robert Collins
* Commit no longer checks for new text keys during insertion when the
2049
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2050
    def test_add_versions_same_dup(self):
2051
        index = self.two_graph_index(catch_adds=True)
2052
        # options can be spelt two different ways
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2053
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 100), [])])
2054
        index.add_records([((b'tip',), b'no-eol,fulltext', (None, 0, 100), [])])
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.
2055
        # position/length are ignored (because each pack could have fulltext or
2056
        # delta, and be at a different position.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2057
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 50, 100), [])])
2058
        index.add_records([((b'tip',), b'fulltext,no-eol', (None, 0, 1000), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2059
        # but neither should have added data.
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.
2060
        self.assertEqual([[], [], [], []], self.caught_entries)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2061
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2062
    def test_add_versions_different_dup(self):
2063
        index = self.two_graph_index(catch_adds=True)
2064
        # change options
6729.7.2 by Jelmer Vernooij
Finish move.
2065
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2066
            [((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2067
        self.assertRaises(KnitCorrupt, index.add_records,
2068
            [((b'tip',), b'line-delta,no-eol', (None, 0, 100), [])])
2069
        self.assertRaises(KnitCorrupt, index.add_records,
2070
            [((b'tip',), b'fulltext', (None, 0, 100), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2071
        # parents
6729.7.2 by Jelmer Vernooij
Finish move.
2072
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2073
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), [(b'parent',)])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2074
        # change options in the second record
6729.7.2 by Jelmer Vernooij
Finish move.
2075
        self.assertRaises(KnitCorrupt, index.add_records,
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2076
            [((b'tip',), b'fulltext,no-eol', (None, 0, 100), []),
2077
             ((b'tip',), b'no-eol,line-delta', (None, 0, 100), [])])
2592.3.34 by Robert Collins
Rough unfactored support for parentless KnitGraphIndexs.
2078
        self.assertEqual([], self.caught_entries)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2079
2080
4039.3.6 by John Arbash Meinel
Turn _split_by_prefix into a classmethod, and add direct tests.
2081
class TestKnitVersionedFiles(KnitTests):
2082
4039.3.7 by John Arbash Meinel
Some direct tests for _group_keys_for_io
2083
    def assertGroupKeysForIo(self, exp_groups, keys, non_local_keys,
2084
                             positions, _min_buffer_size=None):
2085
        kvf = self.make_test_knit()
2086
        if _min_buffer_size is None:
2087
            _min_buffer_size = knit._STREAM_MIN_BUFFER_SIZE
2088
        self.assertEqual(exp_groups, kvf._group_keys_for_io(keys,
2089
                                        non_local_keys, positions,
2090
                                        _min_buffer_size=_min_buffer_size))
2091
4039.3.6 by John Arbash Meinel
Turn _split_by_prefix into a classmethod, and add direct tests.
2092
    def assertSplitByPrefix(self, expected_map, expected_prefix_order,
2093
                            keys):
2094
        split, prefix_order = KnitVersionedFiles._split_by_prefix(keys)
2095
        self.assertEqual(expected_map, split)
2096
        self.assertEqual(expected_prefix_order, prefix_order)
2097
4039.3.7 by John Arbash Meinel
Some direct tests for _group_keys_for_io
2098
    def test__group_keys_for_io(self):
7078.6.1 by Jelmer Vernooij
Fix corrupt knit handling on Python 3.
2099
        ft_detail = ('fulltext', False)
2100
        ld_detail = ('line-delta', False)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2101
        f_a = (b'f', b'a')
2102
        f_b = (b'f', b'b')
2103
        f_c = (b'f', b'c')
2104
        g_a = (b'g', b'a')
2105
        g_b = (b'g', b'b')
2106
        g_c = (b'g', b'c')
4039.3.7 by John Arbash Meinel
Some direct tests for _group_keys_for_io
2107
        positions = {
2108
            f_a: (ft_detail, (f_a, 0, 100), None),
2109
            f_b: (ld_detail, (f_b, 100, 21), f_a),
2110
            f_c: (ld_detail, (f_c, 180, 15), f_b),
2111
            g_a: (ft_detail, (g_a, 121, 35), None),
2112
            g_b: (ld_detail, (g_b, 156, 12), g_a),
2113
            g_c: (ld_detail, (g_c, 195, 13), g_a),
2114
            }
2115
        self.assertGroupKeysForIo([([f_a], set())],
2116
                                  [f_a], [], positions)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2117
        self.assertGroupKeysForIo([([f_a], {f_a})],
4039.3.7 by John Arbash Meinel
Some direct tests for _group_keys_for_io
2118
                                  [f_a], [f_a], positions)
2119
        self.assertGroupKeysForIo([([f_a, f_b], set([]))],
2120
                                  [f_a, f_b], [], positions)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2121
        self.assertGroupKeysForIo([([f_a, f_b], {f_b})],
4039.3.7 by John Arbash Meinel
Some direct tests for _group_keys_for_io
2122
                                  [f_a, f_b], [f_b], positions)
2123
        self.assertGroupKeysForIo([([f_a, f_b, g_a, g_b], set())],
2124
                                  [f_a, g_a, f_b, g_b], [], positions)
2125
        self.assertGroupKeysForIo([([f_a, f_b, g_a, g_b], set())],
2126
                                  [f_a, g_a, f_b, g_b], [], positions,
2127
                                  _min_buffer_size=150)
2128
        self.assertGroupKeysForIo([([f_a, f_b], set()), ([g_a, g_b], set())],
2129
                                  [f_a, g_a, f_b, g_b], [], positions,
2130
                                  _min_buffer_size=100)
2131
        self.assertGroupKeysForIo([([f_c], set()), ([g_b], set())],
2132
                                  [f_c, g_b], [], positions,
2133
                                  _min_buffer_size=125)
2134
        self.assertGroupKeysForIo([([g_b, f_c], set())],
2135
                                  [g_b, f_c], [], positions,
2136
                                  _min_buffer_size=125)
2137
4039.3.6 by John Arbash Meinel
Turn _split_by_prefix into a classmethod, and add direct tests.
2138
    def test__split_by_prefix(self):
6963.2.3 by Jelmer Vernooij
Fix some more tests.
2139
        self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2140
                                  b'g': [(b'g', b'b'), (b'g', b'a')],
2141
                                 }, [b'f', b'g'],
2142
                                 [(b'f', b'a'), (b'g', b'b'),
2143
                                  (b'g', b'a'), (b'f', b'b')])
2144
2145
        self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2146
                                  b'g': [(b'g', b'b'), (b'g', b'a')],
2147
                                 }, [b'f', b'g'],
2148
                                 [(b'f', b'a'), (b'f', b'b'),
2149
                                  (b'g', b'b'), (b'g', b'a')])
2150
2151
        self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2152
                                  b'g': [(b'g', b'b'), (b'g', b'a')],
2153
                                 }, [b'f', b'g'],
2154
                                 [(b'f', b'a'), (b'f', b'b'),
2155
                                  (b'g', b'b'), (b'g', b'a')])
2156
2157
        self.assertSplitByPrefix({b'f': [(b'f', b'a'), (b'f', b'b')],
2158
                                  b'g': [(b'g', b'b'), (b'g', b'a')],
2159
                                  b'': [(b'a',), (b'b',)]
2160
                                 }, [b'f', b'g', b''],
2161
                                 [(b'f', b'a'), (b'g', b'b'),
2162
                                  (b'a',), (b'b',),
2163
                                  (b'g', b'a'), (b'f', b'b')])
4039.3.6 by John Arbash Meinel
Turn _split_by_prefix into a classmethod, and add direct tests.
2164
2165
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2166
class TestStacking(KnitTests):
2167
2168
    def get_basis_and_test_knit(self):
2169
        basis = self.make_test_knit(name='basis')
3350.8.2 by Robert Collins
stacked get_parent_map.
2170
        basis = RecordingVersionedFilesDecorator(basis)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2171
        test = self.make_test_knit(name='test')
2172
        test.add_fallback_versioned_files(basis)
2173
        return basis, test
2174
2175
    def test_add_fallback_versioned_files(self):
2176
        basis = self.make_test_knit(name='basis')
2177
        test = self.make_test_knit(name='test')
2178
        # It must not error; other tests test that the fallback is referred to
2179
        # when accessing data.
2180
        test.add_fallback_versioned_files(basis)
2181
2182
    def test_add_lines(self):
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2183
        # lines added to the test are not added to the basis
2184
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2185
        key = (b'foo',)
2186
        key_basis = (b'bar',)
2187
        key_cross_border = (b'quux',)
2188
        key_delta = (b'zaphod',)
2189
        test.add_lines(key, (), [b'foo\n'])
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2190
        self.assertEqual({}, basis.get_parent_map([key]))
2191
        # lines added to the test that reference across the stack do a
2192
        # fulltext.
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2193
        basis.add_lines(key_basis, (), [b'foo\n'])
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2194
        basis.calls = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2195
        test.add_lines(key_cross_border, (key_basis,), [b'foo\n'])
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2196
        self.assertEqual('fulltext', test._index.get_method(key_cross_border))
3830.3.10 by Martin Pool
Update more stacking effort tests
2197
        # we don't even need to look at the basis to see that this should be
2198
        # stored as a fulltext
2199
        self.assertEqual([], basis.calls)
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2200
        # Subsequent adds do delta.
3350.8.14 by Robert Collins
Review feedback.
2201
        basis.calls = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2202
        test.add_lines(key_delta, (key_cross_border,), [b'foo\n'])
3350.8.9 by Robert Collins
define behaviour for add_lines with stacked storage.
2203
        self.assertEqual('line-delta', test._index.get_method(key_delta))
2204
        self.assertEqual([], basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2205
2206
    def test_annotate(self):
3350.8.8 by Robert Collins
Stacking and knits don't play nice for annotation yet.
2207
        # annotations from the test knit are answered without asking the basis
2208
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2209
        key = (b'foo',)
2210
        key_basis = (b'bar',)
2211
        key_missing = (b'missing',)
2212
        test.add_lines(key, (), [b'foo\n'])
3350.8.8 by Robert Collins
Stacking and knits don't play nice for annotation yet.
2213
        details = test.annotate(key)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2214
        self.assertEqual([(key, b'foo\n')], details)
3350.8.8 by Robert Collins
Stacking and knits don't play nice for annotation yet.
2215
        self.assertEqual([], basis.calls)
2216
        # But texts that are not in the test knit are looked for in the basis
2217
        # directly.
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2218
        basis.add_lines(key_basis, (), [b'foo\n', b'bar\n'])
3350.8.8 by Robert Collins
Stacking and knits don't play nice for annotation yet.
2219
        basis.calls = []
2220
        details = test.annotate(key_basis)
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2221
        self.assertEqual([(key_basis, b'foo\n'), (key_basis, b'bar\n')], details)
3350.9.1 by Robert Collins
Redo annotate more simply, using just the public interfaces for VersionedFiles.
2222
        # Not optimised to date:
2223
        # self.assertEqual([("annotate", key_basis)], basis.calls)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2224
        self.assertEqual([('get_parent_map', {key_basis}),
2225
            ('get_parent_map', {key_basis}),
4537.3.5 by John Arbash Meinel
Fix 3 tests that assumed it would use 'unordered' in the fallback,
2226
            ('get_record_stream', [key_basis], 'topological', True)],
3350.9.1 by Robert Collins
Redo annotate more simply, using just the public interfaces for VersionedFiles.
2227
            basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2228
2229
    def test_check(self):
3517.4.19 by Martin Pool
Update test for knit.check() to expect it to recurse into fallback vfs
2230
        # At the moment checking a stacked knit does implicitly check the
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2231
        # fallback files.
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2232
        basis, test = self.get_basis_and_test_knit()
2233
        test.check()
2234
2235
    def test_get_parent_map(self):
3350.8.2 by Robert Collins
stacked get_parent_map.
2236
        # parents in the test knit are answered without asking the basis
2237
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2238
        key = (b'foo',)
2239
        key_basis = (b'bar',)
2240
        key_missing = (b'missing',)
3350.8.2 by Robert Collins
stacked get_parent_map.
2241
        test.add_lines(key, (), [])
2242
        parent_map = test.get_parent_map([key])
2243
        self.assertEqual({key: ()}, parent_map)
2244
        self.assertEqual([], basis.calls)
2245
        # But parents that are not in the test knit are looked for in the basis
2246
        basis.add_lines(key_basis, (), [])
2247
        basis.calls = []
2248
        parent_map = test.get_parent_map([key, key_basis, key_missing])
2249
        self.assertEqual({key: (),
2250
            key_basis: ()}, parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2251
        self.assertEqual([("get_parent_map", {key_basis, key_missing})],
3350.8.2 by Robert Collins
stacked get_parent_map.
2252
            basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2253
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2254
    def test_get_record_stream_unordered_fulltexts(self):
2255
        # records from the test knit are answered without asking the basis:
2256
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2257
        key = (b'foo',)
2258
        key_basis = (b'bar',)
2259
        key_missing = (b'missing',)
2260
        test.add_lines(key, (), [b'foo\n'])
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2261
        records = list(test.get_record_stream([key], 'unordered', True))
2262
        self.assertEqual(1, len(records))
2263
        self.assertEqual([], basis.calls)
2264
        # Missing (from test knit) objects are retrieved from the basis:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2265
        basis.add_lines(key_basis, (), [b'foo\n', b'bar\n'])
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2266
        basis.calls = []
2267
        records = list(test.get_record_stream([key_basis, key_missing],
2268
            'unordered', True))
2269
        self.assertEqual(2, len(records))
2270
        calls = list(basis.calls)
2271
        for record in records:
2272
            self.assertSubset([record.key], (key_basis, key_missing))
2273
            if record.key == key_missing:
2274
                self.assertIsInstance(record, AbsentContentFactory)
2275
            else:
2276
                reference = list(basis.get_record_stream([key_basis],
2277
                    'unordered', True))[0]
2278
                self.assertEqual(reference.key, record.key)
2279
                self.assertEqual(reference.sha1, record.sha1)
2280
                self.assertEqual(reference.storage_kind, record.storage_kind)
2281
                self.assertEqual(reference.get_bytes_as(reference.storage_kind),
2282
                    record.get_bytes_as(record.storage_kind))
2283
                self.assertEqual(reference.get_bytes_as('fulltext'),
2284
                    record.get_bytes_as('fulltext'))
3350.8.14 by Robert Collins
Review feedback.
2285
        # It's not strictly minimal, but it seems reasonable for now for it to
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2286
        # ask which fallbacks have which parents.
2287
        self.assertEqual([
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2288
            ("get_parent_map", {key_basis, key_missing}),
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2289
            ("get_record_stream", [key_basis], 'unordered', True)],
2290
            calls)
2291
2292
    def test_get_record_stream_ordered_fulltexts(self):
2293
        # ordering is preserved down into the fallback store.
2294
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2295
        key = (b'foo',)
2296
        key_basis = (b'bar',)
2297
        key_basis_2 = (b'quux',)
2298
        key_missing = (b'missing',)
2299
        test.add_lines(key, (key_basis,), [b'foo\n'])
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2300
        # Missing (from test knit) objects are retrieved from the basis:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2301
        basis.add_lines(key_basis, (key_basis_2,), [b'foo\n', b'bar\n'])
2302
        basis.add_lines(key_basis_2, (), [b'quux\n'])
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2303
        basis.calls = []
2304
        # ask for in non-topological order
2305
        records = list(test.get_record_stream(
2306
            [key, key_basis, key_missing, key_basis_2], 'topological', True))
2307
        self.assertEqual(4, len(records))
2308
        results = []
2309
        for record in records:
2310
            self.assertSubset([record.key],
2311
                (key_basis, key_missing, key_basis_2, key))
2312
            if record.key == key_missing:
2313
                self.assertIsInstance(record, AbsentContentFactory)
2314
            else:
2315
                results.append((record.key, record.sha1, record.storage_kind,
2316
                    record.get_bytes_as('fulltext')))
2317
        calls = list(basis.calls)
2318
        order = [record[0] for record in results]
2319
        self.assertEqual([key_basis_2, key_basis, key], order)
2320
        for result in results:
2321
            if result[0] == key:
2322
                source = test
2323
            else:
2324
                source = basis
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
2325
            record = next(source.get_record_stream([result[0]], 'unordered',
2326
                True))
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2327
            self.assertEqual(record.key, result[0])
2328
            self.assertEqual(record.sha1, result[1])
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2329
            # We used to check that the storage kind matched, but actually it
2330
            # depends on whether it was sourced from the basis, or in a single
2331
            # group, because asking for full texts returns proxy objects to a
2332
            # _ContentMapGenerator object; so checking the kind is unneeded.
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2333
            self.assertEqual(record.get_bytes_as('fulltext'), result[3])
3350.8.14 by Robert Collins
Review feedback.
2334
        # It's not strictly minimal, but it seems reasonable for now for it to
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2335
        # ask which fallbacks have which parents.
6973.7.8 by Jelmer Vernooij
Fix more tests.
2336
        self.assertEqual(2, len(calls))
2337
        self.assertEqual(
6997 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-f
2338
                ("get_parent_map", {key_basis, key_basis_2, key_missing}),
2339
                calls[0])
2340
        # topological is requested from the fallback, because that is what
2341
        # was requested at the top level.
2342
        self.assertIn(
2343
                calls[1], [
2344
                ("get_record_stream", [key_basis_2, key_basis], 'topological', True),
2345
                ("get_record_stream", [key_basis, key_basis_2], 'topological', True)])
3350.8.7 by Robert Collins
get_record_stream for fulltexts working (but note extreme memory use!).
2346
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2347
    def test_get_record_stream_unordered_deltas(self):
2348
        # records from the test knit are answered without asking the basis:
2349
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2350
        key = (b'foo',)
2351
        key_basis = (b'bar',)
2352
        key_missing = (b'missing',)
2353
        test.add_lines(key, (), [b'foo\n'])
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2354
        records = list(test.get_record_stream([key], 'unordered', False))
2355
        self.assertEqual(1, len(records))
2356
        self.assertEqual([], basis.calls)
2357
        # Missing (from test knit) objects are retrieved from the basis:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2358
        basis.add_lines(key_basis, (), [b'foo\n', b'bar\n'])
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2359
        basis.calls = []
2360
        records = list(test.get_record_stream([key_basis, key_missing],
2361
            'unordered', False))
2362
        self.assertEqual(2, len(records))
2363
        calls = list(basis.calls)
2364
        for record in records:
2365
            self.assertSubset([record.key], (key_basis, key_missing))
2366
            if record.key == key_missing:
2367
                self.assertIsInstance(record, AbsentContentFactory)
2368
            else:
2369
                reference = list(basis.get_record_stream([key_basis],
2370
                    'unordered', False))[0]
2371
                self.assertEqual(reference.key, record.key)
2372
                self.assertEqual(reference.sha1, record.sha1)
2373
                self.assertEqual(reference.storage_kind, record.storage_kind)
2374
                self.assertEqual(reference.get_bytes_as(reference.storage_kind),
2375
                    record.get_bytes_as(record.storage_kind))
3350.8.14 by Robert Collins
Review feedback.
2376
        # It's not strictly minimal, but it seems reasonable for now for it to
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2377
        # ask which fallbacks have which parents.
2378
        self.assertEqual([
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2379
            ("get_parent_map", {key_basis, key_missing}),
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2380
            ("get_record_stream", [key_basis], 'unordered', False)],
2381
            calls)
2382
2383
    def test_get_record_stream_ordered_deltas(self):
2384
        # ordering is preserved down into the fallback store.
2385
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2386
        key = (b'foo',)
2387
        key_basis = (b'bar',)
2388
        key_basis_2 = (b'quux',)
2389
        key_missing = (b'missing',)
2390
        test.add_lines(key, (key_basis,), [b'foo\n'])
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2391
        # Missing (from test knit) objects are retrieved from the basis:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2392
        basis.add_lines(key_basis, (key_basis_2,), [b'foo\n', b'bar\n'])
2393
        basis.add_lines(key_basis_2, (), [b'quux\n'])
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2394
        basis.calls = []
2395
        # ask for in non-topological order
2396
        records = list(test.get_record_stream(
2397
            [key, key_basis, key_missing, key_basis_2], 'topological', False))
2398
        self.assertEqual(4, len(records))
2399
        results = []
2400
        for record in records:
2401
            self.assertSubset([record.key],
2402
                (key_basis, key_missing, key_basis_2, key))
2403
            if record.key == key_missing:
2404
                self.assertIsInstance(record, AbsentContentFactory)
2405
            else:
2406
                results.append((record.key, record.sha1, record.storage_kind,
2407
                    record.get_bytes_as(record.storage_kind)))
2408
        calls = list(basis.calls)
2409
        order = [record[0] for record in results]
2410
        self.assertEqual([key_basis_2, key_basis, key], order)
2411
        for result in results:
2412
            if result[0] == key:
2413
                source = test
2414
            else:
2415
                source = basis
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
2416
            record = next(source.get_record_stream([result[0]], 'unordered',
2417
                False))
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2418
            self.assertEqual(record.key, result[0])
2419
            self.assertEqual(record.sha1, result[1])
2420
            self.assertEqual(record.storage_kind, result[2])
2421
            self.assertEqual(record.get_bytes_as(record.storage_kind), result[3])
3350.8.14 by Robert Collins
Review feedback.
2422
        # It's not strictly minimal, but it seems reasonable for now for it to
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2423
        # ask which fallbacks have which parents.
2424
        self.assertEqual([
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2425
            ("get_parent_map", {key_basis, key_basis_2, key_missing}),
3350.8.6 by Robert Collins
get_record_stream stacking for delta access.
2426
            ("get_record_stream", [key_basis_2, key_basis], 'topological', False)],
2427
            calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2428
2429
    def test_get_sha1s(self):
3350.8.3 by Robert Collins
VF.get_sha1s needed changing to be stackable.
2430
        # sha1's in the test knit are answered without asking the basis
2431
        basis, test = self.get_basis_and_test_knit()
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2432
        key = (b'foo',)
2433
        key_basis = (b'bar',)
2434
        key_missing = (b'missing',)
2435
        test.add_lines(key, (), [b'foo\n'])
2436
        key_sha1sum = osutils.sha_string(b'foo\n')
3350.8.3 by Robert Collins
VF.get_sha1s needed changing to be stackable.
2437
        sha1s = test.get_sha1s([key])
2438
        self.assertEqual({key: key_sha1sum}, sha1s)
2439
        self.assertEqual([], basis.calls)
2440
        # But texts that are not in the test knit are looked for in the basis
2441
        # directly (rather than via text reconstruction) so that remote servers
2442
        # etc don't have to answer with full content.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2443
        basis.add_lines(key_basis, (), [b'foo\n', b'bar\n'])
2444
        basis_sha1sum = osutils.sha_string(b'foo\nbar\n')
3350.8.3 by Robert Collins
VF.get_sha1s needed changing to be stackable.
2445
        basis.calls = []
2446
        sha1s = test.get_sha1s([key, key_missing, key_basis])
2447
        self.assertEqual({key: key_sha1sum,
2448
            key_basis: basis_sha1sum}, sha1s)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2449
        self.assertEqual([("get_sha1s", {key_basis, key_missing})],
3350.8.3 by Robert Collins
VF.get_sha1s needed changing to be stackable.
2450
            basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2451
2452
    def test_insert_record_stream(self):
3350.8.10 by Robert Collins
Stacked insert_record_stream.
2453
        # records are inserted as normal; insert_record_stream builds on
3350.8.14 by Robert Collins
Review feedback.
2454
        # add_lines, so a smoke test should be all that's needed:
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2455
        key = (b'foo',)
2456
        key_basis = (b'bar',)
2457
        key_delta = (b'zaphod',)
3350.8.10 by Robert Collins
Stacked insert_record_stream.
2458
        basis, test = self.get_basis_and_test_knit()
2459
        source = self.make_test_knit(name='source')
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2460
        basis.add_lines(key_basis, (), [b'foo\n'])
3350.8.10 by Robert Collins
Stacked insert_record_stream.
2461
        basis.calls = []
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2462
        source.add_lines(key_basis, (), [b'foo\n'])
2463
        source.add_lines(key_delta, (key_basis,), [b'bar\n'])
3350.8.10 by Robert Collins
Stacked insert_record_stream.
2464
        stream = source.get_record_stream([key_delta], 'unordered', False)
2465
        test.insert_record_stream(stream)
3830.3.9 by Martin Pool
Simplify kvf insert_record_stream; add has_key shorthand methods; update stacking effort tests
2466
        # XXX: this does somewhat too many calls in making sure of whether it
2467
        # has to recreate the full text.
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2468
        self.assertEqual([("get_parent_map", {key_basis}),
2469
             ('get_parent_map', {key_basis}),
3830.3.10 by Martin Pool
Update more stacking effort tests
2470
             ('get_record_stream', [key_basis], 'unordered', True)],
3350.8.10 by Robert Collins
Stacked insert_record_stream.
2471
            basis.calls)
2472
        self.assertEqual({key_delta:(key_basis,)},
2473
            test.get_parent_map([key_delta]))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2474
        self.assertEqual(b'bar\n', next(test.get_record_stream([key_delta],
2475
            'unordered', True)).get_bytes_as('fulltext'))
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2476
2477
    def test_iter_lines_added_or_present_in_keys(self):
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2478
        # Lines from the basis are returned, and lines for a given key are only
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
2479
        # returned once.
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2480
        key1 = (b'foo1',)
2481
        key2 = (b'foo2',)
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2482
        # all sources are asked for keys:
2483
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2484
        basis.add_lines(key1, (), [b"foo"])
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2485
        basis.calls = []
2486
        lines = list(test.iter_lines_added_or_present_in_keys([key1]))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2487
        self.assertEqual([(b"foo\n", key1)], lines)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2488
        self.assertEqual([("iter_lines_added_or_present_in_keys", {key1})],
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2489
            basis.calls)
2490
        # keys in both are not duplicated:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2491
        test.add_lines(key2, (), [b"bar\n"])
2492
        basis.add_lines(key2, (), [b"bar\n"])
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2493
        basis.calls = []
2494
        lines = list(test.iter_lines_added_or_present_in_keys([key2]))
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2495
        self.assertEqual([(b"bar\n", key2)], lines)
3350.8.5 by Robert Collins
Iter_lines_added_or_present_in_keys stacks.
2496
        self.assertEqual([], basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2497
2498
    def test_keys(self):
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2499
        key1 = (b'foo1',)
2500
        key2 = (b'foo2',)
3350.8.4 by Robert Collins
Vf.keys() stacking support.
2501
        # all sources are asked for keys:
2502
        basis, test = self.get_basis_and_test_knit()
2503
        keys = test.keys()
2504
        self.assertEqual(set(), set(keys))
2505
        self.assertEqual([("keys",)], basis.calls)
2506
        # keys from a basis are returned:
2507
        basis.add_lines(key1, (), [])
2508
        basis.calls = []
2509
        keys = test.keys()
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2510
        self.assertEqual({key1}, set(keys))
3350.8.4 by Robert Collins
Vf.keys() stacking support.
2511
        self.assertEqual([("keys",)], basis.calls)
2512
        # keys in both are not duplicated:
2513
        test.add_lines(key2, (), [])
2514
        basis.add_lines(key2, (), [])
2515
        basis.calls = []
2516
        keys = test.keys()
2517
        self.assertEqual(2, len(keys))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2518
        self.assertEqual({key1, key2}, set(keys))
3350.8.4 by Robert Collins
Vf.keys() stacking support.
2519
        self.assertEqual([("keys",)], basis.calls)
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2520
2521
    def test_add_mpdiffs(self):
3350.8.11 by Robert Collins
Stacked add_mpdiffs.
2522
        # records are inserted as normal; add_mpdiff builds on
3350.8.14 by Robert Collins
Review feedback.
2523
        # add_lines, so a smoke test should be all that's needed:
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2524
        key = (b'foo',)
2525
        key_basis = (b'bar',)
2526
        key_delta = (b'zaphod',)
3350.8.11 by Robert Collins
Stacked add_mpdiffs.
2527
        basis, test = self.get_basis_and_test_knit()
2528
        source = self.make_test_knit(name='source')
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2529
        basis.add_lines(key_basis, (), [b'foo\n'])
3350.8.11 by Robert Collins
Stacked add_mpdiffs.
2530
        basis.calls = []
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2531
        source.add_lines(key_basis, (), [b'foo\n'])
2532
        source.add_lines(key_delta, (key_basis,), [b'bar\n'])
3350.8.11 by Robert Collins
Stacked add_mpdiffs.
2533
        diffs = source.make_mpdiffs([key_delta])
2534
        test.add_mpdiffs([(key_delta, (key_basis,),
2535
            source.get_sha1s([key_delta])[key_delta], diffs[0])])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2536
        self.assertEqual([("get_parent_map", {key_basis}),
3830.3.10 by Martin Pool
Update more stacking effort tests
2537
            ('get_record_stream', [key_basis], 'unordered', True),],
3350.8.11 by Robert Collins
Stacked add_mpdiffs.
2538
            basis.calls)
2539
        self.assertEqual({key_delta:(key_basis,)},
2540
            test.get_parent_map([key_delta]))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2541
        self.assertEqual(b'bar\n', next(test.get_record_stream([key_delta],
2542
            'unordered', True)).get_bytes_as('fulltext'))
3350.8.1 by Robert Collins
KnitVersionedFiles.add_fallback_versioned_files exists.
2543
2544
    def test_make_mpdiffs(self):
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2545
        # Generating an mpdiff across a stacking boundary should detect parent
2546
        # texts regions.
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2547
        key = (b'foo',)
2548
        key_left = (b'bar',)
2549
        key_right = (b'zaphod',)
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2550
        basis, test = self.get_basis_and_test_knit()
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2551
        basis.add_lines(key_left, (), [b'bar\n'])
2552
        basis.add_lines(key_right, (), [b'zaphod\n'])
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2553
        basis.calls = []
2554
        test.add_lines(key, (key_left, key_right),
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2555
            [b'bar\n', b'foo\n', b'zaphod\n'])
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2556
        diffs = test.make_mpdiffs([key])
2557
        self.assertEqual([
2558
            multiparent.MultiParent([multiparent.ParentText(0, 0, 0, 1),
6985 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-weave-fmt.
2559
                multiparent.NewText([b'foo\n']),
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2560
                multiparent.ParentText(1, 0, 2, 1)])],
2561
            diffs)
3830.3.10 by Martin Pool
Update more stacking effort tests
2562
        self.assertEqual(3, len(basis.calls))
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2563
        self.assertEqual([
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2564
            ("get_parent_map", {key_left, key_right}),
2565
            ("get_parent_map", {key_left, key_right}),
3350.8.12 by Robert Collins
Stacked make_mpdiffs.
2566
            ],
3830.3.10 by Martin Pool
Update more stacking effort tests
2567
            basis.calls[:-1])
2568
        last_call = basis.calls[-1]
3350.8.14 by Robert Collins
Review feedback.
2569
        self.assertEqual('get_record_stream', last_call[0])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
2570
        self.assertEqual({key_left, key_right}, set(last_call[1]))
4537.3.5 by John Arbash Meinel
Fix 3 tests that assumed it would use 'unordered' in the fallback,
2571
        self.assertEqual('topological', last_call[2])
3350.8.14 by Robert Collins
Review feedback.
2572
        self.assertEqual(True, last_call[3])
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2573
2574
2575
class TestNetworkBehaviour(KnitTests):
2576
    """Tests for getting data out of/into knits over the network."""
2577
2578
    def test_include_delta_closure_generates_a_knit_delta_closure(self):
2579
        vf = self.make_test_knit(name='test')
2580
        # put in three texts, giving ft, delta, delta
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2581
        vf.add_lines((b'base',), (), [b'base\n', b'content\n'])
2582
        vf.add_lines((b'd1',), ((b'base',),), [b'd1\n'])
2583
        vf.add_lines((b'd2',), ((b'd1',),), [b'd2\n'])
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2584
        # But heuristics could interfere, so check what happened:
2585
        self.assertEqual(['knit-ft-gz', 'knit-delta-gz', 'knit-delta-gz'],
2586
            [record.storage_kind for record in
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2587
             vf.get_record_stream([(b'base',), (b'd1',), (b'd2',)],
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2588
                'topological', False)])
2589
        # generate a stream of just the deltas include_delta_closure=True,
2590
        # serialise to the network, and check that we get a delta closure on the wire.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2591
        stream = vf.get_record_stream([(b'd1',), (b'd2',)], 'topological', True)
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2592
        netb = [record.get_bytes_as(record.storage_kind) for record in stream]
2593
        # The first bytes should be a memo from _ContentMapGenerator, and the
2594
        # second bytes should be empty (because its a API proxy not something
2595
        # for wire serialisation.
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2596
        self.assertEqual(b'', netb[1])
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2597
        bytes = netb[0]
2598
        kind, line_end = network_bytes_to_kind_and_offset(bytes)
2599
        self.assertEqual('knit-delta-closure', kind)
2600
2601
2602
class TestContentMapGenerator(KnitTests):
2603
    """Tests for ContentMapGenerator"""
2604
2605
    def test_get_record_stream_gives_records(self):
2606
        vf = self.make_test_knit(name='test')
2607
        # put in three texts, giving ft, delta, delta
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2608
        vf.add_lines((b'base',), (), [b'base\n', b'content\n'])
2609
        vf.add_lines((b'd1',), ((b'base',),), [b'd1\n'])
2610
        vf.add_lines((b'd2',), ((b'd1',),), [b'd2\n'])
2611
        keys = [(b'd1',), (b'd2',)]
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2612
        generator = _VFContentMapGenerator(vf, keys,
2613
            global_map=vf.get_parent_map(keys))
2614
        for record in generator.get_record_stream():
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2615
            if record.key == (b'd1',):
2616
                self.assertEqual(b'd1\n', record.get_bytes_as('fulltext'))
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2617
            else:
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2618
                self.assertEqual(b'd2\n', record.get_bytes_as('fulltext'))
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2619
2620
    def test_get_record_stream_kinds_are_raw(self):
2621
        vf = self.make_test_knit(name='test')
2622
        # put in three texts, giving ft, delta, delta
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2623
        vf.add_lines((b'base',), (), [b'base\n', b'content\n'])
2624
        vf.add_lines((b'd1',), ((b'base',),), [b'd1\n'])
2625
        vf.add_lines((b'd2',), ((b'd1',),), [b'd2\n'])
2626
        keys = [(b'base',), (b'd1',), (b'd2',)]
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2627
        generator = _VFContentMapGenerator(vf, keys,
2628
            global_map=vf.get_parent_map(keys))
6973.14.2 by Jelmer Vernooij
Fix some knit tests.
2629
        kinds = {(b'base',): 'knit-delta-closure',
2630
            (b'd1',): 'knit-delta-closure-ref',
2631
            (b'd2',): 'knit-delta-closure-ref',
4005.3.6 by Robert Collins
Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.
2632
            }
2633
        for record in generator.get_record_stream():
2634
            self.assertEqual(kinds[record.key], record.storage_kind)