/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2008-2011 Canonical Ltd
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
2
#
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
3
# This program is free software; you can redistribute it and/or modify
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
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
#
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
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.
3735.31.2 by John Arbash Meinel
Cleanup trailing whitespace, get test_source to pass by removing asserts.
12
#
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
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
3735.36.3 by John Arbash Meinel
Add the new address for FSF to the new files.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.17.1 by Robert Collins
Starting point. Interface tests hooked up and failing.
16
17
"""Tests for group compression."""
18
19
import zlib
20
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
21
from .. import (
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
22
    config,
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
23
    errors,
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
24
    osutils,
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
25
    tests,
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
26
    trace,
6670.4.1 by Jelmer Vernooij
Update imports.
27
    )
28
from ..bzr import (
29
    btree_index,
30
    groupcompress,
6744 by Jelmer Vernooij
Merge lp:~jelmer/brz/move-errors-knit.
31
    knit,
6670.4.1 by Jelmer Vernooij
Update imports.
32
    index as _mod_index,
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
33
    versionedfile,
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
34
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
35
from ..osutils import sha_string
36
from .test__groupcompress import compiled_groupcompress_feature
37
from .scenarios import load_tests_apply_scenarios
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
38
39
40
def group_compress_implementation_scenarios():
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
41
    scenarios = [
42
        ('python', {'compressor': groupcompress.PythonGroupCompressor}),
43
        ]
4913.2.24 by John Arbash Meinel
Track down a few more import typos.
44
    if compiled_groupcompress_feature.available():
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
45
        scenarios.append(('C',
7143.15.2 by Jelmer Vernooij
Run autopep8.
46
                          {'compressor': groupcompress.PyrexGroupCompressor}))
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
47
    return scenarios
48
49
50
load_tests = load_tests_apply_scenarios
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
51
52
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
53
class TestGroupCompressor(tests.TestCase):
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
54
55
    def _chunks_to_repr_lines(self, chunks):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
56
        return '\n'.join(map(repr, b''.join(chunks).split(b'\n')))
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
57
58
    def assertEqualDiffEncoded(self, expected, actual):
59
        """Compare the actual content to the expected content.
60
61
        :param expected: A group of chunks that we expect to see
62
        :param actual: The measured 'chunks'
63
64
        We will transform the chunks back into lines, and then run 'repr()'
65
        over them to handle non-ascii characters.
66
        """
67
        self.assertEqualDiff(self._chunks_to_repr_lines(expected),
68
                             self._chunks_to_repr_lines(actual))
69
70
71
class TestAllGroupCompressors(TestGroupCompressor):
0.17.2 by Robert Collins
Core proof of concept working.
72
    """Tests for GroupCompressor"""
73
5559.2.2 by Martin Pool
Change to using standard load_tests_apply_scenarios.
74
    scenarios = group_compress_implementation_scenarios()
7143.15.2 by Jelmer Vernooij
Run autopep8.
75
    compressor = None  # Set by scenario
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
76
0.17.2 by Robert Collins
Core proof of concept working.
77
    def test_empty_delta(self):
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
78
        compressor = self.compressor()
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
79
        self.assertEqual([], compressor.chunks)
0.17.2 by Robert Collins
Core proof of concept working.
80
81
    def test_one_nosha_delta(self):
82
        # diff against NUKK
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
83
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
84
        text = b'strange\ncommon\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
85
        sha1, start_point, end_point, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
86
            ('label',), [text], len(text), None)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
87
        self.assertEqual(sha_string(b'strange\ncommon\n'), sha1)
88
        expected_lines = b'f\x0fstrange\ncommon\n'
89
        self.assertEqual(expected_lines, b''.join(compressor.chunks))
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
90
        self.assertEqual(0, start_point)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
91
        self.assertEqual(len(expected_lines), end_point)
0.17.2 by Robert Collins
Core proof of concept working.
92
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
93
    def test_empty_content(self):
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
94
        compressor = self.compressor()
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
95
        # Adding empty bytes should return the 'null' record
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
96
        sha1, start_point, end_point, kind = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
97
            ('empty',), [], 0, None)
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
98
        self.assertEqual(0, start_point)
99
        self.assertEqual(0, end_point)
100
        self.assertEqual('fulltext', kind)
101
        self.assertEqual(groupcompress._null_sha1, sha1)
102
        self.assertEqual(0, compressor.endpoint)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
103
        self.assertEqual([], compressor.chunks)
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
104
        # Even after adding some content
7463.2.2 by Jelmer Vernooij
Fix tests.
105
        text = b'some\nbytes\n'
106
        compressor.compress(('content',), [text], len(text), None)
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
107
        self.assertTrue(compressor.endpoint > 0)
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
108
        sha1, start_point, end_point, kind = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
109
            ('empty2',), [], 0, None)
3735.2.162 by John Arbash Meinel
Change GroupCompressor.compress() to return the start_point.
110
        self.assertEqual(0, start_point)
111
        self.assertEqual(0, end_point)
112
        self.assertEqual('fulltext', kind)
113
        self.assertEqual(groupcompress._null_sha1, sha1)
114
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
115
    def test_extract_from_compressor(self):
116
        # Knit fetching will try to reconstruct texts locally which results in
117
        # reading something that is in the compressor stream already.
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
118
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
119
        text = b'strange\ncommon long line\nthat needs a 16 byte match\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
120
        sha1_1, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
121
            ('label',), [text], len(text), None)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
122
        expected_lines = list(compressor.chunks)
7463.2.2 by Jelmer Vernooij
Fix tests.
123
        text = b'common long line\nthat needs a 16 byte match\ndifferent\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
124
        sha1_2, _, end_point, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
125
            ('newlabel',), [text], len(text), None)
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
126
        # get the first out
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
127
        self.assertEqual((b'strange\ncommon long line\n'
128
                          b'that needs a 16 byte match\n', sha1_1),
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
129
                         compressor.extract(('label',)))
0.17.11 by Robert Collins
Add extraction of just-compressed texts to support converting from knits.
130
        # and the second
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
131
        self.assertEqual((b'common long line\nthat needs a 16 byte match\n'
132
                          b'different\n', sha1_2),
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
133
                         compressor.extract(('newlabel',)))
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
134
4241.17.2 by John Arbash Meinel
PythonGroupCompressor needs to support pop_last() properly.
135
    def test_pop_last(self):
136
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
137
        text = b'some text\nfor the first entry\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
138
        _, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
139
            ('key1',), [text], len(text), None)
4241.17.2 by John Arbash Meinel
PythonGroupCompressor needs to support pop_last() properly.
140
        expected_lines = list(compressor.chunks)
7463.2.2 by Jelmer Vernooij
Fix tests.
141
        text = b'some text\nfor the second entry\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
142
        _, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
143
            ('key2',), [text], len(text), None)
4241.17.2 by John Arbash Meinel
PythonGroupCompressor needs to support pop_last() properly.
144
        compressor.pop_last()
145
        self.assertEqual(expected_lines, compressor.chunks)
146
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
147
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
148
class TestPyrexGroupCompressor(TestGroupCompressor):
149
4913.2.24 by John Arbash Meinel
Track down a few more import typos.
150
    _test_needs_features = [compiled_groupcompress_feature]
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
151
    compressor = groupcompress.PyrexGroupCompressor
152
153
    def test_stats(self):
154
        compressor = self.compressor()
7463.2.3 by Jelmer Vernooij
Fix tests.
155
        chunks = [b'strange\n',
156
                  b'common very very long line\n',
157
                  b'plus more text\n']
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
158
        compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
159
            ('label',), chunks, sum(map(len, chunks)), None)
160
        chunks = [
161
            b'common very very long line\n',
162
            b'plus more text\n',
163
            b'different\n',
164
            b'moredifferent\n']
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
165
        compressor.compress(
166
            ('newlabel',),
7463.2.3 by Jelmer Vernooij
Fix tests.
167
            chunks, sum(map(len, chunks)), None)
168
        chunks = [
169
            b'new\n',
170
            b'common very very long line\n',
171
            b'plus more text\n',
172
            b'different\n',
173
            b'moredifferent\n']
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
174
        compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
175
            ('label3',), chunks, sum(map(len, chunks)), None)
3735.40.7 by John Arbash Meinel
Move even more functionality into EquivalenceTable.
176
        self.assertAlmostEqual(1.9, compressor.ratio(), 1)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
177
178
    def test_two_nosha_delta(self):
179
        compressor = self.compressor()
7463.2.3 by Jelmer Vernooij
Fix tests.
180
        text = b'strange\ncommon long line\nthat needs a 16 byte match\n'
181
        sha1_1, _, _, _ = compressor.compress(('label',), [text], len(text), None)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
182
        expected_lines = list(compressor.chunks)
7463.2.3 by Jelmer Vernooij
Fix tests.
183
        text = b'common long line\nthat needs a 16 byte match\ndifferent\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
184
        sha1_2, start_point, end_point, _ = compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
185
            ('newlabel',), [text], len(text), None)
186
        self.assertEqual(sha_string(text), sha1_2)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
187
        expected_lines.extend([
188
            # 'delta', delta length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
189
            b'd\x0f',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
190
            # source and target length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
191
            b'\x36',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
192
            # copy the line common
7143.15.2 by Jelmer Vernooij
Run autopep8.
193
            b'\x91\x0a\x2c',  # copy, offset 0x0a, len 0x2c
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
194
            # add the line different, and the trailing newline
7143.15.2 by Jelmer Vernooij
Run autopep8.
195
            b'\x0adifferent\n',  # insert 10 bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
196
            ])
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
197
        self.assertEqualDiffEncoded(expected_lines, compressor.chunks)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
198
        self.assertEqual(sum(map(len, expected_lines)), end_point)
199
200
    def test_three_nosha_delta(self):
201
        # The first interesting test: make a change that should use lines from
202
        # both parents.
203
        compressor = self.compressor()
7463.2.3 by Jelmer Vernooij
Fix tests.
204
        text = b'strange\ncommon very very long line\nwith some extra text\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
205
        sha1_1, _, _, _ = compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
206
            ('label',), [text], len(text), None)
207
        text = b'different\nmoredifferent\nand then some more\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
208
        sha1_2, _, _, _ = compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
209
            ('newlabel',), [text], len(text), None)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
210
        expected_lines = list(compressor.chunks)
7463.2.3 by Jelmer Vernooij
Fix tests.
211
        text = (b'new\ncommon very very long line\nwith some extra text\n'
212
                b'different\nmoredifferent\nand then some more\n')
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
213
        sha1_3, start_point, end_point, _ = compressor.compress(
7463.2.3 by Jelmer Vernooij
Fix tests.
214
            ('label3',), [text], len(text), None)
215
        self.assertEqual(sha_string(text), sha1_3)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
216
        expected_lines.extend([
217
            # 'delta', delta length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
218
            b'd\x0b',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
219
            # source and target length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
220
            b'\x5f'
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
221
            # insert new
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
222
            b'\x03new',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
223
            # Copy of first parent 'common' range
7143.15.2 by Jelmer Vernooij
Run autopep8.
224
            b'\x91\x09\x31'  # copy, offset 0x09, 0x31 bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
225
            # Copy of second parent 'different' range
7143.15.2 by Jelmer Vernooij
Run autopep8.
226
            b'\x91\x3c\x2b'  # copy, offset 0x3c, 0x2b bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
227
            ])
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
228
        self.assertEqualDiffEncoded(expected_lines, compressor.chunks)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
229
        self.assertEqual(sum(map(len, expected_lines)), end_point)
230
231
232
class TestPythonGroupCompressor(TestGroupCompressor):
233
234
    compressor = groupcompress.PythonGroupCompressor
235
236
    def test_stats(self):
237
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
238
        chunks = [b'strange\n',
239
                  b'common very very long line\n',
240
                  b'plus more text\n']
241
        compressor.compress(
242
            ('label',), chunks, sum(map(len, chunks)), None)
243
        chunks = [
244
            b'common very very long line\n',
245
            b'plus more text\n',
246
            b'different\n',
247
            b'moredifferent\n']
248
        compressor.compress(
249
            ('newlabel',), chunks, sum(map(len, chunks)), None)
250
        chunks = [
251
            b'new\n',
252
            b'common very very long line\n',
253
            b'plus more text\n',
254
            b'different\n',
255
            b'moredifferent\n']
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
256
        compressor.compress(
7459.2.3 by Jelmer Vernooij
Fix flake8.
257
            ('label3',),
7463.2.2 by Jelmer Vernooij
Fix tests.
258
            chunks, sum(map(len, chunks)), None)
3735.40.7 by John Arbash Meinel
Move even more functionality into EquivalenceTable.
259
        self.assertAlmostEqual(1.9, compressor.ratio(), 1)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
260
261
    def test_two_nosha_delta(self):
262
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
263
        text = b'strange\ncommon long line\nthat needs a 16 byte match\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
264
        sha1_1, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
265
            ('label',), [text], len(text), None)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
266
        expected_lines = list(compressor.chunks)
7463.2.2 by Jelmer Vernooij
Fix tests.
267
        text = b'common long line\nthat needs a 16 byte match\ndifferent\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
268
        sha1_2, start_point, end_point, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
269
            ('newlabel',), [text], len(text), None)
270
        self.assertEqual(sha_string(text), sha1_2)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
271
        expected_lines.extend([
272
            # 'delta', delta length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
273
            b'd\x0f',
3735.40.10 by John Arbash Meinel
Merge in the new delta format code.
274
            # target length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
275
            b'\x36',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
276
            # copy the line common
7143.15.2 by Jelmer Vernooij
Run autopep8.
277
            b'\x91\x0a\x2c',  # copy, offset 0x0a, len 0x2c
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
278
            # add the line different, and the trailing newline
7143.15.2 by Jelmer Vernooij
Run autopep8.
279
            b'\x0adifferent\n',  # insert 10 bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
280
            ])
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
281
        self.assertEqualDiffEncoded(expected_lines, compressor.chunks)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
282
        self.assertEqual(sum(map(len, expected_lines)), end_point)
283
284
    def test_three_nosha_delta(self):
285
        # The first interesting test: make a change that should use lines from
286
        # both parents.
287
        compressor = self.compressor()
7463.2.2 by Jelmer Vernooij
Fix tests.
288
        text = b'strange\ncommon very very long line\nwith some extra text\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
289
        sha1_1, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
290
            ('label',), [text], len(text), None)
291
        text = b'different\nmoredifferent\nand then some more\n'
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
292
        sha1_2, _, _, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
293
            ('newlabel',), [text], len(text), None)
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
294
        expected_lines = list(compressor.chunks)
7463.2.2 by Jelmer Vernooij
Fix tests.
295
        text = (b'new\ncommon very very long line\nwith some extra text\n'
296
                b'different\nmoredifferent\nand then some more\n')
7459.2.1 by Jelmer Vernooij
Pass chunks to compress().
297
        sha1_3, start_point, end_point, _ = compressor.compress(
7463.2.2 by Jelmer Vernooij
Fix tests.
298
            ('label3',), [text], len(text), None)
299
        self.assertEqual(sha_string(text), sha1_3)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
300
        expected_lines.extend([
301
            # 'delta', delta length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
302
            b'd\x0c',
3735.40.10 by John Arbash Meinel
Merge in the new delta format code.
303
            # target length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
304
            b'\x5f'
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
305
            # insert new
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
306
            b'\x04new\n',
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
307
            # Copy of first parent 'common' range
7143.15.2 by Jelmer Vernooij
Run autopep8.
308
            b'\x91\x0a\x30'  # copy, offset 0x0a, 0x30 bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
309
            # Copy of second parent 'different' range
7143.15.2 by Jelmer Vernooij
Run autopep8.
310
            b'\x91\x3c\x2b'  # copy, offset 0x3c, 0x2b bytes
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
311
            ])
3735.40.17 by John Arbash Meinel
Change the attribute from 'lines' to 'chunks' to make it more
312
        self.assertEqualDiffEncoded(expected_lines, compressor.chunks)
3735.40.4 by John Arbash Meinel
Factor out tests that rely on the exact bytecode.
313
        self.assertEqual(sum(map(len, expected_lines)), end_point)
314
315
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
316
class TestGroupCompressBlock(tests.TestCase):
317
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
318
    def make_block(self, key_to_text):
319
        """Create a GroupCompressBlock, filling it with the given texts."""
320
        compressor = groupcompress.GroupCompressor()
321
        start = 0
322
        for key in sorted(key_to_text):
7463.2.2 by Jelmer Vernooij
Fix tests.
323
            compressor.compress(
324
                key, [key_to_text[key]], len(key_to_text[key]), None)
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
325
        locs = dict((key, (start, end)) for key, (start, _, end, _)
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
326
                    in compressor.labels_deltas.items())
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
327
        block = compressor.flush()
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
328
        raw_bytes = block.to_bytes()
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
329
        # Go through from_bytes(to_bytes()) so that we start with a compressed
330
        # content object
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
331
        return locs, groupcompress.GroupCompressBlock.from_bytes(raw_bytes)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
332
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
333
    def test_from_empty_bytes(self):
3735.31.1 by John Arbash Meinel
Bring the groupcompress plugin into the brisbane-core branch.
334
        self.assertRaises(ValueError,
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
335
                          groupcompress.GroupCompressBlock.from_bytes, b'')
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
336
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
337
    def test_from_minimal_bytes(self):
3735.32.4 by John Arbash Meinel
Change the byte representation of a groupcompress block.
338
        block = groupcompress.GroupCompressBlock.from_bytes(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
339
            b'gcb1z\n0\n0\n')
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
340
        self.assertIsInstance(block, groupcompress.GroupCompressBlock)
3735.32.6 by John Arbash Meinel
A bit of reworking changes things so content is expanded at extract() time.
341
        self.assertIs(None, block._content)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
342
        self.assertEqual(b'', block._z_content)
3735.32.6 by John Arbash Meinel
A bit of reworking changes things so content is expanded at extract() time.
343
        block._ensure_content()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
344
        self.assertEqual(b'', block._content)
345
        self.assertEqual(b'', block._z_content)
7143.15.2 by Jelmer Vernooij
Run autopep8.
346
        block._ensure_content()  # Ensure content is safe to call 2x
0.25.4 by John Arbash Meinel
We at least have the rudimentary ability to encode and decode values.
347
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
348
    def test_from_invalid(self):
349
        self.assertRaises(ValueError,
350
                          groupcompress.GroupCompressBlock.from_bytes,
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
351
                          b'this is not a valid header')
4241.6.6 by Robert Collins, John Arbash Meinel, Ian Clathworthy, Vincent Ladeuil
Groupcompress from brisbane-core.
352
3735.38.4 by John Arbash Meinel
Another disk format change.
353
    def test_from_bytes(self):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
354
        content = (b'a tiny bit of content\n')
3735.32.4 by John Arbash Meinel
Change the byte representation of a groupcompress block.
355
        z_content = zlib.compress(content)
356
        z_bytes = (
7143.15.2 by Jelmer Vernooij
Run autopep8.
357
            b'gcb1z\n'  # group compress block v1 plain
358
            b'%d\n'  # Length of compressed content
359
            b'%d\n'  # Length of uncompressed content
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
360
            b'%s'   # Compressed content
3735.38.4 by John Arbash Meinel
Another disk format change.
361
            ) % (len(z_content), len(content), z_content)
0.25.6 by John Arbash Meinel
(tests broken) implement the basic ability to have a separate header
362
        block = groupcompress.GroupCompressBlock.from_bytes(
3735.32.4 by John Arbash Meinel
Change the byte representation of a groupcompress block.
363
            z_bytes)
3735.32.6 by John Arbash Meinel
A bit of reworking changes things so content is expanded at extract() time.
364
        self.assertEqual(z_content, block._z_content)
365
        self.assertIs(None, block._content)
3735.38.4 by John Arbash Meinel
Another disk format change.
366
        self.assertEqual(len(z_content), block._z_content_length)
367
        self.assertEqual(len(content), block._content_length)
3735.32.10 by John Arbash Meinel
test that we support reading from the gc blocks that didn't have their lengths.
368
        block._ensure_content()
3735.32.27 by John Arbash Meinel
Have _LazyGroupContentManager pre-extract everything it holds.
369
        self.assertEqual(z_content, block._z_content)
3735.32.10 by John Arbash Meinel
test that we support reading from the gc blocks that didn't have their lengths.
370
        self.assertEqual(content, block._content)
371
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
372
    def test_to_chunks(self):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
373
        content_chunks = [b'this is some content\n',
374
                          b'this content will be compressed\n']
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
375
        content_len = sum(map(len, content_chunks))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
376
        content = b''.join(content_chunks)
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
377
        gcb = groupcompress.GroupCompressBlock()
378
        gcb.set_chunked_content(content_chunks, content_len)
379
        total_len, block_chunks = gcb.to_chunks()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
380
        block_bytes = b''.join(block_chunks)
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
381
        self.assertEqual(gcb._z_content_length, len(gcb._z_content))
382
        self.assertEqual(total_len, len(block_bytes))
383
        self.assertEqual(gcb._content_length, content_len)
7143.15.2 by Jelmer Vernooij
Run autopep8.
384
        expected_header = (b'gcb1z\n'  # group compress block v1 zlib
385
                           b'%d\n'  # Length of compressed content
386
                           b'%d\n'  # Length of uncompressed content
387
                           ) % (gcb._z_content_length, gcb._content_length)
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
388
        # The first chunk should be the header chunk. It is small, fixed size,
389
        # and there is no compelling reason to split it up
390
        self.assertEqual(expected_header, block_chunks[0])
391
        self.assertStartsWith(block_bytes, expected_header)
392
        remaining_bytes = block_bytes[len(expected_header):]
393
        raw_bytes = zlib.decompress(remaining_bytes)
394
        self.assertEqual(content, raw_bytes)
395
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
396
    def test_to_bytes(self):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
397
        content = (b'this is some content\n'
398
                   b'this content will be compressed\n')
0.25.2 by John Arbash Meinel
First cut at meta-info as text form.
399
        gcb = groupcompress.GroupCompressBlock()
3735.38.4 by John Arbash Meinel
Another disk format change.
400
        gcb.set_content(content)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
401
        data = gcb.to_bytes()
3735.38.4 by John Arbash Meinel
Another disk format change.
402
        self.assertEqual(gcb._z_content_length, len(gcb._z_content))
403
        self.assertEqual(gcb._content_length, len(content))
7143.15.2 by Jelmer Vernooij
Run autopep8.
404
        expected_header = (b'gcb1z\n'  # group compress block v1 zlib
405
                           b'%d\n'  # Length of compressed content
406
                           b'%d\n'  # Length of uncompressed content
407
                           ) % (gcb._z_content_length, gcb._content_length)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
408
        self.assertStartsWith(data, expected_header)
409
        remaining_bytes = data[len(expected_header):]
0.25.5 by John Arbash Meinel
Now using a zlib compressed format.
410
        raw_bytes = zlib.decompress(remaining_bytes)
3735.38.4 by John Arbash Meinel
Another disk format change.
411
        self.assertEqual(content, raw_bytes)
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
412
4469.1.1 by John Arbash Meinel
Add a set_content_chunked member to GroupCompressBlock.
413
        # we should get the same results if using the chunked version
414
        gcb = groupcompress.GroupCompressBlock()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
415
        gcb.set_chunked_content([b'this is some content\n'
416
                                 b'this content will be compressed\n'],
7143.15.2 by Jelmer Vernooij
Run autopep8.
417
                                len(content))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
418
        old_data = data
419
        data = gcb.to_bytes()
420
        self.assertEqual(old_data, data)
4469.1.1 by John Arbash Meinel
Add a set_content_chunked member to GroupCompressBlock.
421
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
422
    def test_partial_decomp(self):
423
        content_chunks = []
424
        # We need a sufficient amount of data so that zlib.decompress has
425
        # partial decompression to work with. Most auto-generated data
426
        # compresses a bit too well, we want a combination, so we combine a sha
427
        # hash with compressible data.
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
428
        for i in range(2048):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
429
            next_content = b'%d\nThis is a bit of duplicate text\n' % (i,)
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
430
            content_chunks.append(next_content)
431
            next_sha1 = osutils.sha_string(next_content)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
432
            content_chunks.append(next_sha1 + b'\n')
433
        content = b''.join(content_chunks)
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
434
        self.assertEqual(158634, len(content))
435
        z_content = zlib.compress(content)
436
        self.assertEqual(57182, len(z_content))
437
        block = groupcompress.GroupCompressBlock()
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
438
        block._z_content_chunks = (z_content,)
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
439
        block._z_content_length = len(z_content)
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
440
        block._compressor_name = 'zlib'
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
441
        block._content_length = 158634
442
        self.assertIs(None, block._content)
443
        block._ensure_content(100)
444
        self.assertIsNot(None, block._content)
445
        # We have decompressed at least 100 bytes
446
        self.assertTrue(len(block._content) >= 100)
447
        # We have not decompressed the whole content
448
        self.assertTrue(len(block._content) < 158634)
449
        self.assertEqualDiff(content[:len(block._content)], block._content)
450
        # ensuring content that we already have shouldn't cause any more data
451
        # to be extracted
452
        cur_len = len(block._content)
453
        block._ensure_content(cur_len - 10)
454
        self.assertEqual(cur_len, len(block._content))
455
        # Now we want a bit more content
456
        cur_len += 10
457
        block._ensure_content(cur_len)
458
        self.assertTrue(len(block._content) >= cur_len)
459
        self.assertTrue(len(block._content) < 158634)
460
        self.assertEqualDiff(content[:len(block._content)], block._content)
461
        # And now lets finish
462
        block._ensure_content(158634)
463
        self.assertEqualDiff(content, block._content)
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
464
        # And the decompressor is finalized
3735.32.7 by John Arbash Meinel
Implement partial decompression support.
465
        self.assertIs(None, block._z_content_decompressor)
466
4744.2.3 by John Arbash Meinel
change the GroupcompressBlock code a bit.
467
    def test__ensure_all_content(self):
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
468
        content_chunks = []
4744.2.3 by John Arbash Meinel
change the GroupcompressBlock code a bit.
469
        # We need a sufficient amount of data so that zlib.decompress has
470
        # partial decompression to work with. Most auto-generated data
471
        # compresses a bit too well, we want a combination, so we combine a sha
472
        # hash with compressible data.
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
473
        for i in range(2048):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
474
            next_content = b'%d\nThis is a bit of duplicate text\n' % (i,)
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
475
            content_chunks.append(next_content)
476
            next_sha1 = osutils.sha_string(next_content)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
477
            content_chunks.append(next_sha1 + b'\n')
478
        content = b''.join(content_chunks)
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
479
        self.assertEqual(158634, len(content))
480
        z_content = zlib.compress(content)
481
        self.assertEqual(57182, len(z_content))
482
        block = groupcompress.GroupCompressBlock()
5439.2.1 by John Arbash Meinel
Change GroupCompressBlock to work in self._z_compress_chunks
483
        block._z_content_chunks = (z_content,)
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
484
        block._z_content_length = len(z_content)
485
        block._compressor_name = 'zlib'
4744.2.3 by John Arbash Meinel
change the GroupcompressBlock code a bit.
486
        block._content_length = 158634
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
487
        self.assertIs(None, block._content)
4744.2.3 by John Arbash Meinel
change the GroupcompressBlock code a bit.
488
        # The first _ensure_content got all of the required data
489
        block._ensure_content(158634)
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
490
        self.assertEqualDiff(content, block._content)
4744.2.3 by John Arbash Meinel
change the GroupcompressBlock code a bit.
491
        # And we should have released the _z_content_decompressor since it was
492
        # fully consumed
3735.32.11 by John Arbash Meinel
Add tests for the ability to do partial decompression without knowing the final length.
493
        self.assertIs(None, block._z_content_decompressor)
494
4300.1.1 by John Arbash Meinel
Add the ability to convert a gc block into 'human readable' form.
495
    def test__dump(self):
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
496
        dup_content = b'some duplicate content\nwhich is sufficiently long\n'
497
        key_to_text = {(b'1',): dup_content + b'1 unique\n',
498
                       (b'2',): dup_content + b'2 extra special\n'}
4300.1.1 by John Arbash Meinel
Add the ability to convert a gc block into 'human readable' form.
499
        locs, block = self.make_block(key_to_text)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
500
        self.assertEqual([(b'f', len(key_to_text[(b'1',)])),
501
                          (b'd', 21, len(key_to_text[(b'2',)]),
502
                           [(b'c', 2, len(dup_content)),
503
                            (b'i', len(b'2 extra special\n'), b'')
7143.15.2 by Jelmer Vernooij
Run autopep8.
504
                            ]),
505
                          ], block._dump())
4300.1.1 by John Arbash Meinel
Add the ability to convert a gc block into 'human readable' form.
506
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
507
4744.2.5 by John Arbash Meinel
Change to a generic 'VersionedFiles.clear_cache()' api.
508
class TestCaseWithGroupCompressVersionedFiles(
509
        tests.TestCaseWithMemoryTransport):
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
510
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
511
    def make_test_vf(self, create_graph, keylength=1, do_cleanup=True,
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
512
                     dir='.', inconsistency_fatal=True):
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
513
        t = self.get_transport(dir)
514
        t.ensure_base()
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
515
        vf = groupcompress.make_pack_factory(graph=create_graph,
7143.15.2 by Jelmer Vernooij
Run autopep8.
516
                                             delta=False, keylength=keylength,
517
                                             inconsistency_fatal=inconsistency_fatal)(t)
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
518
        if do_cleanup:
519
            self.addCleanup(groupcompress.cleanup_pack_group, vf)
520
        return vf
521
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
522
523
class TestGroupCompressVersionedFiles(TestCaseWithGroupCompressVersionedFiles):
524
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
525
    def make_g_index(self, name, ref_lists=0, nodes=[]):
526
        builder = btree_index.BTreeBuilder(ref_lists)
527
        for node, references, value in nodes:
528
            builder.add_node(node, references, value)
529
        stream = builder.finish()
530
        trans = self.get_transport()
531
        size = trans.put_file(name, stream)
532
        return btree_index.BTreeGraphIndex(trans, name, size)
533
534
    def make_g_index_missing_parent(self):
7045.3.1 by Jelmer Vernooij
Fix another ~500 tests.
535
        graph_index = self.make_g_index('missing_parent', 1,
7143.15.2 by Jelmer Vernooij
Run autopep8.
536
                                        [((b'parent', ), b'2 78 2 10', ([],)),
537
                                         ((b'tip', ), b'2 78 2 10',
538
                                            ([(b'parent', ), (b'missing-parent', )],)),
539
                                         ])
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
540
        return graph_index
541
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
542
    def test_get_record_stream_as_requested(self):
543
        # Consider promoting 'as-requested' to general availability, and
544
        # make this a VF interface test
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
545
        vf = self.make_test_vf(False, dir='source')
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
546
        vf.add_lines((b'a',), (), [b'lines\n'])
547
        vf.add_lines((b'b',), (), [b'lines\n'])
548
        vf.add_lines((b'c',), (), [b'lines\n'])
549
        vf.add_lines((b'd',), (), [b'lines\n'])
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
550
        vf.writer.end()
551
        keys = [record.key for record in vf.get_record_stream(
7143.15.2 by Jelmer Vernooij
Run autopep8.
552
            [(b'a',), (b'b',), (b'c',), (b'd',)],
553
            'as-requested', False)]
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
554
        self.assertEqual([(b'a',), (b'b',), (b'c',), (b'd',)], keys)
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
555
        keys = [record.key for record in vf.get_record_stream(
7143.15.2 by Jelmer Vernooij
Run autopep8.
556
            [(b'b',), (b'a',), (b'd',), (b'c',)],
557
            'as-requested', False)]
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
558
        self.assertEqual([(b'b',), (b'a',), (b'd',), (b'c',)], keys)
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
559
560
        # It should work even after being repacked into another VF
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
561
        vf2 = self.make_test_vf(False, dir='target')
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
562
        vf2.insert_record_stream(vf.get_record_stream(
7143.15.2 by Jelmer Vernooij
Run autopep8.
563
            [(b'b',), (b'a',), (b'd',), (b'c',)], 'as-requested', False))
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
564
        vf2.writer.end()
565
566
        keys = [record.key for record in vf2.get_record_stream(
7143.15.2 by Jelmer Vernooij
Run autopep8.
567
            [(b'a',), (b'b',), (b'c',), (b'd',)],
568
            'as-requested', False)]
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
569
        self.assertEqual([(b'a',), (b'b',), (b'c',), (b'd',)], keys)
3735.32.3 by John Arbash Meinel
Start doing some direct GCVF tests.
570
        keys = [record.key for record in vf2.get_record_stream(
7143.15.2 by Jelmer Vernooij
Run autopep8.
571
            [(b'b',), (b'a',), (b'd',), (b'c',)],
572
            'as-requested', False)]
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
573
        self.assertEqual([(b'b',), (b'a',), (b'd',), (b'c',)], keys)
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
574
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
575
    def test_get_record_stream_max_bytes_to_index_default(self):
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
576
        vf = self.make_test_vf(True, dir='source')
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
577
        vf.add_lines((b'a',), (), [b'lines\n'])
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
578
        vf.writer.end()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
579
        record = next(vf.get_record_stream([(b'a',)], 'unordered', True))
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
580
        self.assertEqual(vf._DEFAULT_COMPRESSOR_SETTINGS,
581
                         record._manager._get_compressor_settings())
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
582
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
583
    def test_get_record_stream_accesses_compressor_settings(self):
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
584
        vf = self.make_test_vf(True, dir='source')
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
585
        vf.add_lines((b'a',), (), [b'lines\n'])
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
586
        vf.writer.end()
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
587
        vf._max_bytes_to_index = 1234
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
588
        record = next(vf.get_record_stream([(b'a',)], 'unordered', True))
5755.2.9 by John Arbash Meinel
Change settings to a dict. That way the attributes are still named.
589
        self.assertEqual(dict(max_bytes_to_index=1234),
590
                         record._manager._get_compressor_settings())
5755.2.6 by John Arbash Meinel
Test that the record stream has the correct values set.
591
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
592
    @staticmethod
593
    def grouped_stream(revision_ids, first_parents=()):
594
        parents = first_parents
595
        for revision_id in revision_ids:
596
            key = (revision_id,)
597
            record = versionedfile.FulltextContentFactory(
598
                key, parents, None,
599
                b'some content that is\n'
600
                b'identical except for\n'
601
                b'revision_id:%s\n' % (revision_id,))
602
            yield record
603
            parents = (key,)
604
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
605
    def test_insert_record_stream_reuses_blocks(self):
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
606
        vf = self.make_test_vf(True, dir='source')
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
607
        # One group, a-d
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
608
        vf.insert_record_stream(self.grouped_stream([b'a', b'b', b'c', b'd']))
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
609
        # Second group, e-h
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
610
        vf.insert_record_stream(self.grouped_stream(
611
            [b'e', b'f', b'g', b'h'], first_parents=((b'd',),)))
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
612
        block_bytes = {}
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
613
        stream = vf.get_record_stream(
614
            [(r.encode(),) for r in 'abcdefgh'], 'unordered', False)
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
615
        num_records = 0
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
616
        for record in stream:
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
617
            if record.key in [(b'a',), (b'e',)]:
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
618
                self.assertEqual('groupcompress-block', record.storage_kind)
619
            else:
620
                self.assertEqual('groupcompress-block-ref',
621
                                 record.storage_kind)
622
            block_bytes[record.key] = record._manager._block._z_content
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
623
            num_records += 1
624
        self.assertEqual(8, num_records)
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
625
        for r in 'abcd':
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
626
            key = (r.encode(),)
627
            self.assertIs(block_bytes[key], block_bytes[(b'a',)])
628
            self.assertNotEqual(block_bytes[key], block_bytes[(b'e',)])
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
629
        for r in 'efgh':
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
630
            key = (r.encode(),)
631
            self.assertIs(block_bytes[key], block_bytes[(b'e',)])
632
            self.assertNotEqual(block_bytes[key], block_bytes[(b'a',)])
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
633
        # Now copy the blocks into another vf, and ensure that the blocks are
634
        # preserved without creating new entries
635
        vf2 = self.make_test_vf(True, dir='target')
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
636
        keys = [(r.encode(),) for r in 'abcdefgh']
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
637
        # ordering in 'groupcompress' order, should actually swap the groups in
638
        # the target vf, but the groups themselves should not be disturbed.
7143.15.2 by Jelmer Vernooij
Run autopep8.
639
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
640
        def small_size_stream():
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
641
            for record in vf.get_record_stream(keys, 'groupcompress', False):
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
642
                record._manager._full_enough_block_size = \
643
                    record._manager._block._content_length
644
                yield record
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
645
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
646
        vf2.insert_record_stream(small_size_stream())
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
647
        stream = vf2.get_record_stream(keys, 'groupcompress', False)
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
648
        vf2.writer.end()
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
649
        num_records = 0
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
650
        for record in stream:
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
651
            num_records += 1
3735.32.20 by John Arbash Meinel
groupcompress now copies the blocks exactly as they were given.
652
            self.assertEqual(block_bytes[record.key],
653
                             record._manager._block._z_content)
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
654
        self.assertEqual(8, num_records)
655
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
656
    def test_insert_record_stream_packs_on_the_fly(self):
657
        vf = self.make_test_vf(True, dir='source')
658
        # One group, a-d
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
659
        vf.insert_record_stream(self.grouped_stream([b'a', b'b', b'c', b'd']))
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
660
        # Second group, e-h
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
661
        vf.insert_record_stream(self.grouped_stream(
662
            [b'e', b'f', b'g', b'h'], first_parents=((b'd',),)))
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
663
        # Now copy the blocks into another vf, and see that the
664
        # insert_record_stream rebuilt a new block on-the-fly because of
665
        # under-utilization
666
        vf2 = self.make_test_vf(True, dir='target')
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
667
        keys = [(r.encode(),) for r in 'abcdefgh']
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
668
        vf2.insert_record_stream(vf.get_record_stream(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
669
            keys, 'groupcompress', False))
670
        stream = vf2.get_record_stream(keys, 'groupcompress', False)
4665.3.9 by John Arbash Meinel
Start doing some work to make sure that we call _check_rebuild_block
671
        vf2.writer.end()
672
        num_records = 0
673
        # All of the records should be recombined into a single block
674
        block = None
675
        for record in stream:
676
            num_records += 1
677
            if block is None:
678
                block = record._manager._block
679
            else:
680
                self.assertIs(block, record._manager._block)
681
        self.assertEqual(8, num_records)
682
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
683
    def test__insert_record_stream_no_reuse_block(self):
684
        vf = self.make_test_vf(True, dir='source')
685
        # One group, a-d
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
686
        vf.insert_record_stream(self.grouped_stream([b'a', b'b', b'c', b'd']))
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
687
        # Second group, e-h
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
688
        vf.insert_record_stream(self.grouped_stream(
689
            [b'e', b'f', b'g', b'h'], first_parents=((b'd',),)))
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
690
        vf.writer.end()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
691
        keys = [(r.encode(),) for r in 'abcdefgh']
692
        self.assertEqual(8, len(list(
693
            vf.get_record_stream(keys, 'unordered', False))))
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
694
        # Now copy the blocks into another vf, and ensure that the blocks are
695
        # preserved without creating new entries
696
        vf2 = self.make_test_vf(True, dir='target')
697
        # ordering in 'groupcompress' order, should actually swap the groups in
698
        # the target vf, but the groups themselves should not be disturbed.
699
        list(vf2._insert_record_stream(vf.get_record_stream(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
700
            keys, 'groupcompress', False),
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
701
            reuse_blocks=False))
702
        vf2.writer.end()
703
        # After inserting with reuse_blocks=False, we should have everything in
704
        # a single new block.
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
705
        stream = vf2.get_record_stream(keys, 'groupcompress', False)
3735.32.21 by John Arbash Meinel
We now have a 'reuse_blocks=False' flag for autopack et al.
706
        block = None
707
        for record in stream:
708
            if block is None:
709
                block = record._manager._block
710
            else:
711
                self.assertIs(block, record._manager._block)
712
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
713
    def test_add_missing_noncompression_parent_unvalidated_index(self):
714
        unvalidated = self.make_g_index_missing_parent()
715
        combined = _mod_index.CombinedGraphIndex([unvalidated])
716
        index = groupcompress._GCGraphIndex(combined,
7143.15.2 by Jelmer Vernooij
Run autopep8.
717
                                            is_locked=lambda: True, parents=True,
718
                                            track_external_parent_refs=True)
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
719
        index.scan_unvalidated_index(unvalidated)
720
        self.assertEqual(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
721
            frozenset([(b'missing-parent',)]), index.get_missing_parents())
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
722
723
    def test_track_external_parent_refs(self):
724
        g_index = self.make_g_index('empty', 1, [])
725
        mod_index = btree_index.BTreeBuilder(1, 1)
726
        combined = _mod_index.CombinedGraphIndex([g_index, mod_index])
727
        index = groupcompress._GCGraphIndex(combined,
7143.15.2 by Jelmer Vernooij
Run autopep8.
728
                                            is_locked=lambda: True, parents=True,
729
                                            add_callback=mod_index.add_nodes,
730
                                            track_external_parent_refs=True)
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
731
        index.add_records([
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
732
            ((b'new-key',), b'2 10 2 10', [((b'parent-1',), (b'parent-2',))])])
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
733
        self.assertEqual(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
734
            frozenset([(b'parent-1',), (b'parent-2',)]),
4343.3.20 by John Arbash Meinel
Copy the track_external_parent_refs tests over to GCVF.
735
            index.get_missing_parents())
736
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
737
    def make_source_with_b(self, a_parent, path):
738
        source = self.make_test_vf(True, dir=path)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
739
        source.add_lines((b'a',), (), [b'lines\n'])
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
740
        if a_parent:
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
741
            b_parents = ((b'a',),)
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
742
        else:
743
            b_parents = ()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
744
        source.add_lines((b'b',), b_parents, [b'lines\n'])
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
745
        return source
746
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
747
    def do_inconsistent_inserts(self, inconsistency_fatal):
748
        target = self.make_test_vf(True, dir='target',
749
                                   inconsistency_fatal=inconsistency_fatal)
750
        for x in range(2):
7143.15.2 by Jelmer Vernooij
Run autopep8.
751
            source = self.make_source_with_b(x == 1, 'source%s' % x)
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
752
            target.insert_record_stream(source.get_record_stream(
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
753
                [(b'b',)], 'unordered', False))
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
754
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
755
    def test_inconsistent_redundant_inserts_warn(self):
4465.2.2 by Aaron Bentley
Add test that duplicates are skipped.
756
        """Should not insert a record that is already present."""
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
757
        warnings = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
758
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
759
        def warning(template, args):
760
            warnings.append(template % args)
761
        _trace_warning = trace.warning
762
        trace.warning = warning
763
        try:
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
764
            self.do_inconsistent_inserts(inconsistency_fatal=False)
4465.2.3 by Aaron Bentley
Update to change redundant inserts into a warning.
765
        finally:
766
            trace.warning = _trace_warning
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
767
        self.assertContainsRe(
768
            "\n".join(warnings),
769
            r"^inconsistent details in skipped record: \(b?'b',\)"
770
            r" \(b?'42 32 0 8', \(\(\),\)\)"
771
            r" \(b?'74 32 0 8', \(\(\(b?'a',\),\),\)\)$")
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
772
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
773
    def test_inconsistent_redundant_inserts_raises(self):
6744 by Jelmer Vernooij
Merge lp:~jelmer/brz/move-errors-knit.
774
        e = self.assertRaises(knit.KnitCorrupt, self.do_inconsistent_inserts,
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
775
                              inconsistency_fatal=True)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
776
        self.assertContainsRe(str(e), r"Knit.* corrupt: inconsistent details"
777
                              r" in add_records:"
778
                              r" \(b?'b',\) \(b?'42 32 0 8', \(\(\),\)\)"
779
                              r" \(b?'74 32 0 8', \(\(\(b?'a',\),\),\)\)")
4465.2.4 by Aaron Bentley
Switch between warn and raise depending on inconsistent_fatal.
780
4744.2.5 by John Arbash Meinel
Change to a generic 'VersionedFiles.clear_cache()' api.
781
    def test_clear_cache(self):
782
        vf = self.make_source_with_b(True, 'source')
783
        vf.writer.end()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
784
        for record in vf.get_record_stream([(b'a',), (b'b',)], 'unordered',
4744.2.5 by John Arbash Meinel
Change to a generic 'VersionedFiles.clear_cache()' api.
785
                                           True):
786
            pass
787
        self.assertTrue(len(vf._group_cache) > 0)
788
        vf.clear_cache()
789
        self.assertEqual(0, len(vf._group_cache))
790
791
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
792
class TestGroupCompressConfig(tests.TestCaseWithTransport):
793
794
    def make_test_vf(self):
795
        t = self.get_transport('.')
796
        t.ensure_base()
797
        factory = groupcompress.make_pack_factory(graph=True,
7143.15.2 by Jelmer Vernooij
Run autopep8.
798
                                                  delta=False, keylength=1, inconsistency_fatal=True)
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
799
        vf = factory(t)
800
        self.addCleanup(groupcompress.cleanup_pack_group, vf)
801
        return vf
802
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
803
    def test_max_bytes_to_index_default(self):
804
        vf = self.make_test_vf()
805
        gc = vf._make_group_compressor()
806
        self.assertEqual(vf._DEFAULT_MAX_BYTES_TO_INDEX,
807
                         vf._max_bytes_to_index)
808
        if isinstance(gc, groupcompress.PyrexGroupCompressor):
809
            self.assertEqual(vf._DEFAULT_MAX_BYTES_TO_INDEX,
810
                             gc._delta_index._max_bytes_to_index)
811
812
    def test_max_bytes_to_index_in_config(self):
813
        c = config.GlobalConfig()
814
        c.set_user_option('bzr.groupcompress.max_bytes_to_index', '10000')
815
        vf = self.make_test_vf()
816
        gc = vf._make_group_compressor()
817
        self.assertEqual(10000, vf._max_bytes_to_index)
818
        if isinstance(gc, groupcompress.PyrexGroupCompressor):
819
            self.assertEqual(10000, gc._delta_index._max_bytes_to_index)
820
821
    def test_max_bytes_to_index_bad_config(self):
822
        c = config.GlobalConfig()
823
        c.set_user_option('bzr.groupcompress.max_bytes_to_index', 'boogah')
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
824
        vf = self.make_test_vf()
825
        # TODO: This is triggering a warning, we might want to trap and make
826
        #       sure it is readable.
827
        gc = vf._make_group_compressor()
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
828
        self.assertEqual(vf._DEFAULT_MAX_BYTES_TO_INDEX,
829
                         vf._max_bytes_to_index)
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
830
        if isinstance(gc, groupcompress.PyrexGroupCompressor):
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
831
            self.assertEqual(vf._DEFAULT_MAX_BYTES_TO_INDEX,
832
                             gc._delta_index._max_bytes_to_index)
5755.2.4 by John Arbash Meinel
Expose the max_entries_per_source into GroupCompressVersionedFiles
833
834
4634.3.20 by Andrew Bennetts
Some basic whitebox unit tests for _BatchingBlockFetcher.
835
class StubGCVF(object):
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
836
    def __init__(self, canned_get_blocks=None):
4634.3.20 by Andrew Bennetts
Some basic whitebox unit tests for _BatchingBlockFetcher.
837
        self._group_cache = {}
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
838
        self._canned_get_blocks = canned_get_blocks or []
7143.15.2 by Jelmer Vernooij
Run autopep8.
839
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
840
    def _get_blocks(self, read_memos):
841
        return iter(self._canned_get_blocks)
7143.15.2 by Jelmer Vernooij
Run autopep8.
842
4634.3.20 by Andrew Bennetts
Some basic whitebox unit tests for _BatchingBlockFetcher.
843
844
class Test_BatchingBlockFetcher(TestCaseWithGroupCompressVersionedFiles):
845
    """Simple whitebox unit tests for _BatchingBlockFetcher."""
7143.15.2 by Jelmer Vernooij
Run autopep8.
846
4634.3.20 by Andrew Bennetts
Some basic whitebox unit tests for _BatchingBlockFetcher.
847
    def test_add_key_new_read_memo(self):
848
        """Adding a key with an uncached read_memo new to this batch adds that
849
        read_memo to the list of memos to fetch.
850
        """
851
        # locations are: index_memo, ignored, parents, ignored
852
        # where index_memo is: (idx, offset, len, factory_start, factory_end)
853
        # and (idx, offset, size) is known as the 'read_memo', identifying the
854
        # raw bytes needed.
855
        read_memo = ('fake index', 100, 50)
856
        locations = {
857
            ('key',): (read_memo + (None, None), None, None, None)}
858
        batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), locations)
859
        total_size = batcher.add_key(('key',))
860
        self.assertEqual(50, total_size)
861
        self.assertEqual([('key',)], batcher.keys)
862
        self.assertEqual([read_memo], batcher.memos_to_get)
863
864
    def test_add_key_duplicate_read_memo(self):
865
        """read_memos that occur multiple times in a batch will only be fetched
866
        once.
867
        """
868
        read_memo = ('fake index', 100, 50)
869
        # Two keys, both sharing the same read memo (but different overall
870
        # index_memos).
871
        locations = {
872
            ('key1',): (read_memo + (0, 1), None, None, None),
873
            ('key2',): (read_memo + (1, 2), None, None, None)}
874
        batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), locations)
875
        total_size = batcher.add_key(('key1',))
876
        total_size = batcher.add_key(('key2',))
877
        self.assertEqual(50, total_size)
878
        self.assertEqual([('key1',), ('key2',)], batcher.keys)
879
        self.assertEqual([read_memo], batcher.memos_to_get)
880
881
    def test_add_key_cached_read_memo(self):
882
        """Adding a key with a cached read_memo will not cause that read_memo
883
        to be added to the list to fetch.
884
        """
885
        read_memo = ('fake index', 100, 50)
886
        gcvf = StubGCVF()
887
        gcvf._group_cache[read_memo] = 'fake block'
888
        locations = {
889
            ('key',): (read_memo + (None, None), None, None, None)}
890
        batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
891
        total_size = batcher.add_key(('key',))
892
        self.assertEqual(0, total_size)
893
        self.assertEqual([('key',)], batcher.keys)
894
        self.assertEqual([], batcher.memos_to_get)
895
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
896
    def test_yield_factories_empty(self):
897
        """An empty batch yields no factories."""
898
        batcher = groupcompress._BatchingBlockFetcher(StubGCVF(), {})
899
        self.assertEqual([], list(batcher.yield_factories()))
900
901
    def test_yield_factories_calls_get_blocks(self):
4634.3.22 by Andrew Bennetts
Fix docstring.
902
        """Uncached memos are retrieved via get_blocks."""
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
903
        read_memo1 = ('fake index', 100, 50)
904
        read_memo2 = ('fake index', 150, 40)
905
        gcvf = StubGCVF(
906
            canned_get_blocks=[
907
                (read_memo1, groupcompress.GroupCompressBlock()),
908
                (read_memo2, groupcompress.GroupCompressBlock())])
909
        locations = {
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
910
            ('key1',): (read_memo1 + (0, 0), None, None, None),
911
            ('key2',): (read_memo2 + (0, 0), None, None, None)}
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
912
        batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
913
        batcher.add_key(('key1',))
914
        batcher.add_key(('key2',))
915
        factories = list(batcher.yield_factories(full_flush=True))
916
        self.assertLength(2, factories)
917
        keys = [f.key for f in factories]
918
        kinds = [f.storage_kind for f in factories]
919
        self.assertEqual([('key1',), ('key2',)], keys)
920
        self.assertEqual(['groupcompress-block', 'groupcompress-block'], kinds)
921
922
    def test_yield_factories_flushing(self):
923
        """yield_factories holds back on yielding results from the final block
924
        unless passed full_flush=True.
925
        """
926
        fake_block = groupcompress.GroupCompressBlock()
927
        read_memo = ('fake index', 100, 50)
928
        gcvf = StubGCVF()
929
        gcvf._group_cache[read_memo] = fake_block
930
        locations = {
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
931
            ('key',): (read_memo + (0, 0), None, None, None)}
4634.3.21 by Andrew Bennetts
Direct tests now have complete line coverage of _BatchingBlockFetcher (except for the assertion).
932
        batcher = groupcompress._BatchingBlockFetcher(gcvf, locations)
933
        batcher.add_key(('key',))
934
        self.assertEqual([], list(batcher.yield_factories()))
935
        factories = list(batcher.yield_factories(full_flush=True))
936
        self.assertLength(1, factories)
937
        self.assertEqual(('key',), factories[0].key)
938
        self.assertEqual('groupcompress-block', factories[0].storage_kind)
939
4634.3.20 by Andrew Bennetts
Some basic whitebox unit tests for _BatchingBlockFetcher.
940
3735.32.14 by John Arbash Meinel
Move the tests over to testing the LazyGroupContentManager object.
941
class TestLazyGroupCompress(tests.TestCaseWithTransport):
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
942
3735.32.14 by John Arbash Meinel
Move the tests over to testing the LazyGroupContentManager object.
943
    _texts = {
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
944
        (b'key1',): b"this is a text\n"
7143.15.2 by Jelmer Vernooij
Run autopep8.
945
        b"with a reasonable amount of compressible bytes\n"
946
        b"which can be shared between various other texts\n",
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
947
        (b'key2',): b"another text\n"
7143.15.2 by Jelmer Vernooij
Run autopep8.
948
        b"with a reasonable amount of compressible bytes\n"
949
        b"which can be shared between various other texts\n",
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
950
        (b'key3',): b"yet another text which won't be extracted\n"
7143.15.2 by Jelmer Vernooij
Run autopep8.
951
        b"with a reasonable amount of compressible bytes\n"
952
        b"which can be shared between various other texts\n",
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
953
        (b'key4',): b"this will be extracted\n"
7143.15.2 by Jelmer Vernooij
Run autopep8.
954
        b"but references most of its bytes from\n"
955
        b"yet another text which won't be extracted\n"
956
        b"with a reasonable amount of compressible bytes\n"
957
        b"which can be shared between various other texts\n",
3735.32.14 by John Arbash Meinel
Move the tests over to testing the LazyGroupContentManager object.
958
    }
7143.15.2 by Jelmer Vernooij
Run autopep8.
959
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
960
    def make_block(self, key_to_text):
961
        """Create a GroupCompressBlock, filling it with the given texts."""
962
        compressor = groupcompress.GroupCompressor()
963
        start = 0
964
        for key in sorted(key_to_text):
7463.2.2 by Jelmer Vernooij
Fix tests.
965
            compressor.compress(
966
                key, [key_to_text[key]], len(key_to_text[key]), None)
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
967
        locs = dict((key, (start, end)) for key, (start, _, end, _)
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
968
                    in compressor.labels_deltas.items())
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
969
        block = compressor.flush()
970
        raw_bytes = block.to_bytes()
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
971
        return locs, groupcompress.GroupCompressBlock.from_bytes(raw_bytes)
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
972
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
973
    def add_key_to_manager(self, key, locations, block, manager):
974
        start, end = locations[key]
975
        manager.add_factory(key, (), start, end)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
976
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
977
    def make_block_and_full_manager(self, texts):
978
        locations, block = self.make_block(texts)
979
        manager = groupcompress._LazyGroupContentManager(block)
980
        for key in sorted(texts):
981
            self.add_key_to_manager(key, locations, block, manager)
982
        return block, manager
983
3735.32.8 by John Arbash Meinel
Some tests for the LazyGroupCompressFactory
984
    def test_get_fulltexts(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
985
        locations, block = self.make_block(self._texts)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
986
        manager = groupcompress._LazyGroupContentManager(block)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
987
        self.add_key_to_manager((b'key1',), locations, block, manager)
988
        self.add_key_to_manager((b'key2',), locations, block, manager)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
989
        result_order = []
990
        for record in manager.get_record_stream():
991
            result_order.append(record.key)
992
            text = self._texts[record.key]
993
            self.assertEqual(text, record.get_bytes_as('fulltext'))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
994
        self.assertEqual([(b'key1',), (b'key2',)], result_order)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
995
996
        # If we build the manager in the opposite order, we should get them
997
        # back in the opposite order
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
998
        manager = groupcompress._LazyGroupContentManager(block)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
999
        self.add_key_to_manager((b'key2',), locations, block, manager)
1000
        self.add_key_to_manager((b'key1',), locations, block, manager)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
1001
        result_order = []
1002
        for record in manager.get_record_stream():
1003
            result_order.append(record.key)
1004
            text = self._texts[record.key]
1005
            self.assertEqual(text, record.get_bytes_as('fulltext'))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1006
        self.assertEqual([(b'key2',), (b'key1',)], result_order)
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
1007
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1008
    def test__wire_bytes_no_keys(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1009
        locations, block = self.make_block(self._texts)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1010
        manager = groupcompress._LazyGroupContentManager(block)
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1011
        wire_bytes = manager._wire_bytes()
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1012
        block_length = len(block.to_bytes())
3735.32.24 by John Arbash Meinel
_wire_bytes() now strips groups as necessary, as does _insert_record_stream
1013
        # We should have triggered a strip, since we aren't using any content
1014
        stripped_block = manager._block.to_bytes()
1015
        self.assertTrue(block_length > len(stripped_block))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1016
        empty_z_header = zlib.compress(b'')
1017
        self.assertEqual(b'groupcompress-block\n'
7143.15.2 by Jelmer Vernooij
Run autopep8.
1018
                         b'8\n'  # len(compress(''))
1019
                         b'0\n'  # len('')
1020
                         b'%d\n'  # compressed block len
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1021
                         b'%s'  # zheader
1022
                         b'%s'  # block
3735.32.24 by John Arbash Meinel
_wire_bytes() now strips groups as necessary, as does _insert_record_stream
1023
                         % (len(stripped_block), empty_z_header,
1024
                            stripped_block),
1025
                         wire_bytes)
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1026
3735.32.15 by John Arbash Meinel
Change the GroupCompressBlock code to allow not recording 'end'.
1027
    def test__wire_bytes(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1028
        locations, block = self.make_block(self._texts)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1029
        manager = groupcompress._LazyGroupContentManager(block)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1030
        self.add_key_to_manager((b'key1',), locations, block, manager)
1031
        self.add_key_to_manager((b'key4',), locations, block, manager)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1032
        block_bytes = block.to_bytes()
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1033
        wire_bytes = manager._wire_bytes()
1034
        (storage_kind, z_header_len, header_len,
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1035
         block_len, rest) = wire_bytes.split(b'\n', 4)
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1036
        z_header_len = int(z_header_len)
1037
        header_len = int(header_len)
1038
        block_len = int(block_len)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1039
        self.assertEqual(b'groupcompress-block', storage_kind)
4665.3.8 by John Arbash Meinel
Of course, when you change the content, it can effect the stored wire bytes slightly.
1040
        self.assertEqual(34, z_header_len)
1041
        self.assertEqual(26, header_len)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1042
        self.assertEqual(len(block_bytes), block_len)
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1043
        z_header = rest[:z_header_len]
1044
        header = zlib.decompress(z_header)
1045
        self.assertEqual(header_len, len(header))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1046
        entry1 = locations[(b'key1',)]
1047
        entry4 = locations[(b'key4',)]
1048
        self.assertEqualDiff(b'key1\n'
1049
                             b'\n'  # no parents
7143.15.2 by Jelmer Vernooij
Run autopep8.
1050
                             b'%d\n'  # start offset
1051
                             b'%d\n'  # end offset
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1052
                             b'key4\n'
1053
                             b'\n'
1054
                             b'%d\n'
1055
                             b'%d\n'
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1056
                             % (entry1[0], entry1[1],
1057
                                entry4[0], entry4[1]),
7143.15.2 by Jelmer Vernooij
Run autopep8.
1058
                             header)
3735.32.16 by John Arbash Meinel
We now have a general header for the GC block.
1059
        z_block = rest[z_header_len:]
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1060
        self.assertEqual(block_bytes, z_block)
1061
1062
    def test_from_bytes(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1063
        locations, block = self.make_block(self._texts)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1064
        manager = groupcompress._LazyGroupContentManager(block)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1065
        self.add_key_to_manager((b'key1',), locations, block, manager)
1066
        self.add_key_to_manager((b'key4',), locations, block, manager)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1067
        wire_bytes = manager._wire_bytes()
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1068
        self.assertStartsWith(wire_bytes, b'groupcompress-block\n')
3735.32.18 by John Arbash Meinel
We now support generating a network stream.
1069
        manager = groupcompress._LazyGroupContentManager.from_bytes(wire_bytes)
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1070
        self.assertIsInstance(manager, groupcompress._LazyGroupContentManager)
3735.38.2 by John Arbash Meinel
Make the text for key4 slightly longer, rather than include key3.
1071
        self.assertEqual(2, len(manager._factories))
3735.32.17 by John Arbash Meinel
We now round-trip the wire_bytes.
1072
        self.assertEqual(block._z_content, manager._block._z_content)
1073
        result_order = []
1074
        for record in manager.get_record_stream():
1075
            result_order.append(record.key)
1076
            text = self._texts[record.key]
1077
            self.assertEqual(text, record.get_bytes_as('fulltext'))
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1078
        self.assertEqual([(b'key1',), (b'key4',)], result_order)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1079
1080
    def test__check_rebuild_no_changes(self):
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1081
        block, manager = self.make_block_and_full_manager(self._texts)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1082
        manager._check_rebuild_block()
1083
        self.assertIs(block, manager._block)
1084
1085
    def test__check_rebuild_only_one(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1086
        locations, block = self.make_block(self._texts)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1087
        manager = groupcompress._LazyGroupContentManager(block)
1088
        # Request just the first key, which should trigger a 'strip' action
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1089
        self.add_key_to_manager((b'key1',), locations, block, manager)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1090
        manager._check_rebuild_block()
1091
        self.assertIsNot(block, manager._block)
1092
        self.assertTrue(block._content_length > manager._block._content_length)
1093
        # We should be able to still get the content out of this block, though
1094
        # it should only have 1 entry
1095
        for record in manager.get_record_stream():
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1096
            self.assertEqual((b'key1',), record.key)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1097
            self.assertEqual(self._texts[record.key],
1098
                             record.get_bytes_as('fulltext'))
1099
1100
    def test__check_rebuild_middle(self):
3735.40.18 by John Arbash Meinel
Get rid of the entries dict in GroupCompressBlock.
1101
        locations, block = self.make_block(self._texts)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1102
        manager = groupcompress._LazyGroupContentManager(block)
1103
        # Request a small key in the middle should trigger a 'rebuild'
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1104
        self.add_key_to_manager((b'key4',), locations, block, manager)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1105
        manager._check_rebuild_block()
1106
        self.assertIsNot(block, manager._block)
1107
        self.assertTrue(block._content_length > manager._block._content_length)
1108
        for record in manager.get_record_stream():
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1109
            self.assertEqual((b'key4',), record.key)
3735.32.23 by John Arbash Meinel
Add a _LazyGroupContentManager._check_rebuild_block
1110
            self.assertEqual(self._texts[record.key],
1111
                             record.get_bytes_as('fulltext'))
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1112
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1113
    def test_manager_default_compressor_settings(self):
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1114
        locations, old_block = self.make_block(self._texts)
1115
        manager = groupcompress._LazyGroupContentManager(old_block)
1116
        gcvf = groupcompress.GroupCompressVersionedFiles
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1117
        # It doesn't greedily evaluate _max_bytes_to_index
1118
        self.assertIs(None, manager._compressor_settings)
1119
        self.assertEqual(gcvf._DEFAULT_COMPRESSOR_SETTINGS,
1120
                         manager._get_compressor_settings())
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1121
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1122
    def test_manager_custom_compressor_settings(self):
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1123
        locations, old_block = self.make_block(self._texts)
1124
        called = []
7143.15.2 by Jelmer Vernooij
Run autopep8.
1125
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1126
        def compressor_settings():
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1127
            called.append('called')
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1128
            return (10,)
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1129
        manager = groupcompress._LazyGroupContentManager(old_block,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1130
                                                         get_compressor_settings=compressor_settings)
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1131
        gcvf = groupcompress.GroupCompressVersionedFiles
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1132
        # It doesn't greedily evaluate compressor_settings
1133
        self.assertIs(None, manager._compressor_settings)
1134
        self.assertEqual((10,), manager._get_compressor_settings())
1135
        self.assertEqual((10,), manager._get_compressor_settings())
1136
        self.assertEqual((10,), manager._compressor_settings)
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1137
        # Only called 1 time
1138
        self.assertEqual(['called'], called)
1139
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1140
    def test__rebuild_handles_compressor_settings(self):
1141
        if not isinstance(groupcompress.GroupCompressor,
1142
                          groupcompress.PyrexGroupCompressor):
1143
            raise tests.TestNotApplicable('pure-python compressor'
7143.15.2 by Jelmer Vernooij
Run autopep8.
1144
                                          ' does not handle compressor_settings')
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1145
        locations, old_block = self.make_block(self._texts)
1146
        manager = groupcompress._LazyGroupContentManager(old_block,
7143.15.2 by Jelmer Vernooij
Run autopep8.
1147
                                                         get_compressor_settings=lambda: dict(max_bytes_to_index=32))
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1148
        gc = manager._make_group_compressor()
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1149
        self.assertEqual(32, gc._delta_index._max_bytes_to_index)
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1150
        self.add_key_to_manager((b'key3',), locations, old_block, manager)
1151
        self.add_key_to_manager((b'key4',), locations, old_block, manager)
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1152
        action, last_byte, total_bytes = manager._check_rebuild_action()
1153
        self.assertEqual('rebuild', action)
1154
        manager._rebuild_block()
1155
        new_block = manager._block
1156
        self.assertIsNot(old_block, new_block)
5755.2.8 by John Arbash Meinel
Do a lot of renaming.
1157
        # Because of the new max_bytes_to_index, we do a poor job of
5755.2.5 by John Arbash Meinel
Expose the setting up the stack.
1158
        # rebuilding. This is a side-effect of the change, but at least it does
1159
        # show the setting had an effect.
1160
        self.assertTrue(old_block._content_length < new_block._content_length)
1161
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1162
    def test_check_is_well_utilized_all_keys(self):
1163
        block, manager = self.make_block_and_full_manager(self._texts)
1164
        self.assertFalse(manager.check_is_well_utilized())
1165
        # Though we can fake it by changing the recommended minimum size
1166
        manager._full_enough_block_size = block._content_length
1167
        self.assertTrue(manager.check_is_well_utilized())
1168
        # Setting it just above causes it to fail
1169
        manager._full_enough_block_size = block._content_length + 1
1170
        self.assertFalse(manager.check_is_well_utilized())
1171
        # Setting the mixed-block size doesn't do anything, because the content
1172
        # is considered to not be 'mixed'
1173
        manager._full_enough_mixed_block_size = block._content_length
1174
        self.assertFalse(manager.check_is_well_utilized())
1175
1176
    def test_check_is_well_utilized_mixed_keys(self):
1177
        texts = {}
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1178
        f1k1 = (b'f1', b'k1')
1179
        f1k2 = (b'f1', b'k2')
1180
        f2k1 = (b'f2', b'k1')
1181
        f2k2 = (b'f2', b'k2')
1182
        texts[f1k1] = self._texts[(b'key1',)]
1183
        texts[f1k2] = self._texts[(b'key2',)]
1184
        texts[f2k1] = self._texts[(b'key3',)]
1185
        texts[f2k2] = self._texts[(b'key4',)]
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1186
        block, manager = self.make_block_and_full_manager(texts)
1187
        self.assertFalse(manager.check_is_well_utilized())
1188
        manager._full_enough_block_size = block._content_length
1189
        self.assertTrue(manager.check_is_well_utilized())
1190
        manager._full_enough_block_size = block._content_length + 1
1191
        self.assertFalse(manager.check_is_well_utilized())
1192
        manager._full_enough_mixed_block_size = block._content_length
1193
        self.assertTrue(manager.check_is_well_utilized())
1194
1195
    def test_check_is_well_utilized_partial_use(self):
1196
        locations, block = self.make_block(self._texts)
1197
        manager = groupcompress._LazyGroupContentManager(block)
1198
        manager._full_enough_block_size = block._content_length
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1199
        self.add_key_to_manager((b'key1',), locations, block, manager)
1200
        self.add_key_to_manager((b'key2',), locations, block, manager)
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1201
        # Just using the content from key1 and 2 is not enough to be considered
1202
        # 'complete'
1203
        self.assertFalse(manager.check_is_well_utilized())
1204
        # However if we add key3, then we have enough, as we only require 75%
1205
        # consumption
6803.2.1 by Martin
Make test_groupcompress.py correct for Python 3
1206
        self.add_key_to_manager((b'key4',), locations, block, manager)
4665.3.7 by John Arbash Meinel
We needed a bit more data to actually get groups doing delta-compression.
1207
        self.assertTrue(manager.check_is_well_utilized())
5365.4.1 by John Arbash Meinel
Find a case where we are wasting a bit of memory.
1208
1209
1210
class Test_GCBuildDetails(tests.TestCase):
1211
1212
    def test_acts_like_tuple(self):
1213
        # _GCBuildDetails inlines some of the data that used to be spread out
1214
        # across a bunch of tuples
1215
        bd = groupcompress._GCBuildDetails((('parent1',), ('parent2',)),
7143.15.2 by Jelmer Vernooij
Run autopep8.
1216
                                           ('INDEX', 10, 20, 0, 5))
5365.4.1 by John Arbash Meinel
Find a case where we are wasting a bit of memory.
1217
        self.assertEqual(4, len(bd))
1218
        self.assertEqual(('INDEX', 10, 20, 0, 5), bd[0])
7143.15.2 by Jelmer Vernooij
Run autopep8.
1219
        self.assertEqual(None, bd[1])  # Compression Parent is always None
5365.4.1 by John Arbash Meinel
Find a case where we are wasting a bit of memory.
1220
        self.assertEqual((('parent1',), ('parent2',)), bd[2])
7143.15.2 by Jelmer Vernooij
Run autopep8.
1221
        self.assertEqual(('group', None), bd[3])  # Record details
5365.4.1 by John Arbash Meinel
Find a case where we are wasting a bit of memory.
1222
1223
    def test__repr__(self):
1224
        bd = groupcompress._GCBuildDetails((('parent1',), ('parent2',)),
7143.15.2 by Jelmer Vernooij
Run autopep8.
1225
                                           ('INDEX', 10, 20, 0, 5))
5365.4.1 by John Arbash Meinel
Find a case where we are wasting a bit of memory.
1226
        self.assertEqual("_GCBuildDetails(('INDEX', 10, 20, 0, 5),"
1227
                         " (('parent1',), ('parent2',)))",
1228
                         repr(bd))