/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2007-2010 Canonical Ltd
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
16
17
"""Tests for indices."""
18
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
19
from .. import (
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
20
    errors,
21
    tests,
22
    transport,
23
    )
6670.4.1 by Jelmer Vernooij
Update imports.
24
from ..bzr import (
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
25
    index as _mod_index,
6670.4.1 by Jelmer Vernooij
Update imports.
26
    )
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
27
28
6743 by Jelmer Vernooij
Merge lp:~jelmer/brz/move-errors-more.
29
class ErrorTests(tests.TestCase):
30
31
    def test_bad_index_format_signature(self):
32
        error = _mod_index.BadIndexFormatSignature("foo", "bar")
33
        self.assertEqual("foo is not an index of type bar.",
34
            str(error))
35
36
    def test_bad_index_data(self):
37
        error = _mod_index.BadIndexData("foo")
38
        self.assertEqual("Error in data for index foo.",
39
            str(error))
40
41
    def test_bad_index_duplicate_key(self):
42
        error = _mod_index.BadIndexDuplicateKey("foo", "bar")
43
        self.assertEqual("The key 'foo' is already in index 'bar'.",
44
            str(error))
45
46
    def test_bad_index_key(self):
47
        error = _mod_index.BadIndexKey("foo")
48
        self.assertEqual("The key 'foo' is not a valid key.",
49
            str(error))
50
51
    def test_bad_index_options(self):
52
        error = _mod_index.BadIndexOptions("foo")
53
        self.assertEqual("Could not parse options for index foo.",
54
            str(error))
55
56
    def test_bad_index_value(self):
57
        error = _mod_index.BadIndexValue("foo")
58
        self.assertEqual("The value 'foo' is not a valid value.",
59
            str(error))
60
61
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
62
class TestGraphIndexBuilder(tests.TestCaseWithMemoryTransport):
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
63
64
    def test_build_index_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
65
        builder = _mod_index.GraphIndexBuilder()
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
66
        stream = builder.finish()
67
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
68
        self.assertEqual(
69
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=0\n\n",
70
            contents)
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
71
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
72
    def test_build_index_empty_two_element_keys(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
73
        builder = _mod_index.GraphIndexBuilder(key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
74
        stream = builder.finish()
75
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
76
        self.assertEqual(
77
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=0\n\n",
78
            contents)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
79
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
80
    def test_build_index_one_reference_list_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
81
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
82
        stream = builder.finish()
83
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
84
        self.assertEqual(
85
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=0\n\n",
86
            contents)
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
87
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
88
    def test_build_index_two_reference_list_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
89
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
90
        stream = builder.finish()
91
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
92
        self.assertEqual(
93
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=0\n\n",
94
            contents)
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
95
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
96
    def test_build_index_one_node_no_refs(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
97
        builder = _mod_index.GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
98
        builder.add_node(('akey', ), 'data')
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
99
        stream = builder.finish()
100
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
101
        self.assertEqual(
102
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
103
            "akey\x00\x00\x00data\n\n", contents)
104
105
    def test_build_index_one_node_no_refs_accepts_empty_reflist(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
106
        builder = _mod_index.GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
107
        builder.add_node(('akey', ), 'data', ())
2592.1.12 by Robert Collins
Handle basic node adds.
108
        stream = builder.finish()
109
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
110
        self.assertEqual(
111
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
112
            "akey\x00\x00\x00data\n\n", contents)
2592.1.12 by Robert Collins
Handle basic node adds.
113
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
114
    def test_build_index_one_node_2_element_keys(self):
2624.2.11 by Robert Collins
Review comments.
115
        # multipart keys are separated by \x00 - because they are fixed length,
116
        # not variable this does not cause any issues, and seems clearer to the
117
        # author.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
118
        builder = _mod_index.GraphIndexBuilder(key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
119
        builder.add_node(('akey', 'secondpart'), 'data')
120
        stream = builder.finish()
121
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
122
        self.assertEqual(
123
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=1\n"
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
124
            "akey\x00secondpart\x00\x00\x00data\n\n", contents)
125
2592.1.21 by Robert Collins
Empty values are ok.
126
    def test_add_node_empty_value(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
127
        builder = _mod_index.GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
128
        builder.add_node(('akey', ), '')
2592.1.21 by Robert Collins
Empty values are ok.
129
        stream = builder.finish()
130
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
131
        self.assertEqual(
132
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
133
            "akey\x00\x00\x00\n\n", contents)
2592.1.21 by Robert Collins
Empty values are ok.
134
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
135
    def test_build_index_nodes_sorted(self):
2592.1.17 by Robert Collins
Multi node sort order is defined.
136
        # the highest sorted node comes first.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
137
        builder = _mod_index.GraphIndexBuilder()
2592.1.17 by Robert Collins
Multi node sort order is defined.
138
        # use three to have a good chance of glitching dictionary hash
139
        # lookups etc. Insert in randomish order that is not correct
140
        # and not the reverse of the correct order.
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
141
        builder.add_node(('2002', ), 'data')
142
        builder.add_node(('2000', ), 'data')
143
        builder.add_node(('2001', ), 'data')
2592.1.17 by Robert Collins
Multi node sort order is defined.
144
        stream = builder.finish()
145
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
146
        self.assertEqual(
147
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=3\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
148
            "2000\x00\x00\x00data\n"
149
            "2001\x00\x00\x00data\n"
150
            "2002\x00\x00\x00data\n"
2592.1.17 by Robert Collins
Multi node sort order is defined.
151
            "\n", contents)
152
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
153
    def test_build_index_2_element_key_nodes_sorted(self):
154
        # multiple element keys are sorted first-key, second-key.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
155
        builder = _mod_index.GraphIndexBuilder(key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
156
        # use three values of each key element, to have a good chance of
157
        # glitching dictionary hash lookups etc. Insert in randomish order that
158
        # is not correct and not the reverse of the correct order.
159
        builder.add_node(('2002', '2002'), 'data')
160
        builder.add_node(('2002', '2000'), 'data')
161
        builder.add_node(('2002', '2001'), 'data')
162
        builder.add_node(('2000', '2002'), 'data')
163
        builder.add_node(('2000', '2000'), 'data')
164
        builder.add_node(('2000', '2001'), 'data')
165
        builder.add_node(('2001', '2002'), 'data')
166
        builder.add_node(('2001', '2000'), 'data')
167
        builder.add_node(('2001', '2001'), 'data')
168
        stream = builder.finish()
169
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
170
        self.assertEqual(
171
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=9\n"
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
172
            "2000\x002000\x00\x00\x00data\n"
173
            "2000\x002001\x00\x00\x00data\n"
174
            "2000\x002002\x00\x00\x00data\n"
175
            "2001\x002000\x00\x00\x00data\n"
176
            "2001\x002001\x00\x00\x00data\n"
177
            "2001\x002002\x00\x00\x00data\n"
178
            "2002\x002000\x00\x00\x00data\n"
179
            "2002\x002001\x00\x00\x00data\n"
180
            "2002\x002002\x00\x00\x00data\n"
181
            "\n", contents)
182
2592.1.19 by Robert Collins
Node references are tab separated.
183
    def test_build_index_reference_lists_are_included_one(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
184
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
185
        builder.add_node(('key', ), 'data', ([], ))
2592.1.19 by Robert Collins
Node references are tab separated.
186
        stream = builder.finish()
187
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
188
        self.assertEqual(
189
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
190
            "key\x00\x00\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
191
            "\n", contents)
192
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
193
    def test_build_index_reference_lists_with_2_element_keys(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
194
        builder = _mod_index.GraphIndexBuilder(reference_lists=1, key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
195
        builder.add_node(('key', 'key2'), 'data', ([], ))
196
        stream = builder.finish()
197
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
198
        self.assertEqual(
199
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=2\nlen=1\n"
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
200
            "key\x00key2\x00\x00\x00data\n"
201
            "\n", contents)
202
2592.1.19 by Robert Collins
Node references are tab separated.
203
    def test_build_index_reference_lists_are_included_two(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
204
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
205
        builder.add_node(('key', ), 'data', ([], []))
2592.1.19 by Robert Collins
Node references are tab separated.
206
        stream = builder.finish()
207
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
208
        self.assertEqual(
209
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
210
            "key\x00\x00\t\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
211
            "\n", contents)
212
4744.2.7 by John Arbash Meinel
Add .clear_cache() members to GraphIndexBuilder and BTreeBuilder.
213
    def test_clear_cache(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
214
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
4744.2.7 by John Arbash Meinel
Add .clear_cache() members to GraphIndexBuilder and BTreeBuilder.
215
        # This is a no-op, but the api should exist
216
        builder.clear_cache()
217
2592.1.22 by Robert Collins
Node references are byte offsets.
218
    def test_node_references_are_byte_offsets(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
219
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
220
        builder.add_node(('reference', ), 'data', ([], ))
221
        builder.add_node(('key', ), 'data', ([('reference', )], ))
2592.1.22 by Robert Collins
Node references are byte offsets.
222
        stream = builder.finish()
223
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
224
        self.assertEqual(
225
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=2\n"
226
            "key\x00\x0072\x00data\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
227
            "reference\x00\x00\x00data\n"
2592.1.22 by Robert Collins
Node references are byte offsets.
228
            "\n", contents)
229
2592.1.23 by Robert Collins
node reference delimiting tested.
230
    def test_node_references_are_cr_delimited(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
231
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
232
        builder.add_node(('reference', ), 'data', ([], ))
233
        builder.add_node(('reference2', ), 'data', ([], ))
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
234
        builder.add_node(('key', ), 'data',
235
                         ([('reference', ), ('reference2', )], ))
2592.1.23 by Robert Collins
node reference delimiting tested.
236
        stream = builder.finish()
237
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
238
        self.assertEqual(
239
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=3\n"
240
            "key\x00\x00077\r094\x00data\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
241
            "reference\x00\x00\x00data\n"
242
            "reference2\x00\x00\x00data\n"
2592.1.23 by Robert Collins
node reference delimiting tested.
243
            "\n", contents)
244
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
245
    def test_multiple_reference_lists_are_tab_delimited(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
246
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
247
        builder.add_node(('keference', ), 'data', ([], []))
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
248
        builder.add_node(('rey', ), 'data',
249
                         ([('keference', )], [('keference', )]))
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
250
        stream = builder.finish()
251
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
252
        self.assertEqual(
253
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=2\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
254
            "keference\x00\x00\t\x00data\n"
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
255
            "rey\x00\x0059\t59\x00data\n"
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
256
            "\n", contents)
257
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
258
    def test_add_node_referencing_missing_key_makes_absent(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
259
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
260
        builder.add_node(('rey', ), 'data',
261
                         ([('beference', ), ('aeference2', )], ))
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
262
        stream = builder.finish()
263
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
264
        self.assertEqual(
265
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
266
            "aeference2\x00a\x00\x00\n"
267
            "beference\x00a\x00\x00\n"
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
268
            "rey\x00\x00074\r059\x00data\n"
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
269
            "\n", contents)
270
2592.1.26 by Robert Collins
Test digit buffering is accurate.
271
    def test_node_references_three_digits(self):
272
        # test the node digit expands as needed.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
273
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
274
        references = [(str(val), ) for val in range(8, -1, -1)]
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
275
        builder.add_node(('2-key', ), '', (references, ))
2592.1.26 by Robert Collins
Test digit buffering is accurate.
276
        stream = builder.finish()
277
        contents = stream.read()
4789.28.2 by John Arbash Meinel
Get rid of the GraphIndexBuilder/BTreeBuilder._keys attribute.
278
        self.assertEqualDiff(
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
279
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
280
            "0\x00a\x00\x00\n"
281
            "1\x00a\x00\x00\n"
282
            "2\x00a\x00\x00\n"
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
283
            "2-key\x00\x00151\r145\r139\r133\r127\r121\r071\r065\r059\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
284
            "3\x00a\x00\x00\n"
285
            "4\x00a\x00\x00\n"
286
            "5\x00a\x00\x00\n"
287
            "6\x00a\x00\x00\n"
288
            "7\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
289
            "8\x00a\x00\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
290
            "\n", contents)
291
292
    def test_absent_has_no_reference_overhead(self):
293
        # the offsets after an absent record should be correct when there are
294
        # >1 reference lists.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
295
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
296
        builder.add_node(('parent', ), '', ([('aail', ), ('zther', )], []))
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
297
        stream = builder.finish()
298
        contents = stream.read()
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
299
        self.assertEqual(
300
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
301
            "aail\x00a\x00\x00\n"
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
302
            "parent\x00\x0059\r84\t\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
303
            "zther\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
304
            "\n", contents)
305
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
306
    def test_add_node_bad_key(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
307
        builder = _mod_index.GraphIndexBuilder()
2592.1.14 by Robert Collins
Detect bad reference key values.
308
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
309
            self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
310
                ('a%skey' % bad_char, ), 'data')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
311
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
312
                ('', ), 'data')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
313
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
314
                'not-a-tuple', 'data')
315
        # not enough length
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
316
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
317
                (), 'data')
318
        # too long
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
319
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
320
                ('primary', 'secondary'), 'data')
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
321
        # secondary key elements get checked too:
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
322
        builder = _mod_index.GraphIndexBuilder(key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
323
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
324
            self.assertRaises(_mod_index.BadIndexKey, builder.add_node,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
325
                ('prefix', 'a%skey' % bad_char), 'data')
2592.1.12 by Robert Collins
Handle basic node adds.
326
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
327
    def test_add_node_bad_data(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
328
        builder = _mod_index.GraphIndexBuilder()
329
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
330
            'data\naa')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
331
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
332
            'data\x00aa')
2592.1.12 by Robert Collins
Handle basic node adds.
333
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
334
    def test_add_node_bad_mismatched_ref_lists_length(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
335
        builder = _mod_index.GraphIndexBuilder()
336
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
337
            'data aa', ([], ))
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
338
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
339
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
340
            'data aa')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
341
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
342
            'data aa', (), )
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
343
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
344
            'data aa', ([], []))
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
345
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
346
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
347
            'data aa')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
348
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
349
            'data aa', ([], ))
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
350
        self.assertRaises(_mod_index.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
351
            'data aa', ([], [], []))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
352
2592.1.14 by Robert Collins
Detect bad reference key values.
353
    def test_add_node_bad_key_in_reference_lists(self):
354
        # first list, first key - trivial
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
355
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
356
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
357
            'data aa', ([('a key', )], ))
358
        # references keys must be tuples too
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
359
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
360
            'data aa', (['not-a-tuple'], ))
361
        # not enough length
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
362
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
363
            'data aa', ([()], ))
364
        # too long
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
365
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
366
            'data aa', ([('primary', 'secondary')], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
367
        # need to check more than the first key in the list
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
368
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
369
            'data aa', ([('agoodkey', ), ('that is a bad key', )], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
370
        # and if there is more than one list it should be getting checked
371
        # too
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
372
        builder = _mod_index.GraphIndexBuilder(reference_lists=2)
373
        self.assertRaises(_mod_index.BadIndexKey, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
374
            'data aa', ([], ['a bad key']))
2592.1.14 by Robert Collins
Detect bad reference key values.
375
2592.1.15 by Robert Collins
Detect duplicate key insertion.
376
    def test_add_duplicate_key(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
377
        builder = _mod_index.GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
378
        builder.add_node(('key', ), 'data')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
379
        self.assertRaises(_mod_index.BadIndexDuplicateKey,
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
380
                          builder.add_node, ('key', ), 'data')
2592.1.15 by Robert Collins
Detect duplicate key insertion.
381
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
382
    def test_add_duplicate_key_2_elements(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
383
        builder = _mod_index.GraphIndexBuilder(key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
384
        builder.add_node(('key', 'key'), 'data')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
385
        self.assertRaises(_mod_index.BadIndexDuplicateKey, builder.add_node,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
386
            ('key', 'key'), 'data')
387
2592.1.16 by Robert Collins
Can add keys after referencing them.
388
    def test_add_key_after_referencing_key(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
389
        builder = _mod_index.GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
390
        builder.add_node(('key', ), 'data', ([('reference', )], ))
391
        builder.add_node(('reference', ), 'data', ([],))
2592.1.16 by Robert Collins
Can add keys after referencing them.
392
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
393
    def test_add_key_after_referencing_key_2_elements(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
394
        builder = _mod_index.GraphIndexBuilder(reference_lists=1, key_elements=2)
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
395
        builder.add_node(('k', 'ey'), 'data', ([('reference', 'tokey')], ))
396
        builder.add_node(('reference', 'tokey'), 'data', ([],))
397
3777.5.3 by John Arbash Meinel
Add Builder.set_optimize(for_size=True) for GraphIndexBuilder and BTreeBuilder.
398
    def test_set_optimize(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
399
        builder = _mod_index.GraphIndexBuilder(reference_lists=1, key_elements=2)
3777.5.3 by John Arbash Meinel
Add Builder.set_optimize(for_size=True) for GraphIndexBuilder and BTreeBuilder.
400
        builder.set_optimize(for_size=True)
401
        self.assertTrue(builder._optimize_for_size)
402
        builder.set_optimize(for_size=False)
403
        self.assertFalse(builder._optimize_for_size)
404
2592.1.5 by Robert Collins
Trivial index reading.
405
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
406
class TestGraphIndex(tests.TestCaseWithMemoryTransport):
2592.1.5 by Robert Collins
Trivial index reading.
407
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
408
    def make_key(self, number):
409
        return (str(number) + 'X'*100,)
410
411
    def make_value(self, number):
412
            return str(number) + 'Y'*100
413
414
    def make_nodes(self, count=64):
415
        # generate a big enough index that we only read some of it on a typical
416
        # bisection lookup.
417
        nodes = []
418
        for counter in range(count):
419
            nodes.append((self.make_key(counter), self.make_value(counter), ()))
420
        return nodes
421
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
422
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
423
        builder = _mod_index.GraphIndexBuilder(ref_lists, key_elements=key_elements)
2624.2.17 by Robert Collins
Review feedback.
424
        for key, value, references in nodes:
425
            builder.add_node(key, value, references)
2592.1.5 by Robert Collins
Trivial index reading.
426
        stream = builder.finish()
6083.1.1 by Jelmer Vernooij
Use get_transport_from_{url,path} in more places.
427
        trans = transport.get_transport_from_url('trace+' + self.get_url())
2890.2.1 by Robert Collins
* ``bzrlib.index.GraphIndex`` now requires a size parameter to the
428
        size = trans.put_file('index', stream)
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
429
        return _mod_index.GraphIndex(trans, 'index', size)
2592.1.5 by Robert Collins
Trivial index reading.
430
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
431
    def make_index_with_offset(self, ref_lists=0, key_elements=1, nodes=[],
432
                               offset=0):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
433
        builder = _mod_index.GraphIndexBuilder(ref_lists, key_elements=key_elements)
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
434
        for key, value, references in nodes:
435
            builder.add_node(key, value, references)
436
        content = builder.finish().read()
437
        size = len(content)
438
        trans = self.get_transport()
439
        trans.put_bytes('index', (' '*offset) + content)
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
440
        return _mod_index.GraphIndex(trans, 'index', size, offset=offset)
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
441
4744.2.6 by John Arbash Meinel
Start exposing an GraphIndex.clear_cache() member.
442
    def test_clear_cache(self):
443
        index = self.make_index()
444
        # For now, we just want to make sure the api is available. As this is
445
        # old code, we don't really worry if it *does* anything.
446
        index.clear_cache()
447
2592.1.7 by Robert Collins
A validate that goes boom.
448
    def test_open_bad_index_no_error(self):
449
        trans = self.get_transport()
450
        trans.put_bytes('name', "not an index\n")
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
451
        idx = _mod_index.GraphIndex(trans, 'name', 13)
2592.1.7 by Robert Collins
A validate that goes boom.
452
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
453
    def test_with_offset(self):
454
        nodes = self.make_nodes(200)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
455
        idx = self.make_index_with_offset(offset=1234567, nodes=nodes)
456
        self.assertEqual(200, idx.key_count())
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
457
458
    def test_buffer_all_with_offset(self):
459
        nodes = self.make_nodes(200)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
460
        idx = self.make_index_with_offset(offset=1234567, nodes=nodes)
461
        idx._buffer_all()
462
        self.assertEqual(200, idx.key_count())
5074.4.3 by John Arbash Meinel
Actually implement offset support for GraphIndex.
463
464
    def test_side_effect_buffering_with_offset(self):
465
        nodes = self.make_nodes(20)
466
        index = self.make_index_with_offset(offset=1234567, nodes=nodes)
467
        index._transport.recommended_page_size = lambda:64*1024
468
        subset_nodes = [nodes[0][0], nodes[10][0], nodes[19][0]]
469
        entries = [n[1] for n in index.iter_entries(subset_nodes)]
470
        self.assertEqual(sorted(subset_nodes), sorted(entries))
471
        self.assertEqual(20, index.key_count())
5074.4.2 by John Arbash Meinel
Add 'offset=' to the GraphIndex api, but refuse to let it be nonzero for now.
472
2890.2.2 by Robert Collins
Opening an index creates a map for the parsed bytes.
473
    def test_open_sets_parsed_map_empty(self):
474
        index = self.make_index()
475
        self.assertEqual([], index._parsed_byte_map)
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
476
        self.assertEqual([], index._parsed_key_map)
477
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
478
    def test_key_count_buffers(self):
479
        index = self.make_index(nodes=self.make_nodes(2))
480
        # reset the transport log
481
        del index._transport._activity[:]
482
        self.assertEqual(2, index.key_count())
483
        # We should have requested reading the header bytes
484
        self.assertEqual([
485
            ('readv', 'index', [(0, 200)], True, index._size),
486
            ],
487
            index._transport._activity)
488
        # And that should have been enough to trigger reading the whole index
489
        # with buffering
490
        self.assertIsNot(None, index._nodes)
491
492
    def test_lookup_key_via_location_buffers(self):
493
        index = self.make_index()
494
        # reset the transport log
495
        del index._transport._activity[:]
496
        # do a _lookup_keys_via_location call for the middle of the file, which
497
        # is what bisection uses.
498
        result = index._lookup_keys_via_location(
499
            [(index._size // 2, ('missing', ))])
500
        # this should have asked for a readv request, with adjust_for_latency,
501
        # and two regions: the header, and half-way into the file.
502
        self.assertEqual([
503
            ('readv', 'index', [(30, 30), (0, 200)], True, 60),
504
            ],
505
            index._transport._activity)
506
        # and the result should be that the key cannot be present, because this
507
        # is a trivial index.
508
        self.assertEqual([((index._size // 2, ('missing', )), False)],
509
            result)
510
        # And this should have caused the file to be fully buffered
511
        self.assertIsNot(None, index._nodes)
512
        self.assertEqual([], index._parsed_byte_map)
513
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
514
    def test_first_lookup_key_via_location(self):
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
515
        # We need enough data so that the _HEADER_READV doesn't consume the
516
        # whole file. We always read 800 bytes for every key, and the local
517
        # transport natural expansion is 4096 bytes. So we have to have >8192
518
        # bytes or we will trigger "buffer_all".
519
        # We also want the 'missing' key to fall within the range that *did*
520
        # read
521
        nodes = []
522
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
523
        # reset the transport log
524
        del index._transport._activity[:]
2890.2.18 by Robert Collins
Review feedback.
525
        # do a _lookup_keys_via_location call for the middle of the file, which
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
526
        # is what bisection uses.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
527
        start_lookup = index._size // 2
2890.2.18 by Robert Collins
Review feedback.
528
        result = index._lookup_keys_via_location(
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
529
            [(start_lookup, ('40missing', ))])
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
530
        # this should have asked for a readv request, with adjust_for_latency,
531
        # and two regions: the header, and half-way into the file.
532
        self.assertEqual([
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
533
            ('readv', 'index',
534
             [(start_lookup, 800), (0, 200)], True, index._size),
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
535
            ],
536
            index._transport._activity)
537
        # and the result should be that the key cannot be present, because this
538
        # is a trivial index.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
539
        self.assertEqual([((start_lookup, ('40missing', )), False)],
540
            result)
541
        # And this should not have caused the file to be fully buffered
542
        self.assertIs(None, index._nodes)
543
        # And the regions of the file that have been parsed should be in the
544
        # parsed_byte_map and the parsed_key_map
545
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
546
        self.assertEqual([(None, self.make_key(26)),
547
                          (self.make_key(31), self.make_key(48))],
548
                         index._parsed_key_map)
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
549
550
    def test_parsing_non_adjacent_data_trims(self):
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
551
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.18 by Robert Collins
Review feedback.
552
        result = index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
553
            [(index._size // 2, ('40', ))])
554
        # and the result should be that the key cannot be present, because key is
555
        # in the middle of the observed data from a 4K read - the smallest transport
556
        # will do today with this api.
557
        self.assertEqual([((index._size // 2, ('40', )), False)],
558
            result)
559
        # and we should have a parse map that includes the header and the
560
        # region that was parsed after trimming.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
561
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
562
        self.assertEqual([(None, self.make_key(26)),
563
                          (self.make_key(31), self.make_key(48))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
564
            index._parsed_key_map)
565
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
566
    def test_parsing_data_handles_parsed_contained_regions(self):
567
        # the following patten creates a parsed region that is wholly within a
568
        # single result from the readv layer:
569
        # .... single-read (readv-minimum-size) ...
570
        # which then trims the start and end so the parsed size is < readv
571
        # miniumum.
572
        # then a dual lookup (or a reference lookup for that matter) which
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
573
        # abuts or overlaps the parsed region on both sides will need to
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
574
        # discard the data in the middle, but parse the end as well.
575
        #
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
576
        # we test this by doing a single lookup to seed the data, then
577
        # a lookup for two keys that are present, and adjacent -
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
578
        # we except both to be found, and the parsed byte map to include the
579
        # locations of both keys.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
580
        index = self.make_index(nodes=self.make_nodes(128))
2890.2.18 by Robert Collins
Review feedback.
581
        result = index._lookup_keys_via_location(
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
582
            [(index._size // 2, ('40', ))])
583
        # and we should have a parse map that includes the header and the
584
        # region that was parsed after trimming.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
585
        self.assertEqual([(0, 4045), (11759, 15707)], index._parsed_byte_map)
586
        self.assertEqual([(None, self.make_key(116)),
587
                          (self.make_key(35), self.make_key(51))],
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
588
            index._parsed_key_map)
589
        # now ask for two keys, right before and after the parsed region
2890.2.18 by Robert Collins
Review feedback.
590
        result = index._lookup_keys_via_location(
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
591
            [(11450, self.make_key(34)), (15707, self.make_key(52))])
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
592
        self.assertEqual([
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
593
            ((11450, self.make_key(34)),
594
             (index, self.make_key(34), self.make_value(34))),
595
            ((15707, self.make_key(52)),
596
             (index, self.make_key(52), self.make_value(52))),
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
597
            ],
598
            result)
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
599
        self.assertEqual([(0, 4045), (9889, 17993)], index._parsed_byte_map)
2890.2.14 by Robert Collins
Parse more than one segment of data from a single readv response if needed.
600
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
601
    def test_lookup_missing_key_answers_without_io_when_map_permits(self):
602
        # generate a big enough index that we only read some of it on a typical
603
        # bisection lookup.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
604
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
605
        # lookup the keys in the middle of the file
2890.2.18 by Robert Collins
Review feedback.
606
        result =index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
607
            [(index._size // 2, ('40', ))])
608
        # check the parse map, this determines the test validity
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
609
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
610
        self.assertEqual([(None, self.make_key(26)),
611
                          (self.make_key(31), self.make_key(48))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
612
            index._parsed_key_map)
613
        # reset the transport log
614
        del index._transport._activity[:]
615
        # now looking up a key in the portion of the file already parsed should
616
        # not create a new transport request, and should return False (cannot
617
        # be in the index) - even when the byte location we ask for is outside
618
        # the parsed region
2890.2.18 by Robert Collins
Review feedback.
619
        result = index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
620
            [(4000, ('40', ))])
621
        self.assertEqual([((4000, ('40', )), False)],
622
            result)
623
        self.assertEqual([], index._transport._activity)
624
625
    def test_lookup_present_key_answers_without_io_when_map_permits(self):
626
        # generate a big enough index that we only read some of it on a typical
627
        # bisection lookup.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
628
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
629
        # lookup the keys in the middle of the file
2890.2.18 by Robert Collins
Review feedback.
630
        result =index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
631
            [(index._size // 2, ('40', ))])
632
        # check the parse map, this determines the test validity
633
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
634
        self.assertEqual([(None, self.make_key(26)),
635
                          (self.make_key(31), self.make_key(48))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
636
            index._parsed_key_map)
637
        # reset the transport log
638
        del index._transport._activity[:]
639
        # now looking up a key in the portion of the file already parsed should
640
        # not create a new transport request, and should return False (cannot
641
        # be in the index) - even when the byte location we ask for is outside
642
        # the parsed region
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
643
        #
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
644
        result = index._lookup_keys_via_location([(4000, self.make_key(40))])
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
645
        self.assertEqual(
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
646
            [((4000, self.make_key(40)),
647
              (index, self.make_key(40), self.make_value(40)))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
648
            result)
649
        self.assertEqual([], index._transport._activity)
650
651
    def test_lookup_key_below_probed_area(self):
652
        # generate a big enough index that we only read some of it on a typical
653
        # bisection lookup.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
654
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
655
        # ask for the key in the middle, but a key that is located in the
656
        # unparsed region before the middle.
2890.2.18 by Robert Collins
Review feedback.
657
        result =index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
658
            [(index._size // 2, ('30', ))])
659
        # check the parse map, this determines the test validity
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
660
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
661
        self.assertEqual([(None, self.make_key(26)),
662
                          (self.make_key(31), self.make_key(48))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
663
            index._parsed_key_map)
664
        self.assertEqual([((index._size // 2, ('30', )), -1)],
665
            result)
666
667
    def test_lookup_key_above_probed_area(self):
668
        # generate a big enough index that we only read some of it on a typical
669
        # bisection lookup.
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
670
        index = self.make_index(nodes=self.make_nodes(64))
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
671
        # ask for the key in the middle, but a key that is located in the
672
        # unparsed region after the middle.
2890.2.18 by Robert Collins
Review feedback.
673
        result =index._lookup_keys_via_location(
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
674
            [(index._size // 2, ('50', ))])
675
        # check the parse map, this determines the test validity
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
676
        self.assertEqual([(0, 4008), (5046, 8996)], index._parsed_byte_map)
677
        self.assertEqual([(None, self.make_key(26)),
678
                          (self.make_key(31), self.make_key(48))],
2890.2.5 by Robert Collins
Create a content lookup function for bisection in GraphIndex.
679
            index._parsed_key_map)
680
        self.assertEqual([((index._size // 2, ('50', )), +1)],
681
            result)
2890.2.2 by Robert Collins
Opening an index creates a map for the parsed bytes.
682
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
683
    def test_lookup_key_resolves_references(self):
684
        # generate a big enough index that we only read some of it on a typical
685
        # bisection lookup.
686
        nodes = []
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
687
        for counter in range(99):
688
            nodes.append((self.make_key(counter), self.make_value(counter),
689
                ((self.make_key(counter + 20),),)  ))
690
        index = self.make_index(ref_lists=1, nodes=nodes)
691
        # lookup a key in the middle that does not exist, so that when we can
692
        # check that the referred-to-keys are not accessed automatically.
693
        index_size = index._size
694
        index_center = index_size // 2
695
        result = index._lookup_keys_via_location(
696
            [(index_center, ('40', ))])
697
        # check the parse map - only the start and middle should have been
698
        # parsed.
699
        self.assertEqual([(0, 4027), (10198, 14028)], index._parsed_byte_map)
700
        self.assertEqual([(None, self.make_key(17)),
701
                          (self.make_key(44), self.make_key(5))],
702
            index._parsed_key_map)
703
        # and check the transport activity likewise.
704
        self.assertEqual(
705
            [('readv', 'index', [(index_center, 800), (0, 200)], True,
706
                                  index_size)],
707
            index._transport._activity)
708
        # reset the transport log for testing the reference lookup
709
        del index._transport._activity[:]
710
        # now looking up a key in the portion of the file already parsed should
711
        # only perform IO to resolve its key references.
712
        result = index._lookup_keys_via_location([(11000, self.make_key(45))])
713
        self.assertEqual(
714
            [((11000, self.make_key(45)),
715
              (index, self.make_key(45), self.make_value(45),
716
               ((self.make_key(65),),)))],
717
            result)
718
        self.assertEqual([('readv', 'index', [(15093, 800)], True, index_size)],
719
            index._transport._activity)
720
721
    def test_lookup_key_can_buffer_all(self):
722
        nodes = []
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
723
        for counter in range(64):
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
724
            nodes.append((self.make_key(counter), self.make_value(counter),
725
                ((self.make_key(counter + 20),),)  ))
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
726
        index = self.make_index(ref_lists=1, nodes=nodes)
727
        # lookup a key in the middle that does not exist, so that when we can
728
        # check that the referred-to-keys are not accessed automatically.
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
729
        index_size = index._size
730
        index_center = index_size // 2
731
        result = index._lookup_keys_via_location([(index_center, ('40', ))])
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
732
        # check the parse map - only the start and middle should have been
733
        # parsed.
734
        self.assertEqual([(0, 3890), (6444, 10274)], index._parsed_byte_map)
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
735
        self.assertEqual([(None, self.make_key(25)),
736
                          (self.make_key(37), self.make_key(52))],
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
737
            index._parsed_key_map)
738
        # and check the transport activity likewise.
739
        self.assertEqual(
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
740
            [('readv', 'index', [(index_center, 800), (0, 200)], True,
741
                                  index_size)],
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
742
            index._transport._activity)
743
        # reset the transport log for testing the reference lookup
744
        del index._transport._activity[:]
745
        # now looking up a key in the portion of the file already parsed should
746
        # only perform IO to resolve its key references.
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
747
        result = index._lookup_keys_via_location([(7000, self.make_key(40))])
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
748
        self.assertEqual(
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
749
            [((7000, self.make_key(40)),
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
750
              (index, self.make_key(40), self.make_value(40),
751
               ((self.make_key(60),),)))],
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
752
            result)
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
753
        # Resolving the references would have required more data read, and we
754
        # are already above the 50% threshold, so it triggered a _buffer_all
755
        self.assertEqual([('get', 'index')], index._transport._activity)
2890.2.6 by Robert Collins
Add support for key references to the index lookup_keys_via_location bisection interface.
756
2592.1.5 by Robert Collins
Trivial index reading.
757
    def test_iter_all_entries_empty(self):
758
        index = self.make_index()
759
        self.assertEqual([], list(index.iter_all_entries()))
760
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
761
    def test_iter_all_entries_simple(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
762
        index = self.make_index(nodes=[(('name', ), 'data', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
763
        self.assertEqual([(index, ('name', ), 'data')],
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
764
            list(index.iter_all_entries()))
765
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
766
    def test_iter_all_entries_simple_2_elements(self):
767
        index = self.make_index(key_elements=2,
768
            nodes=[(('name', 'surname'), 'data', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
769
        self.assertEqual([(index, ('name', 'surname'), 'data')],
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
770
            list(index.iter_all_entries()))
771
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
772
    def test_iter_all_entries_references_resolved(self):
773
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
774
            (('name', ), 'data', ([('ref', )], )),
775
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
776
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),)),
777
            (index, ('ref', ), 'refdata', ((), ))},
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
778
            set(index.iter_all_entries()))
779
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
780
    def test_iter_entries_buffers_once(self):
781
        index = self.make_index(nodes=self.make_nodes(2))
782
        # reset the transport log
783
        del index._transport._activity[:]
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
784
        self.assertEqual({(index, self.make_key(1), self.make_value(1))},
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
785
                         set(index.iter_entries([self.make_key(1)])))
786
        # We should have requested reading the header bytes
787
        # But not needed any more than that because it would have triggered a
788
        # buffer all
789
        self.assertEqual([
790
            ('readv', 'index', [(0, 200)], True, index._size),
791
            ],
792
            index._transport._activity)
793
        # And that should have been enough to trigger reading the whole index
794
        # with buffering
795
        self.assertIsNot(None, index._nodes)
796
3665.3.3 by John Arbash Meinel
If we read more than 50% of the whole index,
797
    def test_iter_entries_buffers_by_bytes_read(self):
798
        index = self.make_index(nodes=self.make_nodes(64))
799
        list(index.iter_entries([self.make_key(10)]))
800
        # The first time through isn't enough to trigger a buffer all
801
        self.assertIs(None, index._nodes)
802
        self.assertEqual(4096, index._bytes_read)
803
        # Grabbing a key in that same page won't trigger a buffer all, as we
804
        # still haven't read 50% of the file
805
        list(index.iter_entries([self.make_key(11)]))
806
        self.assertIs(None, index._nodes)
807
        self.assertEqual(4096, index._bytes_read)
808
        # We haven't read more data, so reading outside the range won't trigger
809
        # a buffer all right away
810
        list(index.iter_entries([self.make_key(40)]))
811
        self.assertIs(None, index._nodes)
812
        self.assertEqual(8192, index._bytes_read)
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
813
        # On the next pass, we will not trigger buffer all if the key is
814
        # available without reading more
3665.3.3 by John Arbash Meinel
If we read more than 50% of the whole index,
815
        list(index.iter_entries([self.make_key(32)]))
3665.3.5 by John Arbash Meinel
Move the point at which we 'buffer_all' if we've read >50% of the index.
816
        self.assertIs(None, index._nodes)
817
        # But if we *would* need to read more to resolve it, then we will
818
        # buffer all.
819
        list(index.iter_entries([self.make_key(60)]))
3665.3.3 by John Arbash Meinel
If we read more than 50% of the whole index,
820
        self.assertIsNot(None, index._nodes)
821
2890.2.10 by Robert Collins
Add test coverage to ensure \r's are not mangled by bisection parsing.
822
    def test_iter_entries_references_resolved(self):
823
        index = self.make_index(1, nodes=[
824
            (('name', ), 'data', ([('ref', ), ('ref', )], )),
825
            (('ref', ), 'refdata', ([], ))])
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
826
        self.assertEqual({(index, ('name', ), 'data', ((('ref',), ('ref',)),)),
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
827
            (index, ('ref', ), 'refdata', ((), ))},
2890.2.10 by Robert Collins
Add test coverage to ensure \r's are not mangled by bisection parsing.
828
            set(index.iter_entries([('name',), ('ref',)])))
829
830
    def test_iter_entries_references_2_refs_resolved(self):
831
        index = self.make_index(2, nodes=[
832
            (('name', ), 'data', ([('ref', )], [('ref', )])),
833
            (('ref', ), 'refdata', ([], []))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
834
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),), (('ref',),))),
835
            (index, ('ref', ), 'refdata', ((), ()))},
2890.2.10 by Robert Collins
Add test coverage to ensure \r's are not mangled by bisection parsing.
836
            set(index.iter_entries([('name',), ('ref',)])))
837
2592.1.30 by Robert Collins
Absent entries are not yeilded.
838
    def test_iteration_absent_skipped(self):
839
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
840
            (('name', ), 'data', ([('ref', )], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
841
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),))},
2592.1.30 by Robert Collins
Absent entries are not yeilded.
842
            set(index.iter_all_entries()))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
843
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),))},
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
844
            set(index.iter_entries([('name', )])))
845
        self.assertEqual([], list(index.iter_entries([('ref', )])))
2592.1.30 by Robert Collins
Absent entries are not yeilded.
846
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
847
    def test_iteration_absent_skipped_2_element_keys(self):
848
        index = self.make_index(1, key_elements=2, nodes=[
849
            (('name', 'fin'), 'data', ([('ref', 'erence')], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
850
        self.assertEqual({(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
851
            set(index.iter_all_entries()))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
852
        self.assertEqual({(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
853
            set(index.iter_entries([('name', 'fin')])))
854
        self.assertEqual([], list(index.iter_entries([('ref', 'erence')])))
855
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
856
    def test_iter_all_keys(self):
2592.1.29 by Robert Collins
Basic iter_entries working.
857
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
858
            (('name', ), 'data', ([('ref', )], )),
859
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
860
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),)),
861
            (index, ('ref', ), 'refdata', ((), ))},
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
862
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.29 by Robert Collins
Basic iter_entries working.
863
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
864
    def test_iter_nothing_empty(self):
2592.1.9 by Robert Collins
Iterating no keys should work too.
865
        index = self.make_index()
866
        self.assertEqual([], list(index.iter_entries([])))
867
2592.1.5 by Robert Collins
Trivial index reading.
868
    def test_iter_missing_entry_empty(self):
869
        index = self.make_index()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
870
        self.assertEqual([], list(index.iter_entries([('a', )])))
2592.1.7 by Robert Collins
A validate that goes boom.
871
2890.2.8 by Robert Collins
Make the size of the index optionally None for the pack-names index.
872
    def test_iter_missing_entry_empty_no_size(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
873
        idx = self.make_index()
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
874
        idx = _mod_index.GraphIndex(idx._transport, 'index', None)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
875
        self.assertEqual([], list(idx.iter_entries([('a', )])))
2890.2.8 by Robert Collins
Make the size of the index optionally None for the pack-names index.
876
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
877
    def test_iter_key_prefix_1_element_key_None(self):
878
        index = self.make_index()
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
879
        self.assertRaises(_mod_index.BadIndexKey, list,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
880
            index.iter_entries_prefix([(None, )]))
881
882
    def test_iter_key_prefix_wrong_length(self):
883
        index = self.make_index()
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
884
        self.assertRaises(_mod_index.BadIndexKey, list,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
885
            index.iter_entries_prefix([('foo', None)]))
886
        index = self.make_index(key_elements=2)
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
887
        self.assertRaises(_mod_index.BadIndexKey, list,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
888
            index.iter_entries_prefix([('foo', )]))
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
889
        self.assertRaises(_mod_index.BadIndexKey, list,
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
890
            index.iter_entries_prefix([('foo', None, None)]))
891
892
    def test_iter_key_prefix_1_key_element_no_refs(self):
893
        index = self.make_index( nodes=[
894
            (('name', ), 'data', ()),
895
            (('ref', ), 'refdata', ())])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
896
        self.assertEqual({(index, ('name', ), 'data'),
897
            (index, ('ref', ), 'refdata')},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
898
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
899
900
    def test_iter_key_prefix_1_key_element_refs(self):
901
        index = self.make_index(1, nodes=[
902
            (('name', ), 'data', ([('ref', )], )),
903
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
904
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),)),
905
            (index, ('ref', ), 'refdata', ((), ))},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
906
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
907
908
    def test_iter_key_prefix_2_key_element_no_refs(self):
909
        index = self.make_index(key_elements=2, nodes=[
910
            (('name', 'fin1'), 'data', ()),
911
            (('name', 'fin2'), 'beta', ()),
912
            (('ref', 'erence'), 'refdata', ())])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
913
        self.assertEqual({(index, ('name', 'fin1'), 'data'),
914
            (index, ('ref', 'erence'), 'refdata')},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
915
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
916
        self.assertEqual({(index, ('name', 'fin1'), 'data'),
917
            (index, ('name', 'fin2'), 'beta')},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
918
            set(index.iter_entries_prefix([('name', None)])))
919
920
    def test_iter_key_prefix_2_key_element_refs(self):
921
        index = self.make_index(1, key_elements=2, nodes=[
922
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
923
            (('name', 'fin2'), 'beta', ([], )),
924
            (('ref', 'erence'), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
925
        self.assertEqual({(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
926
            (index, ('ref', 'erence'), 'refdata', ((), ))},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
927
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
928
        self.assertEqual({(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
929
            (index, ('name', 'fin2'), 'beta', ((), ))},
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
930
            set(index.iter_entries_prefix([('name', None)])))
931
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
932
    def test_key_count_empty(self):
933
        index = self.make_index()
934
        self.assertEqual(0, index.key_count())
935
936
    def test_key_count_one(self):
937
        index = self.make_index(nodes=[(('name', ), '', ())])
938
        self.assertEqual(1, index.key_count())
939
940
    def test_key_count_two(self):
941
        index = self.make_index(nodes=[
942
            (('name', ), '', ()), (('foo', ), '', ())])
943
        self.assertEqual(2, index.key_count())
944
3665.3.3 by John Arbash Meinel
If we read more than 50% of the whole index,
945
    def test_read_and_parse_tracks_real_read_value(self):
946
        index = self.make_index(nodes=self.make_nodes(10))
947
        del index._transport._activity[:]
948
        index._read_and_parse([(0, 200)])
949
        self.assertEqual([
950
            ('readv', 'index', [(0, 200)], True, index._size),
951
            ],
952
            index._transport._activity)
953
        # The readv expansion code will expand the initial request to 4096
954
        # bytes, which is more than enough to read the entire index, and we
955
        # will track the fact that we read that many bytes.
956
        self.assertEqual(index._size, index._bytes_read)
957
958
    def test_read_and_parse_triggers_buffer_all(self):
3665.3.1 by John Arbash Meinel
Updates to GraphIndex processing.
959
        index = self.make_index(key_elements=2, nodes=[
960
            (('name', 'fin1'), 'data', ()),
961
            (('name', 'fin2'), 'beta', ()),
962
            (('ref', 'erence'), 'refdata', ())])
963
        self.assertTrue(index._size > 0)
964
        self.assertIs(None, index._nodes)
965
        index._read_and_parse([(0, index._size)])
966
        self.assertIsNot(None, index._nodes)
967
2592.1.7 by Robert Collins
A validate that goes boom.
968
    def test_validate_bad_index_errors(self):
969
        trans = self.get_transport()
970
        trans.put_bytes('name', "not an index\n")
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
971
        idx = _mod_index.GraphIndex(trans, 'name', 13)
972
        self.assertRaises(_mod_index.BadIndexFormatSignature, idx.validate)
2592.1.8 by Robert Collins
Empty files should validate ok.
973
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
974
    def test_validate_bad_node_refs(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
975
        idx = self.make_index(2)
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
976
        trans = self.get_transport()
977
        content = trans.get_bytes('index')
978
        # change the options line to end with a rather than a parseable number
979
        new_content = content[:-2] + 'a\n\n'
980
        trans.put_bytes('index', new_content)
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
981
        self.assertRaises(_mod_index.BadIndexOptions, idx.validate)
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
982
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
983
    def test_validate_missing_end_line_empty(self):
2592.1.11 by Robert Collins
Detect truncated indices.
984
        index = self.make_index(2)
985
        trans = self.get_transport()
986
        content = trans.get_bytes('index')
987
        # truncate the last byte
988
        trans.put_bytes('index', content[:-1])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
989
        self.assertRaises(_mod_index.BadIndexData, index.validate)
2592.1.11 by Robert Collins
Detect truncated indices.
990
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
991
    def test_validate_missing_end_line_nonempty(self):
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
992
        index = self.make_index(2, nodes=[(('key', ), '', ([], []))])
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
993
        trans = self.get_transport()
994
        content = trans.get_bytes('index')
995
        # truncate the last byte
996
        trans.put_bytes('index', content[:-1])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
997
        self.assertRaises(_mod_index.BadIndexData, index.validate)
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
998
2592.1.8 by Robert Collins
Empty files should validate ok.
999
    def test_validate_empty(self):
1000
        index = self.make_index()
1001
        index.validate()
2592.1.12 by Robert Collins
Handle basic node adds.
1002
1003
    def test_validate_no_refs_content(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1004
        index = self.make_index(nodes=[(('key', ), 'value', ())])
2592.1.12 by Robert Collins
Handle basic node adds.
1005
        index.validate()
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1006
4011.5.3 by Andrew Bennetts
Implement and test external_references on GraphIndex and BTreeGraphIndex.
1007
    # XXX: external_references tests are duplicated in test_btree_index.  We
1008
    # probably should have per_graph_index tests...
1009
    def test_external_references_no_refs(self):
1010
        index = self.make_index(ref_lists=0, nodes=[])
1011
        self.assertRaises(ValueError, index.external_references, 0)
1012
1013
    def test_external_references_no_results(self):
1014
        index = self.make_index(ref_lists=1, nodes=[
1015
            (('key',), 'value', ([],))])
1016
        self.assertEqual(set(), index.external_references(0))
1017
1018
    def test_external_references_missing_ref(self):
1019
        missing_key = ('missing',)
1020
        index = self.make_index(ref_lists=1, nodes=[
1021
            (('key',), 'value', ([missing_key],))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1022
        self.assertEqual({missing_key}, index.external_references(0))
4011.5.3 by Andrew Bennetts
Implement and test external_references on GraphIndex and BTreeGraphIndex.
1023
1024
    def test_external_references_multiple_ref_lists(self):
1025
        missing_key = ('missing',)
1026
        index = self.make_index(ref_lists=2, nodes=[
1027
            (('key',), 'value', ([], [missing_key]))])
1028
        self.assertEqual(set([]), index.external_references(0))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1029
        self.assertEqual({missing_key}, index.external_references(1))
4011.5.3 by Andrew Bennetts
Implement and test external_references on GraphIndex and BTreeGraphIndex.
1030
1031
    def test_external_references_two_records(self):
1032
        index = self.make_index(ref_lists=1, nodes=[
1033
            (('key-1',), 'value', ([('key-2',)],)),
1034
            (('key-2',), 'value', ([],)),
1035
            ])
1036
        self.assertEqual(set([]), index.external_references(0))
1037
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1038
    def test__find_ancestors(self):
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1039
        key1 = ('key-1',)
1040
        key2 = ('key-2',)
1041
        index = self.make_index(ref_lists=1, key_elements=1, nodes=[
1042
            (key1, 'value', ([key2],)),
1043
            (key2, 'value', ([],)),
1044
            ])
1045
        parent_map = {}
1046
        missing_keys = set()
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1047
        search_keys = index._find_ancestors([key1], 0, parent_map, missing_keys)
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1048
        self.assertEqual({key1: (key2,)}, parent_map)
1049
        self.assertEqual(set(), missing_keys)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1050
        self.assertEqual({key2}, search_keys)
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1051
        search_keys = index._find_ancestors(search_keys, 0, parent_map,
1052
                                            missing_keys)
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1053
        self.assertEqual({key1: (key2,), key2: ()}, parent_map)
1054
        self.assertEqual(set(), missing_keys)
1055
        self.assertEqual(set(), search_keys)
1056
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1057
    def test__find_ancestors_w_missing(self):
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1058
        key1 = ('key-1',)
1059
        key2 = ('key-2',)
1060
        key3 = ('key-3',)
1061
        index = self.make_index(ref_lists=1, key_elements=1, nodes=[
1062
            (key1, 'value', ([key2],)),
1063
            (key2, 'value', ([],)),
1064
            ])
1065
        parent_map = {}
1066
        missing_keys = set()
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1067
        search_keys = index._find_ancestors([key2, key3], 0, parent_map,
1068
                                            missing_keys)
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1069
        self.assertEqual({key2: ()}, parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1070
        self.assertEqual({key3}, missing_keys)
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1071
        self.assertEqual(set(), search_keys)
1072
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1073
    def test__find_ancestors_dont_search_known(self):
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1074
        key1 = ('key-1',)
1075
        key2 = ('key-2',)
1076
        key3 = ('key-3',)
1077
        index = self.make_index(ref_lists=1, key_elements=1, nodes=[
1078
            (key1, 'value', ([key2],)),
1079
            (key2, 'value', ([key3],)),
1080
            (key3, 'value', ([],)),
1081
            ])
1082
        # We already know about key2, so we won't try to search for key3
1083
        parent_map = {key2: (key3,)}
1084
        missing_keys = set()
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1085
        search_keys = index._find_ancestors([key1], 0, parent_map,
1086
                                            missing_keys)
4593.4.7 by John Arbash Meinel
Basic implementation of a conforming interface for GraphIndex.
1087
        self.assertEqual({key1: (key2,), key2: (key3,)}, parent_map)
1088
        self.assertEqual(set(), missing_keys)
1089
        self.assertEqual(set(), search_keys)
1090
4634.71.1 by John Arbash Meinel
Work around bug #402623 by allowing BTreeGraphIndex(...,unlimited_cache=True).
1091
    def test_supports_unlimited_cache(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1092
        builder = _mod_index.GraphIndexBuilder(0, key_elements=1)
4634.71.1 by John Arbash Meinel
Work around bug #402623 by allowing BTreeGraphIndex(...,unlimited_cache=True).
1093
        stream = builder.finish()
5609.9.4 by Vincent Ladeuil
Use self.get_transport instead of transport.get_transport where possible.
1094
        trans = self.get_transport()
4634.71.1 by John Arbash Meinel
Work around bug #402623 by allowing BTreeGraphIndex(...,unlimited_cache=True).
1095
        size = trans.put_file('index', stream)
1096
        # It doesn't matter what unlimited_cache does here, just that it can be
1097
        # passed
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1098
        idx = _mod_index.GraphIndex(trans, 'index', size, unlimited_cache=True)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1099
1100
1101
class TestCombinedGraphIndex(tests.TestCaseWithMemoryTransport):
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1102
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
1103
    def make_index(self, name, ref_lists=0, key_elements=1, nodes=[]):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1104
        builder = _mod_index.GraphIndexBuilder(ref_lists, key_elements=key_elements)
2624.2.17 by Robert Collins
Review feedback.
1105
        for key, value, references in nodes:
1106
            builder.add_node(key, value, references)
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1107
        stream = builder.finish()
1108
        trans = self.get_transport()
2890.2.1 by Robert Collins
* ``bzrlib.index.GraphIndex`` now requires a size parameter to the
1109
        size = trans.put_file(name, stream)
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1110
        return _mod_index.GraphIndex(trans, name, size)
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1111
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1112
    def make_combined_index_with_missing(self, missing=['1', '2']):
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1113
        """Create a CombinedGraphIndex which will have missing indexes.
1114
1115
        This creates a CGI which thinks it has 2 indexes, however they have
1116
        been deleted. If CGI._reload_func() is called, then it will repopulate
1117
        with a new index.
1118
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1119
        :param missing: The underlying indexes to delete
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1120
        :return: (CombinedGraphIndex, reload_counter)
1121
        """
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1122
        idx1 = self.make_index('1', nodes=[(('1',), '', ())])
1123
        idx2 = self.make_index('2', nodes=[(('2',), '', ())])
1124
        idx3 = self.make_index('3', nodes=[
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1125
            (('1',), '', ()),
1126
            (('2',), '', ())])
1127
1128
        # total_reloads, num_changed, num_unchanged
1129
        reload_counter = [0, 0, 0]
1130
        def reload():
1131
            reload_counter[0] += 1
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1132
            new_indices = [idx3]
1133
            if idx._indices == new_indices:
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1134
                reload_counter[2] += 1
1135
                return False
1136
            reload_counter[1] += 1
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1137
            idx._indices[:] = new_indices
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1138
            return True
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1139
        idx = _mod_index.CombinedGraphIndex([idx1, idx2], reload_func=reload)
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1140
        trans = self.get_transport()
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1141
        for fname in missing:
1142
            trans.delete(fname)
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1143
        return idx, reload_counter
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1144
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1145
    def test_open_missing_index_no_error(self):
1146
        trans = self.get_transport()
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1147
        idx1 = _mod_index.GraphIndex(trans, 'missing', 100)
1148
        idx = _mod_index.CombinedGraphIndex([idx1])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1149
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
1150
    def test_add_index(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1151
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1152
        idx1 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
1153
        idx.insert_index(0, idx1)
1154
        self.assertEqual([(idx1, ('key', ), '')],
1155
                         list(idx.iter_all_entries()))
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
1156
4744.2.6 by John Arbash Meinel
Start exposing an GraphIndex.clear_cache() member.
1157
    def test_clear_cache(self):
1158
        log = []
1159
1160
        class ClearCacheProxy(object):
1161
1162
            def __init__(self, index):
1163
                self._index = index
1164
1165
            def __getattr__(self, name):
1166
                return getattr(self._index)
1167
1168
            def clear_cache(self):
1169
                log.append(self._index)
1170
                return self._index.clear_cache()
1171
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1172
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1173
        idx1 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
1174
        idx.insert_index(0, ClearCacheProxy(idx1))
1175
        idx2 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
1176
        idx.insert_index(1, ClearCacheProxy(idx2))
4744.2.6 by John Arbash Meinel
Start exposing an GraphIndex.clear_cache() member.
1177
        # CombinedGraphIndex should call 'clear_cache()' on all children
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1178
        idx.clear_cache()
1179
        self.assertEqual(sorted([idx1, idx2]), sorted(log))
4744.2.6 by John Arbash Meinel
Start exposing an GraphIndex.clear_cache() member.
1180
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1181
    def test_iter_all_entries_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1182
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1183
        self.assertEqual([], list(idx.iter_all_entries()))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1184
1185
    def test_iter_all_entries_children_empty(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1186
        idx1 = self.make_index('name')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1187
        idx = _mod_index.CombinedGraphIndex([idx1])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1188
        self.assertEqual([], list(idx.iter_all_entries()))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1189
1190
    def test_iter_all_entries_simple(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1191
        idx1 = self.make_index('name', nodes=[(('name', ), 'data', ())])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1192
        idx = _mod_index.CombinedGraphIndex([idx1])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1193
        self.assertEqual([(idx1, ('name', ), 'data')],
1194
            list(idx.iter_all_entries()))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1195
1196
    def test_iter_all_entries_two_indices(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1197
        idx1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
1198
        idx2 = self.make_index('name2', nodes=[(('2', ), '', ())])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1199
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1200
        self.assertEqual([(idx1, ('name', ), 'data'),
1201
                          (idx2, ('2', ), '')],
1202
                         list(idx.iter_all_entries()))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1203
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
1204
    def test_iter_entries_two_indices_dup_key(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1205
        idx1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
1206
        idx2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1207
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1208
        self.assertEqual([(idx1, ('name', ), 'data')],
1209
                         list(idx.iter_entries([('name', )])))
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
1210
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1211
    def test_iter_all_entries_two_indices_dup_key(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1212
        idx1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
1213
        idx2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1214
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1215
        self.assertEqual([(idx1, ('name', ), 'data')],
1216
                         list(idx.iter_all_entries()))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1217
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
1218
    def test_iter_key_prefix_2_key_element_refs(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1219
        idx1 = self.make_index('1', 1, key_elements=2, nodes=[
1220
                (('name', 'fin1'), 'data', ([('ref', 'erence')], ))])
1221
        idx2 = self.make_index('2', 1, key_elements=2, nodes=[
1222
                (('name', 'fin2'), 'beta', ([], )),
1223
                (('ref', 'erence'), 'refdata', ([], ))])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1224
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1225
        self.assertEqual({(idx1, ('name', 'fin1'), 'data',
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1226
                               ((('ref', 'erence'),),)),
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1227
                              (idx2, ('ref', 'erence'), 'refdata', ((), ))},
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1228
                         set(idx.iter_entries_prefix([('name', 'fin1'),
1229
                                                        ('ref', 'erence')])))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1230
        self.assertEqual({(idx1, ('name', 'fin1'), 'data',
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1231
                               ((('ref', 'erence'),),)),
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1232
                              (idx2, ('name', 'fin2'), 'beta', ((), ))},
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1233
                         set(idx.iter_entries_prefix([('name', None)])))
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
1234
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1235
    def test_iter_nothing_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1236
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1237
        self.assertEqual([], list(idx.iter_entries([])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1238
1239
    def test_iter_nothing_children_empty(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1240
        idx1 = self.make_index('name')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1241
        idx = _mod_index.CombinedGraphIndex([idx1])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1242
        self.assertEqual([], list(idx.iter_entries([])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1243
1244
    def test_iter_all_keys(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1245
        idx1 = self.make_index('1', 1, nodes=[(('name', ), 'data',
1246
                                               ([('ref', )], ))])
1247
        idx2 = self.make_index('2', 1, nodes=[(('ref', ), 'refdata', ((), ))])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1248
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1249
        self.assertEqual({(idx1, ('name', ), 'data', ((('ref', ), ), )),
1250
                              (idx2, ('ref', ), 'refdata', ((), ))},
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1251
                         set(idx.iter_entries([('name', ), ('ref', )])))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1252
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1253
    def test_iter_all_keys_dup_entry(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1254
        idx1 = self.make_index('1', 1, nodes=[(('name', ), 'data',
1255
                                                 ([('ref', )], )),
1256
                                                (('ref', ), 'refdata', ([], ))])
1257
        idx2 = self.make_index('2', 1, nodes=[(('ref', ), 'refdata', ([], ))])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1258
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1259
        self.assertEqual({(idx1, ('name', ), 'data', ((('ref',),),)),
1260
                              (idx1, ('ref', ), 'refdata', ((), ))},
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1261
                         set(idx.iter_entries([('name', ), ('ref', )])))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1262
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1263
    def test_iter_missing_entry_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1264
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1265
        self.assertEqual([], list(idx.iter_entries([('a', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1266
1267
    def test_iter_missing_entry_one_index(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1268
        idx1 = self.make_index('1')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1269
        idx = _mod_index.CombinedGraphIndex([idx1])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1270
        self.assertEqual([], list(idx.iter_entries([('a', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1271
1272
    def test_iter_missing_entry_two_index(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1273
        idx1 = self.make_index('1')
1274
        idx2 = self.make_index('2')
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1275
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1276
        self.assertEqual([], list(idx.iter_entries([('a', )])))
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1277
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1278
    def test_iter_entry_present_one_index_only(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1279
        idx1 = self.make_index('1', nodes=[(('key', ), '', ())])
1280
        idx2 = self.make_index('2', nodes=[])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1281
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1282
        self.assertEqual([(idx1, ('key', ), '')],
1283
                         list(idx.iter_entries([('key', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1284
        # and in the other direction
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1285
        idx = _mod_index.CombinedGraphIndex([idx2, idx1])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1286
        self.assertEqual([(idx1, ('key', ), '')],
1287
                         list(idx.iter_entries([('key', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1288
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1289
    def test_key_count_empty(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1290
        idx1 = self.make_index('1', nodes=[])
1291
        idx2 = self.make_index('2', nodes=[])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1292
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1293
        self.assertEqual(0, idx.key_count())
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1294
1295
    def test_key_count_sums_index_keys(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1296
        idx1 = self.make_index('1', nodes=[
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1297
            (('1',), '', ()),
1298
            (('2',), '', ())])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1299
        idx2 = self.make_index('2', nodes=[(('1',), '', ())])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1300
        idx = _mod_index.CombinedGraphIndex([idx1, idx2])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1301
        self.assertEqual(3, idx.key_count())
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1302
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1303
    def test_validate_bad_child_index_errors(self):
1304
        trans = self.get_transport()
1305
        trans.put_bytes('name', "not an index\n")
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1306
        idx1 = _mod_index.GraphIndex(trans, 'name', 13)
1307
        idx = _mod_index.CombinedGraphIndex([idx1])
1308
        self.assertRaises(_mod_index.BadIndexFormatSignature, idx.validate)
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
1309
1310
    def test_validate_empty(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1311
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1312
        idx.validate()
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1313
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1314
    def test_key_count_reloads(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1315
        idx, reload_counter = self.make_combined_index_with_missing()
1316
        self.assertEqual(2, idx.key_count())
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1317
        self.assertEqual([1, 1, 0], reload_counter)
1318
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1319
    def test_key_count_no_reload(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1320
        idx, reload_counter = self.make_combined_index_with_missing()
1321
        idx._reload_func = None
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1322
        # Without a _reload_func we just raise the exception
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1323
        self.assertRaises(errors.NoSuchFile, idx.key_count)
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1324
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1325
    def test_key_count_reloads_and_fails(self):
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1326
        # We have deleted all underlying indexes, so we will try to reload, but
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1327
        # still fail. This is mostly to test we don't get stuck in an infinite
1328
        # loop trying to reload
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1329
        idx, reload_counter = self.make_combined_index_with_missing(
1330
            ['1', '2', '3'])
1331
        self.assertRaises(errors.NoSuchFile, idx.key_count)
3789.1.3 by John Arbash Meinel
CombinedGraphIndex can now reload when calling key_count().
1332
        self.assertEqual([2, 1, 1], reload_counter)
1333
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1334
    def test_iter_entries_reloads(self):
1335
        index, reload_counter = self.make_combined_index_with_missing()
1336
        result = list(index.iter_entries([('1',), ('2',), ('3',)]))
1337
        index3 = index._indices[0]
1338
        self.assertEqual([(index3, ('1',), ''), (index3, ('2',), '')],
1339
                         result)
1340
        self.assertEqual([1, 1, 0], reload_counter)
1341
1342
    def test_iter_entries_reloads_midway(self):
1343
        # The first index still looks present, so we get interrupted mid-way
1344
        # through
1345
        index, reload_counter = self.make_combined_index_with_missing(['2'])
1346
        index1, index2 = index._indices
1347
        result = list(index.iter_entries([('1',), ('2',), ('3',)]))
1348
        index3 = index._indices[0]
3789.1.5 by John Arbash Meinel
CombinedGraphIndex.iter_all_entries() can now reload when needed.
1349
        # We had already yielded '1', so we just go on to the next, we should
3789.1.6 by John Arbash Meinel
CombinedGraphIndex.iter_entries_prefix can now reload when needed.
1350
        # not yield '1' twice.
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1351
        self.assertEqual([(index1, ('1',), ''), (index3, ('2',), '')],
1352
                         result)
1353
        self.assertEqual([1, 1, 0], reload_counter)
1354
1355
    def test_iter_entries_no_reload(self):
1356
        index, reload_counter = self.make_combined_index_with_missing()
1357
        index._reload_func = None
1358
        # Without a _reload_func we just raise the exception
1359
        self.assertListRaises(errors.NoSuchFile, index.iter_entries, [('3',)])
1360
1361
    def test_iter_entries_reloads_and_fails(self):
1362
        index, reload_counter = self.make_combined_index_with_missing(
1363
                                    ['1', '2', '3'])
1364
        self.assertListRaises(errors.NoSuchFile, index.iter_entries, [('3',)])
1365
        self.assertEqual([2, 1, 1], reload_counter)
1366
3789.1.5 by John Arbash Meinel
CombinedGraphIndex.iter_all_entries() can now reload when needed.
1367
    def test_iter_all_entries_reloads(self):
1368
        index, reload_counter = self.make_combined_index_with_missing()
1369
        result = list(index.iter_all_entries())
1370
        index3 = index._indices[0]
1371
        self.assertEqual([(index3, ('1',), ''), (index3, ('2',), '')],
1372
                         result)
1373
        self.assertEqual([1, 1, 0], reload_counter)
1374
1375
    def test_iter_all_entries_reloads_midway(self):
1376
        index, reload_counter = self.make_combined_index_with_missing(['2'])
1377
        index1, index2 = index._indices
1378
        result = list(index.iter_all_entries())
1379
        index3 = index._indices[0]
1380
        # We had already yielded '1', so we just go on to the next, we should
3789.1.6 by John Arbash Meinel
CombinedGraphIndex.iter_entries_prefix can now reload when needed.
1381
        # not yield '1' twice.
3789.1.5 by John Arbash Meinel
CombinedGraphIndex.iter_all_entries() can now reload when needed.
1382
        self.assertEqual([(index1, ('1',), ''), (index3, ('2',), '')],
1383
                         result)
1384
        self.assertEqual([1, 1, 0], reload_counter)
1385
1386
    def test_iter_all_entries_no_reload(self):
1387
        index, reload_counter = self.make_combined_index_with_missing()
1388
        index._reload_func = None
1389
        self.assertListRaises(errors.NoSuchFile, index.iter_all_entries)
1390
1391
    def test_iter_all_entries_reloads_and_fails(self):
1392
        index, reload_counter = self.make_combined_index_with_missing(
1393
                                    ['1', '2', '3'])
1394
        self.assertListRaises(errors.NoSuchFile, index.iter_all_entries)
3789.1.4 by John Arbash Meinel
CombinedGraphIndex.iter_entries() is now able to reload on request.
1395
3789.1.6 by John Arbash Meinel
CombinedGraphIndex.iter_entries_prefix can now reload when needed.
1396
    def test_iter_entries_prefix_reloads(self):
1397
        index, reload_counter = self.make_combined_index_with_missing()
1398
        result = list(index.iter_entries_prefix([('1',)]))
1399
        index3 = index._indices[0]
1400
        self.assertEqual([(index3, ('1',), '')], result)
1401
        self.assertEqual([1, 1, 0], reload_counter)
1402
1403
    def test_iter_entries_prefix_reloads_midway(self):
1404
        index, reload_counter = self.make_combined_index_with_missing(['2'])
1405
        index1, index2 = index._indices
1406
        result = list(index.iter_entries_prefix([('1',)]))
1407
        index3 = index._indices[0]
1408
        # We had already yielded '1', so we just go on to the next, we should
1409
        # not yield '1' twice.
1410
        self.assertEqual([(index1, ('1',), '')], result)
1411
        self.assertEqual([1, 1, 0], reload_counter)
1412
1413
    def test_iter_entries_prefix_no_reload(self):
1414
        index, reload_counter = self.make_combined_index_with_missing()
1415
        index._reload_func = None
1416
        self.assertListRaises(errors.NoSuchFile, index.iter_entries_prefix,
1417
                                                 [('1',)])
1418
1419
    def test_iter_entries_prefix_reloads_and_fails(self):
1420
        index, reload_counter = self.make_combined_index_with_missing(
1421
                                    ['1', '2', '3'])
1422
        self.assertListRaises(errors.NoSuchFile, index.iter_entries_prefix,
1423
                                                 [('1',)])
1424
5086.7.7 by Andrew Bennetts
Add another test for propagating reorderings.
1425
1426
    def make_index_with_simple_nodes(self, name, num_nodes=1):
1427
        """Make an index named after 'name', with keys named after 'name' too.
1428
1429
        Nodes will have a value of '' and no references.
1430
        """
1431
        nodes = [
1432
            (('index-%s-key-%s' % (name, n),), '', ())
1433
            for n in range(1, num_nodes+1)]
1434
        return self.make_index('index-%s' % name, 0, nodes=nodes)
1435
5086.7.5 by Andrew Bennetts
Add test for CombinedGraphIndex's auto-reordering behaviour.
1436
    def test_reorder_after_iter_entries(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1437
        # Four indices: [key1] in idx1, [key2,key3] in idx2, [] in idx3,
1438
        # [key4] in idx4.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1439
        idx = _mod_index.CombinedGraphIndex([])
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1440
        idx.insert_index(0, self.make_index_with_simple_nodes('1'), '1')
1441
        idx.insert_index(1, self.make_index_with_simple_nodes('2'), '2')
1442
        idx.insert_index(2, self.make_index_with_simple_nodes('3'), '3')
1443
        idx.insert_index(3, self.make_index_with_simple_nodes('4'), '4')
1444
        idx1, idx2, idx3, idx4 = idx._indices
1445
        # Query a key from idx4 and idx2.
1446
        self.assertLength(2, list(idx.iter_entries(
5086.7.7 by Andrew Bennetts
Add another test for propagating reorderings.
1447
            [('index-4-key-1',), ('index-2-key-1',)])))
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1448
        # Now idx2 and idx4 should be moved to the front (and idx1 should
1449
        # still be before idx3).
1450
        self.assertEqual([idx2, idx4, idx1, idx3], idx._indices)
1451
        self.assertEqual(['2', '4', '1', '3'], idx._index_names)
5086.7.5 by Andrew Bennetts
Add test for CombinedGraphIndex's auto-reordering behaviour.
1452
5086.7.7 by Andrew Bennetts
Add another test for propagating reorderings.
1453
    def test_reorder_propagates_to_siblings(self):
1454
        # Two CombinedGraphIndex objects, with the same number of indicies with
1455
        # matching names.
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1456
        cgi1 = _mod_index.CombinedGraphIndex([])
1457
        cgi2 = _mod_index.CombinedGraphIndex([])
5086.7.7 by Andrew Bennetts
Add another test for propagating reorderings.
1458
        cgi1.insert_index(0, self.make_index_with_simple_nodes('1-1'), 'one')
1459
        cgi1.insert_index(1, self.make_index_with_simple_nodes('1-2'), 'two')
1460
        cgi2.insert_index(0, self.make_index_with_simple_nodes('2-1'), 'one')
1461
        cgi2.insert_index(1, self.make_index_with_simple_nodes('2-2'), 'two')
1462
        index2_1, index2_2 = cgi2._indices
1463
        cgi1.set_sibling_indices([cgi2])
1464
        # Trigger a reordering in cgi1.  cgi2 will be reordered as well.
1465
        list(cgi1.iter_entries([('index-1-2-key-1',)]))
1466
        self.assertEqual([index2_2, index2_1], cgi2._indices)
1467
        self.assertEqual(['two', 'one'], cgi2._index_names)
1468
3789.1.7 by John Arbash Meinel
CombinedGraphIndex.validate() will now reload.
1469
    def test_validate_reloads(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1470
        idx, reload_counter = self.make_combined_index_with_missing()
1471
        idx.validate()
3789.1.7 by John Arbash Meinel
CombinedGraphIndex.validate() will now reload.
1472
        self.assertEqual([1, 1, 0], reload_counter)
1473
1474
    def test_validate_reloads_midway(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1475
        idx, reload_counter = self.make_combined_index_with_missing(['2'])
1476
        idx.validate()
3789.1.7 by John Arbash Meinel
CombinedGraphIndex.validate() will now reload.
1477
1478
    def test_validate_no_reload(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1479
        idx, reload_counter = self.make_combined_index_with_missing()
1480
        idx._reload_func = None
1481
        self.assertRaises(errors.NoSuchFile, idx.validate)
3789.1.7 by John Arbash Meinel
CombinedGraphIndex.validate() will now reload.
1482
1483
    def test_validate_reloads_and_fails(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1484
        idx, reload_counter = self.make_combined_index_with_missing(
1485
            ['1', '2', '3'])
1486
        self.assertRaises(errors.NoSuchFile, idx.validate)
3789.1.7 by John Arbash Meinel
CombinedGraphIndex.validate() will now reload.
1487
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1488
    def test_find_ancestors_across_indexes(self):
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1489
        key1 = ('key-1',)
1490
        key2 = ('key-2',)
1491
        key3 = ('key-3',)
1492
        key4 = ('key-4',)
1493
        index1 = self.make_index('12', ref_lists=1, nodes=[
1494
            (key1, 'value', ([],)),
1495
            (key2, 'value', ([key1],)),
1496
            ])
1497
        index2 = self.make_index('34', ref_lists=1, nodes=[
1498
            (key3, 'value', ([key2],)),
1499
            (key4, 'value', ([key3],)),
1500
            ])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1501
        c_index = _mod_index.CombinedGraphIndex([index1, index2])
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1502
        parent_map, missing_keys = c_index.find_ancestry([key1], 0)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1503
        self.assertEqual({key1: ()}, parent_map)
1504
        self.assertEqual(set(), missing_keys)
1505
        # Now look for a key from index2 which requires us to find the key in
1506
        # the second index, and then continue searching for parents in the
1507
        # first index
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1508
        parent_map, missing_keys = c_index.find_ancestry([key3], 0)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1509
        self.assertEqual({key1: (), key2: (key1,), key3: (key2,)}, parent_map)
1510
        self.assertEqual(set(), missing_keys)
1511
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1512
    def test_find_ancestors_missing_keys(self):
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1513
        key1 = ('key-1',)
1514
        key2 = ('key-2',)
1515
        key3 = ('key-3',)
1516
        key4 = ('key-4',)
1517
        index1 = self.make_index('12', ref_lists=1, nodes=[
1518
            (key1, 'value', ([],)),
1519
            (key2, 'value', ([key1],)),
1520
            ])
1521
        index2 = self.make_index('34', ref_lists=1, nodes=[
1522
            (key3, 'value', ([key2],)),
1523
            ])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1524
        c_index = _mod_index.CombinedGraphIndex([index1, index2])
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1525
        # Searching for a key which is actually not present at all should
1526
        # eventually converge
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1527
        parent_map, missing_keys = c_index.find_ancestry([key4], 0)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1528
        self.assertEqual({}, parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1529
        self.assertEqual({key4}, missing_keys)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1530
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1531
    def test_find_ancestors_no_indexes(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1532
        c_index = _mod_index.CombinedGraphIndex([])
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1533
        key1 = ('key-1',)
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1534
        parent_map, missing_keys = c_index.find_ancestry([key1], 0)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1535
        self.assertEqual({}, parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1536
        self.assertEqual({key1}, missing_keys)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1537
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1538
    def test_find_ancestors_ghost_parent(self):
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1539
        key1 = ('key-1',)
1540
        key2 = ('key-2',)
1541
        key3 = ('key-3',)
1542
        key4 = ('key-4',)
1543
        index1 = self.make_index('12', ref_lists=1, nodes=[
1544
            (key1, 'value', ([],)),
1545
            (key2, 'value', ([key1],)),
1546
            ])
1547
        index2 = self.make_index('34', ref_lists=1, nodes=[
1548
            (key4, 'value', ([key2, key3],)),
1549
            ])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1550
        c_index = _mod_index.CombinedGraphIndex([index1, index2])
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1551
        # Searching for a key which is actually not present at all should
1552
        # eventually converge
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1553
        parent_map, missing_keys = c_index.find_ancestry([key4], 0)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1554
        self.assertEqual({key4: (key2, key3), key2: (key1,), key1: ()},
1555
                         parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1556
        self.assertEqual({key3}, missing_keys)
4593.4.8 by John Arbash Meinel
Implement CombinedGraphIndex.get_ancestry()
1557
4593.4.12 by John Arbash Meinel
Name the specific index api _find_ancestors, and the public CombinedGraphIndex api find_ancestry()
1558
    def test__find_ancestors_empty_index(self):
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1559
        idx = self.make_index('test', ref_lists=1, key_elements=1, nodes=[])
4593.4.11 by John Arbash Meinel
Snapshot the work in progress.
1560
        parent_map = {}
1561
        missing_keys = set()
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1562
        search_keys = idx._find_ancestors([('one',), ('two',)], 0, parent_map,
1563
                                          missing_keys)
4593.4.11 by John Arbash Meinel
Snapshot the work in progress.
1564
        self.assertEqual(set(), search_keys)
1565
        self.assertEqual({}, parent_map)
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1566
        self.assertEqual({('one',), ('two',)}, missing_keys)
4593.4.11 by John Arbash Meinel
Snapshot the work in progress.
1567
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1568
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1569
class TestInMemoryGraphIndex(tests.TestCaseWithMemoryTransport):
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1570
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1571
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1572
        result = _mod_index.InMemoryGraphIndex(ref_lists, key_elements=key_elements)
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1573
        result.add_nodes(nodes)
1574
        return result
1575
2624.2.1 by Robert Collins
InMemoryGraphIndex.add_nodes was inconsistent with other metods for non-node-reference indices.
1576
    def test_add_nodes_no_refs(self):
1577
        index = self.make_index(0)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1578
        index.add_nodes([(('name', ), 'data')])
1579
        index.add_nodes([(('name2', ), ''), (('name3', ), '')])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1580
        self.assertEqual({
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
1581
            (index, ('name', ), 'data'),
1582
            (index, ('name2', ), ''),
1583
            (index, ('name3', ), ''),
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1584
            }, set(index.iter_all_entries()))
2624.2.1 by Robert Collins
InMemoryGraphIndex.add_nodes was inconsistent with other metods for non-node-reference indices.
1585
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1586
    def test_add_nodes(self):
1587
        index = self.make_index(1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1588
        index.add_nodes([(('name', ), 'data', ([],))])
1589
        index.add_nodes([(('name2', ), '', ([],)), (('name3', ), '', ([('r', )],))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1590
        self.assertEqual({
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
1591
            (index, ('name', ), 'data', ((),)),
1592
            (index, ('name2', ), '', ((),)),
1593
            (index, ('name3', ), '', ((('r', ), ), )),
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1594
            }, set(index.iter_all_entries()))
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1595
1596
    def test_iter_all_entries_empty(self):
1597
        index = self.make_index()
1598
        self.assertEqual([], list(index.iter_all_entries()))
1599
1600
    def test_iter_all_entries_simple(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1601
        index = self.make_index(nodes=[(('name', ), 'data')])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
1602
        self.assertEqual([(index, ('name', ), 'data')],
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1603
            list(index.iter_all_entries()))
1604
1605
    def test_iter_all_entries_references(self):
1606
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1607
            (('name', ), 'data', ([('ref', )], )),
1608
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1609
        self.assertEqual({(index, ('name', ), 'data', ((('ref', ),),)),
1610
            (index, ('ref', ), 'refdata', ((), ))},
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1611
            set(index.iter_all_entries()))
1612
1613
    def test_iteration_absent_skipped(self):
1614
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1615
            (('name', ), 'data', ([('ref', )], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1616
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),))},
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1617
            set(index.iter_all_entries()))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1618
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),))},
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1619
            set(index.iter_entries([('name', )])))
1620
        self.assertEqual([], list(index.iter_entries([('ref', )])))
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1621
1622
    def test_iter_all_keys(self):
1623
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1624
            (('name', ), 'data', ([('ref', )], )),
1625
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1626
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),)),
1627
            (index, ('ref', ), 'refdata', ((), ))},
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1628
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1629
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1630
    def test_iter_key_prefix_1_key_element_no_refs(self):
1631
        index = self.make_index( nodes=[
1632
            (('name', ), 'data'),
1633
            (('ref', ), 'refdata')])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1634
        self.assertEqual({(index, ('name', ), 'data'),
1635
            (index, ('ref', ), 'refdata')},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1636
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
1637
1638
    def test_iter_key_prefix_1_key_element_refs(self):
1639
        index = self.make_index(1, nodes=[
1640
            (('name', ), 'data', ([('ref', )], )),
1641
            (('ref', ), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1642
        self.assertEqual({(index, ('name', ), 'data', ((('ref',),),)),
1643
            (index, ('ref', ), 'refdata', ((), ))},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1644
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
1645
1646
    def test_iter_key_prefix_2_key_element_no_refs(self):
1647
        index = self.make_index(key_elements=2, nodes=[
1648
            (('name', 'fin1'), 'data'),
1649
            (('name', 'fin2'), 'beta'),
1650
            (('ref', 'erence'), 'refdata')])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1651
        self.assertEqual({(index, ('name', 'fin1'), 'data'),
1652
            (index, ('ref', 'erence'), 'refdata')},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1653
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1654
        self.assertEqual({(index, ('name', 'fin1'), 'data'),
1655
            (index, ('name', 'fin2'), 'beta')},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1656
            set(index.iter_entries_prefix([('name', None)])))
1657
1658
    def test_iter_key_prefix_2_key_element_refs(self):
1659
        index = self.make_index(1, key_elements=2, nodes=[
1660
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
1661
            (('name', 'fin2'), 'beta', ([], )),
1662
            (('ref', 'erence'), 'refdata', ([], ))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1663
        self.assertEqual({(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
1664
            (index, ('ref', 'erence'), 'refdata', ((), ))},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1665
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1666
        self.assertEqual({(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
1667
            (index, ('name', 'fin2'), 'beta', ((), ))},
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
1668
            set(index.iter_entries_prefix([('name', None)])))
1669
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1670
    def test_iter_nothing_empty(self):
1671
        index = self.make_index()
1672
        self.assertEqual([], list(index.iter_entries([])))
1673
1674
    def test_iter_missing_entry_empty(self):
1675
        index = self.make_index()
1676
        self.assertEqual([], list(index.iter_entries(['a'])))
1677
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1678
    def test_key_count_empty(self):
1679
        index = self.make_index()
1680
        self.assertEqual(0, index.key_count())
1681
1682
    def test_key_count_one(self):
1683
        index = self.make_index(nodes=[(('name', ), '')])
1684
        self.assertEqual(1, index.key_count())
1685
1686
    def test_key_count_two(self):
1687
        index = self.make_index(nodes=[(('name', ), ''), (('foo', ), '')])
1688
        self.assertEqual(2, index.key_count())
1689
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1690
    def test_validate_empty(self):
1691
        index = self.make_index()
1692
        index.validate()
1693
1694
    def test_validate_no_refs_content(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
1695
        index = self.make_index(nodes=[(('key', ), 'value')])
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
1696
        index.validate()
1697
1698
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1699
class TestGraphIndexPrefixAdapter(tests.TestCaseWithMemoryTransport):
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1700
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1701
    def make_index(self, ref_lists=1, key_elements=2, nodes=[],
1702
                   add_callback=False):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1703
        result = _mod_index.InMemoryGraphIndex(ref_lists, key_elements=key_elements)
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1704
        result.add_nodes(nodes)
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1705
        if add_callback:
2624.2.17 by Robert Collins
Review feedback.
1706
            add_nodes_callback = result.add_nodes
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1707
        else:
2624.2.17 by Robert Collins
Review feedback.
1708
            add_nodes_callback = None
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1709
        adapter = _mod_index.GraphIndexPrefixAdapter(
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1710
            result, ('prefix', ), key_elements - 1,
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1711
            add_nodes_callback=add_nodes_callback)
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1712
        return result, adapter
1713
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1714
    def test_add_node(self):
1715
        index, adapter = self.make_index(add_callback=True)
1716
        adapter.add_node(('key',), 'value', ((('ref',),),))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1717
        self.assertEqual({(index, ('prefix', 'key'), 'value',
1718
                               ((('prefix', 'ref'),),))},
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1719
            set(index.iter_all_entries()))
1720
1721
    def test_add_nodes(self):
1722
        index, adapter = self.make_index(add_callback=True)
1723
        adapter.add_nodes((
1724
            (('key',), 'value', ((('ref',),),)),
1725
            (('key2',), 'value2', ((),)),
1726
            ))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1727
        self.assertEqual({
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
1728
            (index, ('prefix', 'key2'), 'value2', ((),)),
1729
            (index, ('prefix', 'key'), 'value', ((('prefix', 'ref'),),))
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1730
            },
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
1731
            set(index.iter_all_entries()))
1732
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1733
    def test_construct(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1734
        idx = _mod_index.InMemoryGraphIndex()
1735
        adapter = _mod_index.GraphIndexPrefixAdapter(idx, ('prefix', ), 1)
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1736
1737
    def test_construct_with_callback(self):
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1738
        idx = _mod_index.InMemoryGraphIndex()
1739
        adapter = _mod_index.GraphIndexPrefixAdapter(idx, ('prefix', ), 1,
5273.1.7 by Vincent Ladeuil
No more use of the get_transport imported *symbol*, all uses are through
1740
                                                idx.add_nodes)
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1741
1742
    def test_iter_all_entries_cross_prefix_map_errors(self):
1743
        index, adapter = self.make_index(nodes=[
1744
            (('prefix', 'key1'), 'data1', ((('prefixaltered', 'key2'),),))])
6734.1.18 by Jelmer Vernooij
Move BadIndex* errors out of breezy.errors.
1745
        self.assertRaises(_mod_index.BadIndexData, list, adapter.iter_all_entries())
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1746
1747
    def test_iter_all_entries(self):
1748
        index, adapter = self.make_index(nodes=[
1749
            (('notprefix', 'key1'), 'data', ((), )),
1750
            (('prefix', 'key1'), 'data1', ((), )),
1751
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1752
        self.assertEqual({(index, ('key1', ), 'data1', ((),)),
1753
            (index, ('key2', ), 'data2', ((('key1',),),))},
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1754
            set(adapter.iter_all_entries()))
1755
1756
    def test_iter_entries(self):
1757
        index, adapter = self.make_index(nodes=[
1758
            (('notprefix', 'key1'), 'data', ((), )),
1759
            (('prefix', 'key1'), 'data1', ((), )),
1760
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
1761
        # ask for many - get all
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1762
        self.assertEqual({(index, ('key1', ), 'data1', ((),)),
1763
            (index, ('key2', ), 'data2', ((('key1', ),),))},
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1764
            set(adapter.iter_entries([('key1', ), ('key2', )])))
1765
        # ask for one, get one
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1766
        self.assertEqual({(index, ('key1', ), 'data1', ((),))},
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1767
            set(adapter.iter_entries([('key1', )])))
1768
        # ask for missing, get none
1769
        self.assertEqual(set(),
1770
            set(adapter.iter_entries([('key3', )])))
1771
1772
    def test_iter_entries_prefix(self):
1773
        index, adapter = self.make_index(key_elements=3, nodes=[
1774
            (('notprefix', 'foo', 'key1'), 'data', ((), )),
1775
            (('prefix', 'prefix2', 'key1'), 'data1', ((), )),
1776
            (('prefix', 'prefix2', 'key2'), 'data2', ((('prefix', 'prefix2', 'key1'),),))])
1777
        # ask for a prefix, get the results for just that prefix, adjusted.
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
1778
        self.assertEqual({(index, ('prefix2', 'key1', ), 'data1', ((),)),
1779
            (index, ('prefix2', 'key2', ), 'data2', ((('prefix2', 'key1', ),),))},
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1780
            set(adapter.iter_entries_prefix([('prefix2', None)])))
1781
2624.2.16 by Robert Collins
Add a key_count method to GraphIndex and friends, allowing optimisation of length calculations by the index.
1782
    def test_key_count_no_matching_keys(self):
1783
        index, adapter = self.make_index(nodes=[
1784
            (('notprefix', 'key1'), 'data', ((), ))])
1785
        self.assertEqual(0, adapter.key_count())
1786
1787
    def test_key_count_some_keys(self):
1788
        index, adapter = self.make_index(nodes=[
1789
            (('notprefix', 'key1'), 'data', ((), )),
1790
            (('prefix', 'key1'), 'data1', ((), )),
1791
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
1792
        self.assertEqual(2, adapter.key_count())
1793
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
1794
    def test_validate(self):
1795
        index, adapter = self.make_index()
1796
        calls = []
1797
        def validate():
1798
            calls.append('called')
1799
        index.validate = validate
1800
        adapter.validate()
1801
        self.assertEqual(['called'], calls)