/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
1
# Copyright (C) 2007 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for indices."""
18
2592.1.5 by Robert Collins
Trivial index reading.
19
from bzrlib import errors
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
20
from bzrlib.index import *
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
21
from bzrlib.tests import TestCaseWithMemoryTransport
22
23
24
class TestGraphIndexBuilder(TestCaseWithMemoryTransport):
25
26
    def test_build_index_empty(self):
27
        builder = GraphIndexBuilder()
28
        stream = builder.finish()
29
        contents = stream.read()
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
30
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n\n", contents)
31
32
    def test_build_index_one_reference_list_empty(self):
33
        builder = GraphIndexBuilder(reference_lists=1)
34
        stream = builder.finish()
35
        contents = stream.read()
36
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n\n", contents)
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
37
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
38
    def test_build_index_two_reference_list_empty(self):
39
        builder = GraphIndexBuilder(reference_lists=2)
40
        stream = builder.finish()
41
        contents = stream.read()
42
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n\n", contents)
43
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
44
    def test_build_index_one_node_no_refs(self):
45
        builder = GraphIndexBuilder()
46
        builder.add_node('akey', 'data')
47
        stream = builder.finish()
48
        contents = stream.read()
49
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
50
            "akey\x00\x00\x00data\n\n", contents)
51
52
    def test_build_index_one_node_no_refs_accepts_empty_reflist(self):
53
        builder = GraphIndexBuilder()
54
        builder.add_node('akey', 'data', ())
2592.1.12 by Robert Collins
Handle basic node adds.
55
        stream = builder.finish()
56
        contents = stream.read()
57
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
58
            "akey\x00\x00\x00data\n\n", contents)
2592.1.12 by Robert Collins
Handle basic node adds.
59
2592.1.21 by Robert Collins
Empty values are ok.
60
    def test_add_node_empty_value(self):
61
        builder = GraphIndexBuilder()
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
62
        builder.add_node('akey', '')
2592.1.21 by Robert Collins
Empty values are ok.
63
        stream = builder.finish()
64
        contents = stream.read()
65
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
66
            "akey\x00\x00\x00\n\n", contents)
2592.1.21 by Robert Collins
Empty values are ok.
67
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
68
    def test_build_index_two_nodes_sorted(self):
2592.1.17 by Robert Collins
Multi node sort order is defined.
69
        # the highest sorted node comes first.
70
        builder = GraphIndexBuilder()
71
        # use three to have a good chance of glitching dictionary hash
72
        # lookups etc. Insert in randomish order that is not correct
73
        # and not the reverse of the correct order.
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
74
        builder.add_node('2002', 'data')
75
        builder.add_node('2000', 'data')
76
        builder.add_node('2001', 'data')
2592.1.17 by Robert Collins
Multi node sort order is defined.
77
        stream = builder.finish()
78
        contents = stream.read()
79
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
80
            "2000\x00\x00\x00data\n"
81
            "2001\x00\x00\x00data\n"
82
            "2002\x00\x00\x00data\n"
2592.1.17 by Robert Collins
Multi node sort order is defined.
83
            "\n", contents)
84
2592.1.19 by Robert Collins
Node references are tab separated.
85
    def test_build_index_reference_lists_are_included_one(self):
86
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
87
        builder.add_node('key', 'data', ([], ))
2592.1.19 by Robert Collins
Node references are tab separated.
88
        stream = builder.finish()
89
        contents = stream.read()
90
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
91
            "key\x00\x00\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
92
            "\n", contents)
93
94
    def test_build_index_reference_lists_are_included_two(self):
95
        builder = GraphIndexBuilder(reference_lists=2)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
96
        builder.add_node('key', 'data', ([], []))
2592.1.19 by Robert Collins
Node references are tab separated.
97
        stream = builder.finish()
98
        contents = stream.read()
99
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
100
            "key\x00\x00\t\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
101
            "\n", contents)
102
2592.1.22 by Robert Collins
Node references are byte offsets.
103
    def test_node_references_are_byte_offsets(self):
104
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
105
        builder.add_node('reference', 'data', ([], ))
106
        builder.add_node('key', 'data', (['reference'], ))
2592.1.22 by Robert Collins
Node references are byte offsets.
107
        stream = builder.finish()
108
        contents = stream.read()
109
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
110
            "key\x00\x0051\x00data\n"
111
            "reference\x00\x00\x00data\n"
2592.1.22 by Robert Collins
Node references are byte offsets.
112
            "\n", contents)
113
2592.1.23 by Robert Collins
node reference delimiting tested.
114
    def test_node_references_are_cr_delimited(self):
115
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
116
        builder.add_node('reference', 'data', ([], ))
117
        builder.add_node('reference2', 'data', ([], ))
118
        builder.add_node('key', 'data', (['reference', 'reference2'], ))
2592.1.23 by Robert Collins
node reference delimiting tested.
119
        stream = builder.finish()
120
        contents = stream.read()
121
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
122
            "key\x00\x0054\r71\x00data\n"
123
            "reference\x00\x00\x00data\n"
124
            "reference2\x00\x00\x00data\n"
2592.1.23 by Robert Collins
node reference delimiting tested.
125
            "\n", contents)
126
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
127
    def test_multiple_reference_lists_are_tab_delimited(self):
128
        builder = GraphIndexBuilder(reference_lists=2)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
129
        builder.add_node('keference', 'data', ([], []))
130
        builder.add_node('rey', 'data', (['keference'], ['keference']))
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
131
        stream = builder.finish()
132
        contents = stream.read()
133
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
134
            "keference\x00\x00\t\x00data\n"
135
            "rey\x00\x0038\t38\x00data\n"
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
136
            "\n", contents)
137
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
138
    def test_add_node_referencing_missing_key_makes_absent(self):
139
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
140
        builder.add_node('rey', 'data', (['beference', 'aeference2'], ))
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
141
        stream = builder.finish()
142
        contents = stream.read()
143
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
144
            "aeference2\x00a\x00\x00\n"
145
            "beference\x00a\x00\x00\n"
146
            "rey\x00\x0053\r38\x00data\n"
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
147
            "\n", contents)
148
2592.1.26 by Robert Collins
Test digit buffering is accurate.
149
    def test_node_references_three_digits(self):
150
        # test the node digit expands as needed.
151
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
152
        references = map(str, reversed(range(9)))
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
153
        builder.add_node('2-key', '', (references, ))
2592.1.26 by Robert Collins
Test digit buffering is accurate.
154
        stream = builder.finish()
155
        contents = stream.read()
156
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
157
            "0\x00a\x00\x00\n"
158
            "1\x00a\x00\x00\n"
159
            "2\x00a\x00\x00\n"
160
            "2-key\x00\x00130\r124\r118\r112\r106\r100\r050\r044\r038\x00\n"
161
            "3\x00a\x00\x00\n"
162
            "4\x00a\x00\x00\n"
163
            "5\x00a\x00\x00\n"
164
            "6\x00a\x00\x00\n"
165
            "7\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
166
            "8\x00a\x00\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
167
            "\n", contents)
168
169
    def test_absent_has_no_reference_overhead(self):
170
        # the offsets after an absent record should be correct when there are
171
        # >1 reference lists.
172
        builder = GraphIndexBuilder(reference_lists=2)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
173
        builder.add_node('parent', '', (['aail', 'zther'], []))
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
174
        stream = builder.finish()
175
        contents = stream.read()
176
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
177
            "aail\x00a\x00\x00\n"
178
            "parent\x00\x0038\r63\t\x00\n"
179
            "zther\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
180
            "\n", contents)
181
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
182
    def test_add_node_bad_key(self):
2592.1.12 by Robert Collins
Handle basic node adds.
183
        builder = GraphIndexBuilder()
2592.1.14 by Robert Collins
Detect bad reference key values.
184
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
185
            self.assertRaises(errors.BadIndexKey, builder.add_node,
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
186
                'a%skey' % bad_char, 'data')
2592.1.20 by Robert Collins
Empty keys are invalid.
187
        self.assertRaises(errors.BadIndexKey, builder.add_node,
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
188
                '', 'data')
2592.1.12 by Robert Collins
Handle basic node adds.
189
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
190
    def test_add_node_bad_data(self):
2592.1.12 by Robert Collins
Handle basic node adds.
191
        builder = GraphIndexBuilder()
192
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
193
            'data\naa')
2592.1.12 by Robert Collins
Handle basic node adds.
194
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
195
            'data\x00aa')
2592.1.12 by Robert Collins
Handle basic node adds.
196
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
197
    def test_add_node_bad_mismatched_ref_lists_length(self):
198
        builder = GraphIndexBuilder()
199
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
200
            'data aa', ([], ))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
201
        builder = GraphIndexBuilder(reference_lists=1)
202
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
203
            'data aa')
204
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
205
            'data aa', (), )
206
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
207
            'data aa', ([], []))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
208
        builder = GraphIndexBuilder(reference_lists=2)
209
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
210
            'data aa')
211
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
212
            'data aa', ([], ))
213
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
214
            'data aa', ([], [], []))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
215
2592.1.14 by Robert Collins
Detect bad reference key values.
216
    def test_add_node_bad_key_in_reference_lists(self):
217
        # first list, first key - trivial
218
        builder = GraphIndexBuilder(reference_lists=1)
219
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
220
            'data aa', (['a key'], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
221
        # need to check more than the first key in the list
222
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
223
            'data aa', (['agoodkey', 'this is a bad key'], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
224
        # and if there is more than one list it should be getting checked
225
        # too
226
        builder = GraphIndexBuilder(reference_lists=2)
227
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
228
            'data aa', ([], ['a bad key']))
2592.1.14 by Robert Collins
Detect bad reference key values.
229
2592.1.15 by Robert Collins
Detect duplicate key insertion.
230
    def test_add_duplicate_key(self):
231
        builder = GraphIndexBuilder()
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
232
        builder.add_node('key', 'data')
2592.1.15 by Robert Collins
Detect duplicate key insertion.
233
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node, 'key',
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
234
            'data')
2592.1.15 by Robert Collins
Detect duplicate key insertion.
235
2592.1.16 by Robert Collins
Can add keys after referencing them.
236
    def test_add_key_after_referencing_key(self):
237
        builder = GraphIndexBuilder(reference_lists=1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
238
        builder.add_node('key', 'data', (['reference'], ))
239
        builder.add_node('reference', 'data', ([],))
2592.1.16 by Robert Collins
Can add keys after referencing them.
240
2592.1.5 by Robert Collins
Trivial index reading.
241
242
class TestGraphIndex(TestCaseWithMemoryTransport):
243
2592.1.12 by Robert Collins
Handle basic node adds.
244
    def make_index(self, ref_lists=0, nodes=[]):
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
245
        builder = GraphIndexBuilder(ref_lists)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
246
        for node, value, references in nodes:
247
            builder.add_node(node, value, references)
2592.1.5 by Robert Collins
Trivial index reading.
248
        stream = builder.finish()
249
        trans = self.get_transport()
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
250
        trans.put_file('index', stream)
2592.1.5 by Robert Collins
Trivial index reading.
251
        return GraphIndex(trans, 'index')
252
2592.1.7 by Robert Collins
A validate that goes boom.
253
    def test_open_bad_index_no_error(self):
254
        trans = self.get_transport()
255
        trans.put_bytes('name', "not an index\n")
256
        index = GraphIndex(trans, 'name')
257
2592.1.5 by Robert Collins
Trivial index reading.
258
    def test_iter_all_entries_empty(self):
259
        index = self.make_index()
260
        self.assertEqual([], list(index.iter_all_entries()))
261
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
262
    def test_iter_all_entries_simple(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
263
        index = self.make_index(nodes=[('name', 'data', ())])
264
        self.assertEqual([('name', 'data')],
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
265
            list(index.iter_all_entries()))
266
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
267
    def test_iter_all_entries_references_resolved(self):
268
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
269
            ('name', 'data', (['ref'], )),
270
            ('ref', 'refdata', ([], ))])
271
        self.assertEqual(set([('name', 'data', (('ref',),)),
272
            ('ref', 'refdata', ((), ))]),
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
273
            set(index.iter_all_entries()))
274
2592.1.30 by Robert Collins
Absent entries are not yeilded.
275
    def test_iteration_absent_skipped(self):
276
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
277
            ('name', 'data', (['ref'], ))])
278
        self.assertEqual(set([('name', 'data', (('ref',),))]),
2592.1.30 by Robert Collins
Absent entries are not yeilded.
279
            set(index.iter_all_entries()))
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
280
        self.assertEqual(set([('name', 'data', (('ref',),))]),
2592.1.30 by Robert Collins
Absent entries are not yeilded.
281
            set(index.iter_entries(['name'])))
2592.1.35 by Robert Collins
Change the missing key interface in index operations to not raise, allowing callers to set policy.
282
        self.assertEqual([], list(index.iter_entries(['ref'])))
2592.1.30 by Robert Collins
Absent entries are not yeilded.
283
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
284
    def test_iter_all_keys(self):
2592.1.29 by Robert Collins
Basic iter_entries working.
285
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
286
            ('name', 'data', (['ref'], )),
287
            ('ref', 'refdata', ([], ))])
288
        self.assertEqual(set([('name', 'data', (('ref',),)),
289
            ('ref', 'refdata', ((), ))]),
2592.1.29 by Robert Collins
Basic iter_entries working.
290
            set(index.iter_entries(['name', 'ref'])))
291
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
292
    def test_iter_nothing_empty(self):
2592.1.9 by Robert Collins
Iterating no keys should work too.
293
        index = self.make_index()
294
        self.assertEqual([], list(index.iter_entries([])))
295
2592.1.5 by Robert Collins
Trivial index reading.
296
    def test_iter_missing_entry_empty(self):
297
        index = self.make_index()
2592.1.35 by Robert Collins
Change the missing key interface in index operations to not raise, allowing callers to set policy.
298
        self.assertEqual([], list(index.iter_entries(['a'])))
2592.1.7 by Robert Collins
A validate that goes boom.
299
300
    def test_validate_bad_index_errors(self):
301
        trans = self.get_transport()
302
        trans.put_bytes('name', "not an index\n")
303
        index = GraphIndex(trans, 'name')
304
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
2592.1.8 by Robert Collins
Empty files should validate ok.
305
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
306
    def test_validate_bad_node_refs(self):
307
        index = self.make_index(2)
308
        trans = self.get_transport()
309
        content = trans.get_bytes('index')
310
        # change the options line to end with a rather than a parseable number
311
        new_content = content[:-2] + 'a\n\n'
312
        trans.put_bytes('index', new_content)
313
        self.assertRaises(errors.BadIndexOptions, index.validate)
314
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
315
    def test_validate_missing_end_line_empty(self):
2592.1.11 by Robert Collins
Detect truncated indices.
316
        index = self.make_index(2)
317
        trans = self.get_transport()
318
        content = trans.get_bytes('index')
319
        # truncate the last byte
320
        trans.put_bytes('index', content[:-1])
321
        self.assertRaises(errors.BadIndexData, index.validate)
322
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
323
    def test_validate_missing_end_line_nonempty(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
324
        index = self.make_index(2, [('key', '', ([], []))])
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
325
        trans = self.get_transport()
326
        content = trans.get_bytes('index')
327
        # truncate the last byte
328
        trans.put_bytes('index', content[:-1])
329
        self.assertRaises(errors.BadIndexData, index.validate)
330
2592.1.8 by Robert Collins
Empty files should validate ok.
331
    def test_validate_empty(self):
332
        index = self.make_index()
333
        index.validate()
2592.1.12 by Robert Collins
Handle basic node adds.
334
335
    def test_validate_no_refs_content(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
336
        index = self.make_index(nodes=[('key', 'value', ())])
2592.1.12 by Robert Collins
Handle basic node adds.
337
        index.validate()
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
338
339
340
class TestCombinedGraphIndex(TestCaseWithMemoryTransport):
341
342
    def make_index(self, name, ref_lists=0, nodes=[]):
343
        builder = GraphIndexBuilder(ref_lists)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
344
        for node, value, references in nodes:
345
            builder.add_node(node, value, references)
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
346
        stream = builder.finish()
347
        trans = self.get_transport()
348
        trans.put_file(name, stream)
349
        return GraphIndex(trans, name)
350
351
    def test_open_missing_index_no_error(self):
352
        trans = self.get_transport()
353
        index1 = GraphIndex(trans, 'missing')
354
        index = CombinedGraphIndex([index1])
355
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
356
    def test_add_index(self):
357
        index = CombinedGraphIndex([])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
358
        index1 = self.make_index('name', 0, nodes=[('key', '', ())])
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
359
        index.insert_index(0, index1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
360
        self.assertEqual([('key', '')], list(index.iter_all_entries()))
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
361
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
362
    def test_iter_all_entries_empty(self):
363
        index = CombinedGraphIndex([])
364
        self.assertEqual([], list(index.iter_all_entries()))
365
366
    def test_iter_all_entries_children_empty(self):
367
        index1 = self.make_index('name')
368
        index = CombinedGraphIndex([index1])
369
        self.assertEqual([], list(index.iter_all_entries()))
370
371
    def test_iter_all_entries_simple(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
372
        index1 = self.make_index('name', nodes=[('name', 'data', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
373
        index = CombinedGraphIndex([index1])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
374
        self.assertEqual([('name', 'data')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
375
            list(index.iter_all_entries()))
376
377
    def test_iter_all_entries_two_indices(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
378
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
379
        index2 = self.make_index('name2', nodes=[('2', '', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
380
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
381
        self.assertEqual([('name', 'data'),
382
            ('2', '')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
383
            list(index.iter_all_entries()))
384
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
385
    def test_iter_entries_two_indices_dup_key(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
386
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
387
        index2 = self.make_index('name2', nodes=[('name', 'data', ())])
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
388
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
389
        self.assertEqual([('name', 'data')],
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
390
            list(index.iter_entries(['name'])))
391
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
392
    def test_iter_all_entries_two_indices_dup_key(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
393
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
394
        index2 = self.make_index('name2', nodes=[('name', 'data', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
395
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
396
        self.assertEqual([('name', 'data')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
397
            list(index.iter_all_entries()))
398
399
    def test_iter_nothing_empty(self):
400
        index = CombinedGraphIndex([])
401
        self.assertEqual([], list(index.iter_entries([])))
402
403
    def test_iter_nothing_children_empty(self):
404
        index1 = self.make_index('name')
405
        index = CombinedGraphIndex([index1])
406
        self.assertEqual([], list(index.iter_entries([])))
407
408
    def test_iter_all_keys(self):
409
        index1 = self.make_index('1', 1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
410
            ('name', 'data', (['ref'], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
411
        index2 = self.make_index('2', 1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
412
            ('ref', 'refdata', ((), ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
413
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
414
        self.assertEqual(set([('name', 'data', (('ref', ), )),
415
            ('ref', 'refdata', ((), ))]),
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
416
            set(index.iter_entries(['name', 'ref'])))
417
 
418
    def test_iter_all_keys_dup_entry(self):
419
        index1 = self.make_index('1', 1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
420
            ('name', 'data', (['ref'], )),
421
            ('ref', 'refdata', ([], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
422
        index2 = self.make_index('2', 1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
423
            ('ref', 'refdata', ([], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
424
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
425
        self.assertEqual(set([('name', 'data', (('ref',),)),
426
            ('ref', 'refdata', ((), ))]),
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
427
            set(index.iter_entries(['name', 'ref'])))
428
 
429
    def test_iter_missing_entry_empty(self):
430
        index = CombinedGraphIndex([])
2592.1.35 by Robert Collins
Change the missing key interface in index operations to not raise, allowing callers to set policy.
431
        self.assertEqual([], list(index.iter_entries(['a'])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
432
433
    def test_iter_missing_entry_one_index(self):
434
        index1 = self.make_index('1')
435
        index = CombinedGraphIndex([index1])
2592.1.35 by Robert Collins
Change the missing key interface in index operations to not raise, allowing callers to set policy.
436
        self.assertEqual([], list(index.iter_entries(['a'])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
437
438
    def test_iter_missing_entry_two_index(self):
439
        index1 = self.make_index('1')
440
        index2 = self.make_index('2')
441
        index = CombinedGraphIndex([index1, index2])
2592.1.35 by Robert Collins
Change the missing key interface in index operations to not raise, allowing callers to set policy.
442
        self.assertEqual([], list(index.iter_entries(['a'])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
443
 
444
    def test_iter_entry_present_one_index_only(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
445
        index1 = self.make_index('1', nodes=[('key', '', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
446
        index2 = self.make_index('2', nodes=[])
447
        index = CombinedGraphIndex([index1, index2])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
448
        self.assertEqual([('key', '')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
449
            list(index.iter_entries(['key'])))
450
        # and in the other direction
451
        index = CombinedGraphIndex([index2, index1])
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
452
        self.assertEqual([('key', '')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
453
            list(index.iter_entries(['key'])))
454
455
    def test_validate_bad_child_index_errors(self):
456
        trans = self.get_transport()
457
        trans.put_bytes('name', "not an index\n")
458
        index1 = GraphIndex(trans, 'name')
459
        index = CombinedGraphIndex([index1])
460
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
461
462
    def test_validate_empty(self):
463
        index = CombinedGraphIndex([])
464
        index.validate()
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
465
466
467
class TestInMemoryGraphIndex(TestCaseWithMemoryTransport):
468
469
    def make_index(self, ref_lists=0, nodes=[]):
470
        result = InMemoryGraphIndex(ref_lists)
471
        result.add_nodes(nodes)
472
        return result
473
474
    def test_add_nodes(self):
475
        index = self.make_index(1)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
476
        index.add_nodes([('name', 'data', ([],))])
477
        index.add_nodes([('name2', '', ([],)), ('name3', '', (['r'],))])
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
478
        self.assertEqual(set([
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
479
            ('name', 'data', ((),)),
480
            ('name2', '', ((),)),
481
            ('name3', '', (('r',),)),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
482
            ]), set(index.iter_all_entries()))
483
484
    def test_iter_all_entries_empty(self):
485
        index = self.make_index()
486
        self.assertEqual([], list(index.iter_all_entries()))
487
488
    def test_iter_all_entries_simple(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
489
        index = self.make_index(nodes=[('name', 'data', ())])
490
        self.assertEqual([('name', 'data')],
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
491
            list(index.iter_all_entries()))
492
493
    def test_iter_all_entries_references(self):
494
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
495
            ('name', 'data', (['ref'], )),
496
            ('ref', 'refdata', ([], ))])
497
        self.assertEqual(set([('name', 'data', (('ref',),)),
498
            ('ref', 'refdata', ((), ))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
499
            set(index.iter_all_entries()))
500
501
    def test_iteration_absent_skipped(self):
502
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
503
            ('name', 'data', (['ref'], ))])
504
        self.assertEqual(set([('name', 'data', (('ref',),))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
505
            set(index.iter_all_entries()))
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
506
        self.assertEqual(set([('name', 'data', (('ref',),))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
507
            set(index.iter_entries(['name'])))
508
        self.assertEqual([], list(index.iter_entries(['ref'])))
509
510
    def test_iter_all_keys(self):
511
        index = self.make_index(1, nodes=[
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
512
            ('name', 'data', (['ref'], )),
513
            ('ref', 'refdata', ([], ))])
514
        self.assertEqual(set([('name', 'data', (('ref',),)),
515
            ('ref', 'refdata', ((), ))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
516
            set(index.iter_entries(['name', 'ref'])))
517
518
    def test_iter_nothing_empty(self):
519
        index = self.make_index()
520
        self.assertEqual([], list(index.iter_entries([])))
521
522
    def test_iter_missing_entry_empty(self):
523
        index = self.make_index()
524
        self.assertEqual([], list(index.iter_entries(['a'])))
525
526
    def test_validate_empty(self):
527
        index = self.make_index()
528
        index.validate()
529
530
    def test_validate_no_refs_content(self):
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
531
        index = self.make_index(nodes=[('key', 'value', ())])
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
532
        index.validate()
533
534