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