Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.query_unittest.py @ 2e04d454

History | View | Annotate | Download (64.3 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2010, 2011 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Script for testing ganeti.query"""
23

    
24
import re
25
import unittest
26
import random
27

    
28
from ganeti import constants
29
from ganeti import utils
30
from ganeti import compat
31
from ganeti import errors
32
from ganeti import query
33
from ganeti import objects
34
from ganeti import cmdlib
35

    
36
import testutils
37

    
38

    
39
class TestConstants(unittest.TestCase):
40
  def test(self):
41
    self.assertEqual(set(query._VERIFY_FN.keys()),
42
                     constants.QFT_ALL)
43

    
44

    
45
class _QueryData:
46
  def __init__(self, data, **kwargs):
47
    self.data = data
48

    
49
    for name, value in kwargs.items():
50
      setattr(self, name, value)
51

    
52
  def __iter__(self):
53
    return iter(self.data)
54

    
55

    
56
def _GetDiskSize(nr, ctx, item):
57
  disks = item["disks"]
58
  try:
59
    return disks[nr]
60
  except IndexError:
61
    return query._FS_UNAVAIL
62

    
63

    
64
class TestQuery(unittest.TestCase):
65
  def test(self):
66
    (STATIC, DISK) = range(10, 12)
67

    
68
    fielddef = query._PrepareFieldList([
69
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
70
       STATIC, 0, lambda ctx, item: item["name"]),
71
      (query._MakeField("master", "Master", constants.QFT_BOOL, "Master"),
72
       STATIC, 0, lambda ctx, item: ctx.mastername == item["name"]),
73
      ] +
74
      [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
75
                         constants.QFT_UNIT, "Disk size %s" % i),
76
        DISK, 0, compat.partial(_GetDiskSize, i))
77
       for i in range(4)], [])
78

    
79
    q = query.Query(fielddef, ["name"])
80
    self.assertEqual(q.RequestedData(), set([STATIC]))
81
    self.assertEqual(len(q._fields), 1)
82
    self.assertEqual(len(q.GetFields()), 1)
83
    self.assertEqual(q.GetFields()[0].ToDict(),
84
      objects.QueryFieldDefinition(name="name",
85
                                   title="Name",
86
                                   kind=constants.QFT_TEXT,
87
                                   doc="Name").ToDict())
88

    
89
    # Create data only once query has been prepared
90
    data = [
91
      { "name": "node1", "disks": [0, 1, 2], },
92
      { "name": "node2", "disks": [3, 4], },
93
      { "name": "node3", "disks": [5, 6, 7], },
94
      ]
95

    
96
    self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
97
                     [[(constants.RS_NORMAL, "node1")],
98
                      [(constants.RS_NORMAL, "node2")],
99
                      [(constants.RS_NORMAL, "node3")]])
100
    self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node3")),
101
                     [["node1"], ["node2"], ["node3"]])
102

    
103
    q = query.Query(fielddef, ["name", "master"])
104
    self.assertEqual(q.RequestedData(), set([STATIC]))
105
    self.assertEqual(len(q._fields), 2)
106
    self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
107
                     [[(constants.RS_NORMAL, "node1"),
108
                       (constants.RS_NORMAL, False)],
109
                      [(constants.RS_NORMAL, "node2"),
110
                       (constants.RS_NORMAL, False)],
111
                      [(constants.RS_NORMAL, "node3"),
112
                       (constants.RS_NORMAL, True)],
113
                     ])
114

    
115
    q = query.Query(fielddef, ["name", "master", "disk0.size"])
116
    self.assertEqual(q.RequestedData(), set([STATIC, DISK]))
117
    self.assertEqual(len(q._fields), 3)
118
    self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
119
                     [[(constants.RS_NORMAL, "node1"),
120
                       (constants.RS_NORMAL, False),
121
                       (constants.RS_NORMAL, 0)],
122
                      [(constants.RS_NORMAL, "node2"),
123
                       (constants.RS_NORMAL, True),
124
                       (constants.RS_NORMAL, 3)],
125
                      [(constants.RS_NORMAL, "node3"),
126
                       (constants.RS_NORMAL, False),
127
                       (constants.RS_NORMAL, 5)],
128
                     ])
129

    
130
    # With unknown column
131
    q = query.Query(fielddef, ["disk2.size", "disk1.size", "disk99.size",
132
                               "disk0.size"])
133
    self.assertEqual(q.RequestedData(), set([DISK]))
134
    self.assertEqual(len(q._fields), 4)
135
    self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
136
                     [[(constants.RS_NORMAL, 2),
137
                       (constants.RS_NORMAL, 1),
138
                       (constants.RS_UNKNOWN, None),
139
                       (constants.RS_NORMAL, 0)],
140
                      [(constants.RS_UNAVAIL, None),
141
                       (constants.RS_NORMAL, 4),
142
                       (constants.RS_UNKNOWN, None),
143
                       (constants.RS_NORMAL, 3)],
144
                      [(constants.RS_NORMAL, 7),
145
                       (constants.RS_NORMAL, 6),
146
                       (constants.RS_UNKNOWN, None),
147
                       (constants.RS_NORMAL, 5)],
148
                     ])
149
    self.assertRaises(errors.OpPrereqError, q.OldStyleQuery,
150
                      _QueryData(data, mastername="node2"))
151
    self.assertEqual([fdef.ToDict() for fdef in q.GetFields()], [
152
                     { "name": "disk2.size", "title": "DiskSize2",
153
                       "kind": constants.QFT_UNIT, "doc": "Disk size 2", },
154
                     { "name": "disk1.size", "title": "DiskSize1",
155
                       "kind": constants.QFT_UNIT, "doc": "Disk size 1", },
156
                     { "name": "disk99.size", "title": "disk99.size",
157
                       "kind": constants.QFT_UNKNOWN,
158
                       "doc": "Unknown field 'disk99.size'", },
159
                     { "name": "disk0.size", "title": "DiskSize0",
160
                       "kind": constants.QFT_UNIT, "doc": "Disk size 0", },
161
                     ])
162

    
163
    # Empty query
164
    q = query.Query(fielddef, [])
165
    self.assertEqual(q.RequestedData(), set([]))
166
    self.assertEqual(len(q._fields), 0)
167
    self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
168
                     [[], [], []])
169
    self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node2")),
170
                     [[], [], []])
171
    self.assertEqual(q.GetFields(), [])
172

    
173
  def testPrepareFieldList(self):
174
    # Duplicate titles
175
    for (a, b) in [("name", "name"), ("NAME", "name")]:
176
      self.assertRaises(AssertionError, query._PrepareFieldList, [
177
        (query._MakeField("name", b, constants.QFT_TEXT, "Name"), None, 0,
178
         lambda *args: None),
179
        (query._MakeField("other", a, constants.QFT_TEXT, "Other"), None, 0,
180
         lambda *args: None),
181
        ], [])
182

    
183
    # Non-lowercase names
184
    self.assertRaises(AssertionError, query._PrepareFieldList, [
185
      (query._MakeField("NAME", "Name", constants.QFT_TEXT, "Name"), None, 0,
186
       lambda *args: None),
187
      ], [])
188
    self.assertRaises(AssertionError, query._PrepareFieldList, [
189
      (query._MakeField("Name", "Name", constants.QFT_TEXT, "Name"), None, 0,
190
       lambda *args: None),
191
      ], [])
192

    
193
    # Empty name
194
    self.assertRaises(AssertionError, query._PrepareFieldList, [
195
      (query._MakeField("", "Name", constants.QFT_TEXT, "Name"), None, 0,
196
       lambda *args: None),
197
      ], [])
198

    
199
    # Empty title
200
    self.assertRaises(AssertionError, query._PrepareFieldList, [
201
      (query._MakeField("name", "", constants.QFT_TEXT, "Name"), None, 0,
202
       lambda *args: None),
203
      ], [])
204

    
205
    # Whitespace in title
206
    self.assertRaises(AssertionError, query._PrepareFieldList, [
207
      (query._MakeField("name", "Co lu mn", constants.QFT_TEXT, "Name"),
208
       None, 0, lambda *args: None),
209
      ], [])
210

    
211
    # No callable function
212
    self.assertRaises(AssertionError, query._PrepareFieldList, [
213
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
214
       None, 0, None),
215
      ], [])
216

    
217
    # Invalid documentation
218
    for doc in ["", ".", "Hello world\n", "Hello\nWo\nrld", "Hello World!",
219
                "HelloWorld.", "only lowercase", ",", " x y z .\t", "  "]:
220
      self.assertRaises(AssertionError, query._PrepareFieldList, [
221
        (query._MakeField("name", "Name", constants.QFT_TEXT, doc),
222
        None, 0, lambda *args: None),
223
        ], [])
224

    
225
    # Duplicate field name
226
    self.assertRaises(ValueError, query._PrepareFieldList, [
227
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
228
       None, 0, lambda *args: None),
229
      (query._MakeField("name", "Other", constants.QFT_OTHER, "Other"),
230
       None, 0, lambda *args: None),
231
      ], [])
232

    
233
  def testUnknown(self):
234
    fielddef = query._PrepareFieldList([
235
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
236
       None, 0, lambda _, item: "name%s" % item),
237
      (query._MakeField("other0", "Other0", constants.QFT_TIMESTAMP, "Other"),
238
       None, 0, lambda *args: 1234),
239
      (query._MakeField("nodata", "NoData", constants.QFT_NUMBER, "No data"),
240
       None, 0, lambda *args: query._FS_NODATA ),
241
      (query._MakeField("unavail", "Unavail", constants.QFT_BOOL, "Unavail"),
242
       None, 0, lambda *args: query._FS_UNAVAIL),
243
      ], [])
244

    
245
    for selected in [["foo"], ["Hello", "World"],
246
                     ["name1", "other", "foo"]]:
247
      q = query.Query(fielddef, selected)
248
      self.assertEqual(len(q._fields), len(selected))
249
      self.assert_(compat.all(len(row) == len(selected)
250
                              for row in q.Query(_QueryData(range(1, 10)))))
251
      self.assertEqual(q.Query(_QueryData(range(1, 10))),
252
                       [[(constants.RS_UNKNOWN, None)] * len(selected)
253
                        for i in range(1, 10)])
254
      self.assertEqual([fdef.ToDict() for fdef in q.GetFields()],
255
                       [{ "name": name, "title": name,
256
                          "kind": constants.QFT_UNKNOWN,
257
                          "doc": "Unknown field '%s'" % name}
258
                        for name in selected])
259

    
260
    q = query.Query(fielddef, ["name", "other0", "nodata", "unavail"])
261
    self.assertEqual(len(q._fields), 4)
262
    self.assertEqual(q.OldStyleQuery(_QueryData(range(1, 10))), [
263
                     ["name%s" % i, 1234, None, None]
264
                     for i in range(1, 10)
265
                     ])
266

    
267
    q = query.Query(fielddef, ["name", "other0", "nodata", "unavail", "unk"])
268
    self.assertEqual(len(q._fields), 5)
269
    self.assertEqual(q.Query(_QueryData(range(1, 10))),
270
                     [[(constants.RS_NORMAL, "name%s" % i),
271
                       (constants.RS_NORMAL, 1234),
272
                       (constants.RS_NODATA, None),
273
                       (constants.RS_UNAVAIL, None),
274
                       (constants.RS_UNKNOWN, None)]
275
                      for i in range(1, 10)])
276

    
277
  def testAliases(self):
278
    fields = [
279
      (query._MakeField("a", "a-title", constants.QFT_TEXT, "Field A"),
280
       None, 0, lambda *args: None),
281
      (query._MakeField("b", "b-title", constants.QFT_TEXT, "Field B"),
282
       None, 0, lambda *args: None),
283
      ]
284
    # duplicate field
285
    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
286
                      [("b", "a")])
287
    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
288
                      [("c", "b"), ("c", "a")])
289
    # missing target
290
    self.assertRaises(AssertionError, query._PrepareFieldList, fields,
291
                      [("c", "d")])
292
    fdefs = query._PrepareFieldList(fields, [("c", "b")])
293
    self.assertEqual(len(fdefs), 3)
294
    self.assertEqual(fdefs["b"][1:], fdefs["c"][1:])
295

    
296

    
297
class TestGetNodeRole(unittest.TestCase):
298
  def test(self):
299
    tested_role = set()
300

    
301
    checks = [
302
      (constants.NR_MASTER, "node1", objects.Node(name="node1")),
303
      (constants.NR_MCANDIDATE, "master",
304
       objects.Node(name="node1", master_candidate=True)),
305
      (constants.NR_REGULAR, "master", objects.Node(name="node1")),
306
      (constants.NR_DRAINED, "master",
307
       objects.Node(name="node1", drained=True)),
308
      (constants.NR_OFFLINE,
309
       "master", objects.Node(name="node1", offline=True)),
310
      ]
311

    
312
    for (role, master_name, node) in checks:
313
      result = query._GetNodeRole(node, master_name)
314
      self.assertEqual(result, role)
315
      tested_role.add(result)
316

    
317
    self.assertEqual(tested_role, constants.NR_ALL)
318

    
319

    
320
class TestNodeQuery(unittest.TestCase):
321
  def _Create(self, selected):
322
    return query.Query(query.NODE_FIELDS, selected)
323

    
324
  def testSimple(self):
325
    nodes = [
326
      objects.Node(name="node1", drained=False),
327
      objects.Node(name="node2", drained=True),
328
      objects.Node(name="node3", drained=False),
329
      ]
330
    for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]:
331
      nqd = query.NodeQueryData(nodes, live_data, None, None, None, None, None,
332
                                None)
333

    
334
      q = self._Create(["name", "drained"])
335
      self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG]))
336
      self.assertEqual(q.Query(nqd),
337
                       [[(constants.RS_NORMAL, "node1"),
338
                         (constants.RS_NORMAL, False)],
339
                        [(constants.RS_NORMAL, "node2"),
340
                         (constants.RS_NORMAL, True)],
341
                        [(constants.RS_NORMAL, "node3"),
342
                         (constants.RS_NORMAL, False)],
343
                       ])
344
      self.assertEqual(q.OldStyleQuery(nqd),
345
                       [["node1", False],
346
                        ["node2", True],
347
                        ["node3", False]])
348

    
349
  def test(self):
350
    selected = query.NODE_FIELDS.keys()
351
    field_index = dict((field, idx) for idx, field in enumerate(selected))
352

    
353
    q = self._Create(selected)
354
    self.assertEqual(q.RequestedData(),
355
                     set([query.NQ_CONFIG, query.NQ_LIVE, query.NQ_INST,
356
                          query.NQ_GROUP, query.NQ_OOB]))
357

    
358
    cluster = objects.Cluster(cluster_name="testcluster",
359
      hvparams=constants.HVC_DEFAULTS,
360
      beparams={
361
        constants.PP_DEFAULT: constants.BEC_DEFAULTS,
362
        },
363
      nicparams={
364
        constants.PP_DEFAULT: constants.NICC_DEFAULTS,
365
        },
366
      ndparams=constants.NDC_DEFAULTS,
367
        )
368

    
369
    node_names = ["node%s" % i for i in range(20)]
370
    master_name = node_names[3]
371
    nodes = [
372
      objects.Node(name=name,
373
                   primary_ip="192.0.2.%s" % idx,
374
                   secondary_ip="192.0.100.%s" % idx,
375
                   serial_no=7789 * idx,
376
                   master_candidate=(name != master_name and idx % 3 == 0),
377
                   offline=False,
378
                   drained=False,
379
                   powered=True,
380
                   vm_capable=True,
381
                   master_capable=False,
382
                   ndparams={},
383
                   group="default",
384
                   ctime=1290006900,
385
                   mtime=1290006913,
386
                   uuid="fd9ccebe-6339-43c9-a82e-94bbe575%04d" % idx)
387
      for idx, name in enumerate(node_names)
388
      ]
389

    
390
    master_node = nodes[3]
391
    master_node.AddTag("masternode")
392
    master_node.AddTag("another")
393
    master_node.AddTag("tag")
394
    master_node.ctime = None
395
    master_node.mtime = None
396
    assert master_node.name == master_name
397

    
398
    live_data_name = node_names[4]
399
    assert live_data_name != master_name
400

    
401
    fake_live_data = {
402
      "bootid": "a2504766-498e-4b25-b21e-d23098dc3af4",
403
      "cnodes": 4,
404
      "csockets": 4,
405
      "ctotal": 8,
406
      "mnode": 128,
407
      "mfree": 100,
408
      "mtotal": 4096,
409
      "dfree": 5 * 1024 * 1024,
410
      "dtotal": 100 * 1024 * 1024,
411
      }
412

    
413
    assert (sorted(query._NODE_LIVE_FIELDS.keys()) ==
414
            sorted(fake_live_data.keys()))
415

    
416
    live_data = dict.fromkeys(node_names, {})
417
    live_data[live_data_name] = \
418
      dict((query._NODE_LIVE_FIELDS[name][2], value)
419
           for name, value in fake_live_data.items())
420

    
421
    node_to_primary = dict((name, set()) for name in node_names)
422
    node_to_primary[master_name].update(["inst1", "inst2"])
423

    
424
    node_to_secondary = dict((name, set()) for name in node_names)
425
    node_to_secondary[live_data_name].update(["instX", "instY", "instZ"])
426

    
427
    ng_uuid = "492b4b74-8670-478a-b98d-4c53a76238e6"
428
    groups = {
429
      ng_uuid: objects.NodeGroup(name="ng1", uuid=ng_uuid, ndparams={}),
430
      }
431

    
432
    oob_not_powered_node = node_names[0]
433
    nodes[0].powered = False
434
    oob_support = dict((name, False) for name in node_names)
435
    oob_support[master_name] = True
436
    oob_support[oob_not_powered_node] = True
437

    
438
    master_node.group = ng_uuid
439

    
440
    nqd = query.NodeQueryData(nodes, live_data, master_name,
441
                              node_to_primary, node_to_secondary, groups,
442
                              oob_support, cluster)
443
    result = q.Query(nqd)
444
    self.assert_(compat.all(len(row) == len(selected) for row in result))
445
    self.assertEqual([row[field_index["name"]] for row in result],
446
                     [(constants.RS_NORMAL, name) for name in node_names])
447

    
448
    node_to_row = dict((row[field_index["name"]][1], idx)
449
                       for idx, row in enumerate(result))
450

    
451
    master_row = result[node_to_row[master_name]]
452
    self.assert_(master_row[field_index["master"]])
453
    self.assert_(master_row[field_index["role"]], "M")
454
    self.assertEqual(master_row[field_index["group"]],
455
                     (constants.RS_NORMAL, "ng1"))
456
    self.assertEqual(master_row[field_index["group.uuid"]],
457
                     (constants.RS_NORMAL, ng_uuid))
458
    self.assertEqual(master_row[field_index["ctime"]],
459
                     (constants.RS_UNAVAIL, None))
460
    self.assertEqual(master_row[field_index["mtime"]],
461
                     (constants.RS_UNAVAIL, None))
462

    
463
    self.assert_(row[field_index["pip"]] == node.primary_ip and
464
                 row[field_index["sip"]] == node.secondary_ip and
465
                 set(row[field_index["tags"]]) == node.GetTags() and
466
                 row[field_index["serial_no"]] == node.serial_no and
467
                 row[field_index["role"]] == query._GetNodeRole(node,
468
                                                                master_name) and
469
                 (node.name == master_name or
470
                  (row[field_index["group"]] == "<unknown>" and
471
                   row[field_index["group.uuid"]] is None and
472
                   row[field_index["ctime"]] == (constants.RS_NORMAL,
473
                                                 node.ctime) and
474
                   row[field_index["mtime"]] == (constants.RS_NORMAL,
475
                                                 node.mtime) and
476
                   row[field_index["powered"]] == (constants.RS_NORMAL,
477
                                                   True))) or
478
                 (node.name == oob_not_powered_node and
479
                  row[field_index["powered"]] == (constants.RS_NORMAL,
480
                                                  False)) or
481
                 row[field_index["powered"]] == (constants.RS_UNAVAIL, None)
482
                 for row, node in zip(result, nodes))
483

    
484
    live_data_row = result[node_to_row[live_data_name]]
485

    
486
    for (field, value) in fake_live_data.items():
487
      self.assertEqual(live_data_row[field_index[field]],
488
                       (constants.RS_NORMAL, value))
489

    
490
    self.assertEqual(master_row[field_index["pinst_cnt"]],
491
                     (constants.RS_NORMAL, 2))
492
    self.assertEqual(live_data_row[field_index["sinst_cnt"]],
493
                     (constants.RS_NORMAL, 3))
494
    self.assertEqual(master_row[field_index["pinst_list"]],
495
                     (constants.RS_NORMAL,
496
                      list(node_to_primary[master_name])))
497
    self.assertEqual(live_data_row[field_index["sinst_list"]],
498
                     (constants.RS_NORMAL,
499
                      list(node_to_secondary[live_data_name])))
500

    
501
  def testGetLiveNodeField(self):
502
    nodes = [
503
      objects.Node(name="node1", drained=False, offline=False,
504
                   vm_capable=True),
505
      objects.Node(name="node2", drained=True, offline=False,
506
                   vm_capable=True),
507
      objects.Node(name="node3", drained=False, offline=False,
508
                   vm_capable=True),
509
      objects.Node(name="node4", drained=False, offline=True,
510
                   vm_capable=True),
511
      objects.Node(name="node5", drained=False, offline=False,
512
                   vm_capable=False),
513
      ]
514
    live_data = dict.fromkeys([node.name for node in nodes], {})
515

    
516
    # No data
517
    nqd = query.NodeQueryData(None, None, None, None, None, None, None, None)
518
    self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
519
                                             nqd, nodes[0]),
520
                     query._FS_NODATA)
521

    
522
    # Missing field
523
    ctx = _QueryData(None, curlive_data={
524
      "some": 1,
525
      "other": 2,
526
      })
527
    self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
528
                                             ctx, nodes[0]),
529
                     query._FS_UNAVAIL)
530

    
531
    # Wrong format/datatype
532
    ctx = _QueryData(None, curlive_data={
533
      "hello": ["Hello World"],
534
      "other": 2,
535
      })
536
    self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
537
                                             ctx, nodes[0]),
538
                     query._FS_UNAVAIL)
539

    
540
    # Offline node
541
    assert nodes[3].offline
542
    ctx = _QueryData(None, curlive_data={})
543
    self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
544
                                             ctx, nodes[3]),
545
                     query._FS_OFFLINE, None)
546

    
547
    # Wrong field type
548
    ctx = _QueryData(None, curlive_data={"hello": 123})
549
    self.assertRaises(AssertionError, query._GetLiveNodeField,
550
                      "hello", constants.QFT_BOOL, ctx, nodes[0])
551

    
552
    # Non-vm_capable node
553
    assert not nodes[4].vm_capable
554
    ctx = _QueryData(None, curlive_data={})
555
    self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
556
                                             ctx, nodes[4]),
557
                     query._FS_UNAVAIL, None)
558

    
559

    
560
class TestInstanceQuery(unittest.TestCase):
561
  def _Create(self, selected):
562
    return query.Query(query.INSTANCE_FIELDS, selected)
563

    
564
  def testSimple(self):
565
    q = self._Create(["name", "be/memory", "ip"])
566
    self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
567

    
568
    cluster = objects.Cluster(cluster_name="testcluster",
569
      hvparams=constants.HVC_DEFAULTS,
570
      beparams={
571
        constants.PP_DEFAULT: constants.BEC_DEFAULTS,
572
        },
573
      nicparams={
574
        constants.PP_DEFAULT: constants.NICC_DEFAULTS,
575
        },
576
      os_hvp={},
577
      osparams={})
578

    
579
    instances = [
580
      objects.Instance(name="inst1", hvparams={}, beparams={}, osparams={},
581
                       nics=[], os="deb1"),
582
      objects.Instance(name="inst2", hvparams={}, nics=[], osparams={},
583
        os="foomoo",
584
        beparams={
585
          constants.BE_MEMORY: 512,
586
        }),
587
      objects.Instance(name="inst3", hvparams={}, beparams={}, osparams={},
588
        os="dos", nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
589
      ]
590

    
591
    iqd = query.InstanceQueryData(instances, cluster, None, [], [], {},
592
                                  set(), {}, None, None)
593
    self.assertEqual(q.Query(iqd),
594
      [[(constants.RS_NORMAL, "inst1"),
595
        (constants.RS_NORMAL, 128),
596
        (constants.RS_UNAVAIL, None),
597
       ],
598
       [(constants.RS_NORMAL, "inst2"),
599
        (constants.RS_NORMAL, 512),
600
        (constants.RS_UNAVAIL, None),
601
       ],
602
       [(constants.RS_NORMAL, "inst3"),
603
        (constants.RS_NORMAL, 128),
604
        (constants.RS_NORMAL, "192.0.2.99"),
605
       ]])
606
    self.assertEqual(q.OldStyleQuery(iqd),
607
      [["inst1", 128, None],
608
       ["inst2", 512, None],
609
       ["inst3", 128, "192.0.2.99"]])
610

    
611
  def test(self):
612
    selected = query.INSTANCE_FIELDS.keys()
613
    fieldidx = dict((field, idx) for idx, field in enumerate(selected))
614

    
615
    macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
616
            for i in range(20)]
617

    
618
    q = self._Create(selected)
619
    self.assertEqual(q.RequestedData(),
620
                     set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE,
621
                          query.IQ_CONSOLE, query.IQ_NODES]))
622

    
623
    cluster = objects.Cluster(cluster_name="testcluster",
624
      hvparams=constants.HVC_DEFAULTS,
625
      beparams={
626
        constants.PP_DEFAULT: constants.BEC_DEFAULTS,
627
        },
628
      nicparams={
629
        constants.PP_DEFAULT: constants.NICC_DEFAULTS,
630
        },
631
      os_hvp={},
632
      tcpudp_port_pool=set(),
633
      osparams={
634
        "deb99": {
635
          "clean_install": "yes",
636
          },
637
        })
638

    
639
    offline_nodes = ["nodeoff1", "nodeoff2"]
640
    bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
641
    nodes = ["node%s" % i for i in range(10)] + bad_nodes
642

    
643
    instances = [
644
      objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
645
        uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
646
        ctime=1291244000, mtime=1291244400, serial_no=30,
647
        admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_PVM,
648
        os="linux1",
649
        primary_node="node1",
650
        disk_template=constants.DT_PLAIN,
651
        disks=[],
652
        osparams={}),
653
      objects.Instance(name="inst2", hvparams={}, nics=[],
654
        uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
655
        ctime=1291211000, mtime=1291211077, serial_no=1,
656
        admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_HVM,
657
        os="deb99",
658
        primary_node="node5",
659
        disk_template=constants.DT_DISKLESS,
660
        disks=[],
661
        beparams={
662
          constants.BE_MEMORY: 512,
663
        },
664
        osparams={}),
665
      objects.Instance(name="inst3", hvparams={}, beparams={},
666
        uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
667
        ctime=1291011000, mtime=1291013000, serial_no=1923,
668
        admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_KVM,
669
        os="busybox",
670
        primary_node="node6",
671
        disk_template=constants.DT_DRBD8,
672
        disks=[],
673
        nics=[
674
          objects.NIC(ip="192.0.2.99", mac=macs.pop(),
675
                      nicparams={
676
                        constants.NIC_LINK: constants.DEFAULT_BRIDGE,
677
                        }),
678
          objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
679
          ],
680
        osparams={}),
681
      objects.Instance(name="inst4", hvparams={}, beparams={},
682
        uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
683
        ctime=1291244390, mtime=1291244395, serial_no=25,
684
        admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_PVM,
685
        os="linux1",
686
        primary_node="nodeoff2",
687
        disk_template=constants.DT_DRBD8,
688
        disks=[],
689
        nics=[
690
          objects.NIC(ip="192.0.2.1", mac=macs.pop(),
691
                      nicparams={
692
                        constants.NIC_LINK: constants.DEFAULT_BRIDGE,
693
                        }),
694
          objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
695
          objects.NIC(ip="192.0.2.3", mac=macs.pop(),
696
                      nicparams={
697
                        constants.NIC_MODE: constants.NIC_MODE_ROUTED,
698
                        }),
699
          objects.NIC(ip="192.0.2.4", mac=macs.pop(),
700
                      nicparams={
701
                        constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
702
                        constants.NIC_LINK: "eth123",
703
                        }),
704
          ],
705
        osparams={}),
706
      objects.Instance(name="inst5", hvparams={}, nics=[],
707
        uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
708
        ctime=1231211000, mtime=1261200000, serial_no=3,
709
        admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_HVM,
710
        os="deb99",
711
        primary_node="nodebad2",
712
        disk_template=constants.DT_DISKLESS,
713
        disks=[],
714
        beparams={
715
          constants.BE_MEMORY: 512,
716
        },
717
        osparams={}),
718
      objects.Instance(name="inst6", hvparams={}, nics=[],
719
        uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
720
        ctime=7513, mtime=11501, serial_no=13390,
721
        admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_HVM,
722
        os="deb99",
723
        primary_node="node7",
724
        disk_template=constants.DT_DISKLESS,
725
        disks=[],
726
        beparams={
727
          constants.BE_MEMORY: 768,
728
        },
729
        osparams={
730
          "clean_install": "no",
731
          }),
732
      objects.Instance(name="inst7", hvparams={}, nics=[],
733
        uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
734
        ctime=None, mtime=None, serial_no=1947,
735
        admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_HVM,
736
        os="deb99",
737
        primary_node="node6",
738
        disk_template=constants.DT_DISKLESS,
739
        disks=[],
740
        beparams={},
741
        osparams={}),
742
      objects.Instance(name="inst8", hvparams={}, nics=[],
743
        uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920f",
744
        ctime=None, mtime=None, serial_no=19478,
745
        admin_state=constants.ADMINST_OFFLINE, hypervisor=constants.HT_XEN_HVM,
746
        os="deb99",
747
        primary_node="node6",
748
        disk_template=constants.DT_DISKLESS,
749
        disks=[],
750
        beparams={},
751
        osparams={}),
752
      ]
753

    
754
    assert not utils.FindDuplicates(inst.name for inst in instances)
755

    
756
    instbyname = dict((inst.name, inst) for inst in instances)
757

    
758
    disk_usage = dict((inst.name,
759
                       cmdlib._ComputeDiskSize(inst.disk_template,
760
                                               [{"size": disk.size}
761
                                                for disk in inst.disks]))
762
                      for inst in instances)
763

    
764
    inst_bridges = {
765
      "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
766
      "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
767
                None, "eth123"],
768
      }
769

    
770
    live_data = {
771
      "inst2": {
772
        "vcpus": 3,
773
        },
774
      "inst4": {
775
        "memory": 123,
776
        },
777
      "inst6": {
778
        "memory": 768,
779
        },
780
      "inst7": {
781
        "vcpus": 3,
782
        },
783
      }
784
    wrongnode_inst = set(["inst7"])
785

    
786
    consinfo = dict((inst.name, None) for inst in instances)
787
    consinfo["inst7"] = \
788
      objects.InstanceConsole(instance="inst7", kind=constants.CONS_SSH,
789
                              host=instbyname["inst7"].primary_node,
790
                              user=constants.GANETI_RUNAS,
791
                              command=["hostname"]).ToDict()
792

    
793
    iqd = query.InstanceQueryData(instances, cluster, disk_usage,
794
                                  offline_nodes, bad_nodes, live_data,
795
                                  wrongnode_inst, consinfo, {}, {})
796
    result = q.Query(iqd)
797
    self.assertEqual(len(result), len(instances))
798
    self.assert_(compat.all(len(row) == len(selected)
799
                            for row in result))
800

    
801
    assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
802
           "Offline nodes not included in bad nodes"
803

    
804
    tested_status = set()
805

    
806
    for (inst, row) in zip(instances, result):
807
      assert inst.primary_node in nodes
808

    
809
      self.assertEqual(row[fieldidx["name"]],
810
                       (constants.RS_NORMAL, inst.name))
811

    
812
      if inst.primary_node in offline_nodes:
813
        exp_status = constants.INSTST_NODEOFFLINE
814
      elif inst.primary_node in bad_nodes:
815
        exp_status = constants.INSTST_NODEDOWN
816
      elif inst.name in live_data:
817
        if inst.name in wrongnode_inst:
818
          exp_status = constants.INSTST_WRONGNODE
819
        elif inst.admin_state == constants.ADMINST_UP:
820
          exp_status = constants.INSTST_RUNNING
821
        else:
822
          exp_status = constants.INSTST_ERRORUP
823
      elif inst.admin_state == constants.ADMINST_UP:
824
        exp_status = constants.INSTST_ERRORDOWN
825
      elif inst.admin_state == constants.ADMINST_DOWN:
826
        exp_status = constants.INSTST_ADMINDOWN
827
      else:
828
        exp_status = constants.INSTST_ADMINOFFLINE
829

    
830
      self.assertEqual(row[fieldidx["status"]],
831
                       (constants.RS_NORMAL, exp_status))
832

    
833
      (_, status) = row[fieldidx["status"]]
834
      tested_status.add(status)
835

    
836
      for (field, livefield) in [("oper_ram", "memory"),
837
                                 ("oper_vcpus", "vcpus")]:
838
        if inst.primary_node in bad_nodes:
839
          exp = (constants.RS_NODATA, None)
840
        elif inst.name in live_data:
841
          value = live_data[inst.name].get(livefield, None)
842
          if value is None:
843
            exp = (constants.RS_UNAVAIL, None)
844
          else:
845
            exp = (constants.RS_NORMAL, value)
846
        else:
847
          exp = (constants.RS_UNAVAIL, None)
848

    
849
        self.assertEqual(row[fieldidx[field]], exp)
850

    
851
      bridges = inst_bridges.get(inst.name, [])
852
      self.assertEqual(row[fieldidx["nic.bridges"]],
853
                       (constants.RS_NORMAL, bridges))
854
      if bridges:
855
        self.assertEqual(row[fieldidx["bridge"]],
856
                         (constants.RS_NORMAL, bridges[0]))
857
      else:
858
        self.assertEqual(row[fieldidx["bridge"]],
859
                         (constants.RS_UNAVAIL, None))
860

    
861
      for i in range(constants.MAX_NICS):
862
        if i < len(bridges) and bridges[i] is not None:
863
          exp = (constants.RS_NORMAL, bridges[i])
864
        else:
865
          exp = (constants.RS_UNAVAIL, None)
866
        self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
867

    
868
      if inst.primary_node in bad_nodes:
869
        exp = (constants.RS_NODATA, None)
870
      else:
871
        exp = (constants.RS_NORMAL, inst.name in live_data)
872
      self.assertEqual(row[fieldidx["oper_state"]], exp)
873

    
874
      cust_exp = (constants.RS_NORMAL, {})
875
      if inst.os == "deb99":
876
        if inst.name == "inst6":
877
          exp = (constants.RS_NORMAL, {"clean_install": "no"})
878
          cust_exp = exp
879
        else:
880
          exp = (constants.RS_NORMAL, {"clean_install": "yes"})
881
      else:
882
        exp = (constants.RS_NORMAL, {})
883
      self.assertEqual(row[fieldidx["osparams"]], exp)
884
      self.assertEqual(row[fieldidx["custom_osparams"]], cust_exp)
885

    
886
      usage = disk_usage[inst.name]
887
      if usage is None:
888
        usage = 0
889
      self.assertEqual(row[fieldidx["disk_usage"]],
890
                       (constants.RS_NORMAL, usage))
891

    
892
      for alias, target in [("sda_size", "disk.size/0"),
893
                            ("sdb_size", "disk.size/1"),
894
                            ("vcpus", "be/vcpus"),
895
                            ("ip", "nic.ip/0"),
896
                            ("mac", "nic.mac/0"),
897
                            ("bridge", "nic.bridge/0"),
898
                            ("nic_mode", "nic.mode/0"),
899
                            ("nic_link", "nic.link/0"),
900
                            ]:
901
        self.assertEqual(row[fieldidx[alias]], row[fieldidx[target]])
902

    
903
      for field in ["ctime", "mtime"]:
904
        if getattr(inst, field) is None:
905
          # No ctime/mtime
906
          exp = (constants.RS_UNAVAIL, None)
907
        else:
908
          exp = (constants.RS_NORMAL, getattr(inst, field))
909
        self.assertEqual(row[fieldidx[field]], exp)
910

    
911
      self._CheckInstanceConsole(inst, row[fieldidx["console"]])
912

    
913
    # Ensure all possible status' have been tested
914
    self.assertEqual(tested_status, constants.INSTST_ALL)
915

    
916
  def _CheckInstanceConsole(self, instance, (status, consdata)):
917
    if instance.name == "inst7":
918
      self.assertEqual(status, constants.RS_NORMAL)
919
      console = objects.InstanceConsole.FromDict(consdata)
920
      self.assertTrue(console.Validate())
921
      self.assertEqual(console.host, instance.primary_node)
922
    else:
923
      self.assertEqual(status, constants.RS_UNAVAIL)
924

    
925

    
926
class TestGroupQuery(unittest.TestCase):
927

    
928
  def setUp(self):
929
    self.groups = [
930
      objects.NodeGroup(name="default",
931
                        uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
932
                        alloc_policy=constants.ALLOC_POLICY_PREFERRED),
933
      objects.NodeGroup(name="restricted",
934
                        uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
935
                        alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
936
      ]
937

    
938
  def _Create(self, selected):
939
    return query.Query(query.GROUP_FIELDS, selected)
940

    
941
  def testSimple(self):
942
    q = self._Create(["name", "uuid", "alloc_policy"])
943
    gqd = query.GroupQueryData(self.groups, None, None)
944

    
945
    self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
946

    
947
    self.assertEqual(q.Query(gqd),
948
      [[(constants.RS_NORMAL, "default"),
949
        (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
950
        (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
951
        ],
952
       [(constants.RS_NORMAL, "restricted"),
953
        (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
954
        (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
955
        ],
956
       ])
957

    
958
  def testNodes(self):
959
    groups_to_nodes = {
960
      "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
961
      "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
962
      }
963

    
964
    q = self._Create(["name", "node_cnt", "node_list"])
965
    gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
966

    
967
    self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
968

    
969
    self.assertEqual(q.Query(gqd),
970
                     [[(constants.RS_NORMAL, "default"),
971
                       (constants.RS_NORMAL, 2),
972
                       (constants.RS_NORMAL, ["node1", "node2"]),
973
                       ],
974
                      [(constants.RS_NORMAL, "restricted"),
975
                       (constants.RS_NORMAL, 3),
976
                       (constants.RS_NORMAL, ["node1", "node9", "node10"]),
977
                       ],
978
                      ])
979

    
980
  def testInstances(self):
981
    groups_to_instances = {
982
      "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
983
      "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
984
      }
985

    
986
    q = self._Create(["pinst_cnt", "pinst_list"])
987
    gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
988

    
989
    self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
990

    
991
    self.assertEqual(q.Query(gqd),
992
                     [[(constants.RS_NORMAL, 2),
993
                       (constants.RS_NORMAL, ["inst1", "inst2"]),
994
                       ],
995
                      [(constants.RS_NORMAL, 3),
996
                       (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
997
                       ],
998
                      ])
999

    
1000

    
1001
class TestOsQuery(unittest.TestCase):
1002
  def _Create(self, selected):
1003
    return query.Query(query.OS_FIELDS, selected)
1004

    
1005
  def test(self):
1006
    variants = ["v00", "plain", "v3", "var0", "v33", "v20"]
1007
    api_versions = [10, 0, 15, 5]
1008
    parameters = ["zpar3", "apar9"]
1009

    
1010
    assert variants != sorted(variants) and variants != utils.NiceSort(variants)
1011
    assert (api_versions != sorted(api_versions) and
1012
            api_versions != utils.NiceSort(variants))
1013
    assert (parameters != sorted(parameters) and
1014
            parameters != utils.NiceSort(parameters))
1015

    
1016
    data = [
1017
      query.OsInfo(name="debian", valid=False, hidden=False, blacklisted=False,
1018
                   variants=set(), api_versions=set(), parameters=set(),
1019
                   node_status={ "some": "status", }),
1020
      query.OsInfo(name="dos", valid=True, hidden=False, blacklisted=True,
1021
                   variants=set(variants),
1022
                   api_versions=set(api_versions),
1023
                   parameters=set(parameters),
1024
                   node_status={ "some": "other", "status": None, }),
1025
      ]
1026

    
1027

    
1028
    q = self._Create(["name", "valid", "hidden", "blacklisted", "variants",
1029
                      "api_versions", "parameters", "node_status"])
1030
    self.assertEqual(q.RequestedData(), set([]))
1031
    self.assertEqual(q.Query(data),
1032
                     [[(constants.RS_NORMAL, "debian"),
1033
                       (constants.RS_NORMAL, False),
1034
                       (constants.RS_NORMAL, False),
1035
                       (constants.RS_NORMAL, False),
1036
                       (constants.RS_NORMAL, []),
1037
                       (constants.RS_NORMAL, []),
1038
                       (constants.RS_NORMAL, []),
1039
                       (constants.RS_NORMAL, {"some": "status"})],
1040
                      [(constants.RS_NORMAL, "dos"),
1041
                       (constants.RS_NORMAL, True),
1042
                       (constants.RS_NORMAL, False),
1043
                       (constants.RS_NORMAL, True),
1044
                       (constants.RS_NORMAL,
1045
                        ["plain", "v00", "v3", "v20", "v33", "var0"]),
1046
                       (constants.RS_NORMAL, [0, 5, 10, 15]),
1047
                       (constants.RS_NORMAL, ["apar9", "zpar3"]),
1048
                       (constants.RS_NORMAL,
1049
                        { "some": "other", "status": None, })
1050
                       ]])
1051

    
1052

    
1053
class TestQueryFields(unittest.TestCase):
1054
  def testAllFields(self):
1055
    for fielddefs in query.ALL_FIELD_LISTS:
1056
      result = query.QueryFields(fielddefs, None)
1057
      self.assert_(isinstance(result, dict))
1058
      response = objects.QueryFieldsResponse.FromDict(result)
1059
      self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1060
        [(fdef2.name, fdef2.title)
1061
         for (fdef2, _, _, _) in utils.NiceSort(fielddefs.values(),
1062
                                                key=lambda x: x[0].name)])
1063

    
1064
  def testSomeFields(self):
1065
    rnd = random.Random(5357)
1066

    
1067
    for _ in range(10):
1068
      for fielddefs in query.ALL_FIELD_LISTS:
1069
        if len(fielddefs) > 20:
1070
          sample_size = rnd.randint(5, 20)
1071
        else:
1072
          sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
1073
        fields = [fdef for (fdef, _, _, _) in rnd.sample(fielddefs.values(),
1074
                                                         sample_size)]
1075
        result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
1076
        self.assert_(isinstance(result, dict))
1077
        response = objects.QueryFieldsResponse.FromDict(result)
1078
        self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1079
                         [(fdef2.name, fdef2.title) for fdef2 in fields])
1080

    
1081

    
1082
class TestQueryFilter(unittest.TestCase):
1083
  def testRequestedNames(self):
1084
    innerfilter = [["=", "name", "x%s" % i] for i in range(4)]
1085

    
1086
    for fielddefs in query.ALL_FIELD_LISTS:
1087
      assert "name" in fielddefs
1088

    
1089
      # No name field
1090
      q = query.Query(fielddefs, ["name"], qfilter=["=", "name", "abc"],
1091
                      namefield=None)
1092
      self.assertEqual(q.RequestedNames(), None)
1093

    
1094
      # No filter
1095
      q = query.Query(fielddefs, ["name"], qfilter=None, namefield="name")
1096
      self.assertEqual(q.RequestedNames(), None)
1097

    
1098
      # Check empty query
1099
      q = query.Query(fielddefs, ["name"], qfilter=["|"], namefield="name")
1100
      self.assertEqual(q.RequestedNames(), None)
1101

    
1102
      # Check order
1103
      q = query.Query(fielddefs, ["name"], qfilter=["|"] + innerfilter,
1104
                      namefield="name")
1105
      self.assertEqual(q.RequestedNames(), ["x0", "x1", "x2", "x3"])
1106

    
1107
      # Check reverse order
1108
      q = query.Query(fielddefs, ["name"],
1109
                      qfilter=["|"] + list(reversed(innerfilter)),
1110
                      namefield="name")
1111
      self.assertEqual(q.RequestedNames(), ["x3", "x2", "x1", "x0"])
1112

    
1113
      # Duplicates
1114
      q = query.Query(fielddefs, ["name"],
1115
                      qfilter=["|"] + innerfilter + list(reversed(innerfilter)),
1116
                      namefield="name")
1117
      self.assertEqual(q.RequestedNames(), ["x0", "x1", "x2", "x3"])
1118

    
1119
      # Unknown name field
1120
      self.assertRaises(AssertionError, query.Query, fielddefs, ["name"],
1121
                        namefield="_unknown_field_")
1122

    
1123
      # Filter with AND
1124
      q = query.Query(fielddefs, ["name"],
1125
                      qfilter=["|", ["=", "name", "foo"],
1126
                                    ["&", ["=", "name", ""]]],
1127
                      namefield="name")
1128
      self.assertTrue(q.RequestedNames() is None)
1129

    
1130
      # Filter with NOT
1131
      q = query.Query(fielddefs, ["name"],
1132
                      qfilter=["|", ["=", "name", "foo"],
1133
                                    ["!", ["=", "name", ""]]],
1134
                      namefield="name")
1135
      self.assertTrue(q.RequestedNames() is None)
1136

    
1137
      # Filter with only OR (names must be in correct order)
1138
      q = query.Query(fielddefs, ["name"],
1139
                      qfilter=["|", ["=", "name", "x17361"],
1140
                                    ["|", ["=", "name", "x22015"]],
1141
                                    ["|", ["|", ["=", "name", "x13193"]]],
1142
                                    ["=", "name", "x15215"]],
1143
                      namefield="name")
1144
      self.assertEqual(q.RequestedNames(),
1145
                       ["x17361", "x22015", "x13193", "x15215"])
1146

    
1147
  @staticmethod
1148
  def _GenNestedFilter(op, depth):
1149
    nested = ["=", "name", "value"]
1150
    for i in range(depth):
1151
      nested = [op, nested]
1152
    return nested
1153

    
1154
  def testCompileFilter(self):
1155
    levels_max = query._FilterCompilerHelper._LEVELS_MAX
1156

    
1157
    checks = [
1158
      [], ["="], ["=", "foo"], ["unknownop"], ["!"],
1159
      ["=", "_unknown_field", "value"],
1160
      self._GenNestedFilter("|", levels_max),
1161
      self._GenNestedFilter("|", levels_max * 3),
1162
      self._GenNestedFilter("!", levels_max),
1163
      ]
1164

    
1165
    for fielddefs in query.ALL_FIELD_LISTS:
1166
      for qfilter in checks:
1167
        self.assertRaises(errors.ParameterError, query._CompileFilter,
1168
                          fielddefs, None, qfilter)
1169

    
1170
      for op in ["|", "!"]:
1171
        qfilter = self._GenNestedFilter(op, levels_max - 1)
1172
        self.assertTrue(callable(query._CompileFilter(fielddefs, None,
1173
                                                      qfilter)))
1174

    
1175
  def testQueryInputOrder(self):
1176
    fielddefs = query._PrepareFieldList([
1177
      (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1178
       None, 0, lambda ctx, item: item["pnode"]),
1179
      (query._MakeField("snode", "SNode", constants.QFT_TEXT, "Secondary"),
1180
       None, 0, lambda ctx, item: item["snode"]),
1181
      ], [])
1182

    
1183
    data = [
1184
      { "pnode": "node1", "snode": "node44", },
1185
      { "pnode": "node30", "snode": "node90", },
1186
      { "pnode": "node25", "snode": "node1", },
1187
      { "pnode": "node20", "snode": "node1", },
1188
      ]
1189

    
1190
    qfilter = ["|", ["=", "pnode", "node1"], ["=", "snode", "node1"]]
1191

    
1192
    q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode",
1193
                    qfilter=qfilter)
1194
    self.assertTrue(q.RequestedNames() is None)
1195
    self.assertFalse(q.RequestedData())
1196
    self.assertEqual(q.Query(data),
1197
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1198
       [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1199
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1200

    
1201
    # Try again with reversed input data
1202
    self.assertEqual(q.Query(reversed(data)),
1203
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1204
       [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1205
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1206

    
1207
    # No name field, result must be in incoming order
1208
    q = query.Query(fielddefs, ["pnode", "snode"], namefield=None,
1209
                    qfilter=qfilter)
1210
    self.assertFalse(q.RequestedData())
1211
    self.assertEqual(q.Query(data),
1212
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1213
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1214
       [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1215
    self.assertEqual(q.OldStyleQuery(data), [
1216
      ["node1", "node44"],
1217
      ["node25", "node1"],
1218
      ["node20", "node1"],
1219
      ])
1220
    self.assertEqual(q.Query(reversed(data)),
1221
      [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1222
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1223
       [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1224
    self.assertEqual(q.OldStyleQuery(reversed(data)), [
1225
      ["node20", "node1"],
1226
      ["node25", "node1"],
1227
      ["node1", "node44"],
1228
      ])
1229

    
1230
    # Name field, but no sorting, result must be in incoming order
1231
    q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode")
1232
    self.assertFalse(q.RequestedData())
1233
    self.assertEqual(q.Query(data, sort_by_name=False),
1234
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1235
       [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1236
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1237
       [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1238
    self.assertEqual(q.OldStyleQuery(data, sort_by_name=False), [
1239
      ["node1", "node44"],
1240
      ["node30", "node90"],
1241
      ["node25", "node1"],
1242
      ["node20", "node1"],
1243
      ])
1244
    self.assertEqual(q.Query(reversed(data), sort_by_name=False),
1245
      [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1246
       [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1247
       [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1248
       [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1249
    self.assertEqual(q.OldStyleQuery(reversed(data), sort_by_name=False), [
1250
      ["node20", "node1"],
1251
      ["node25", "node1"],
1252
      ["node30", "node90"],
1253
      ["node1", "node44"],
1254
      ])
1255

    
1256
  def testEqualNamesOrder(self):
1257
    fielddefs = query._PrepareFieldList([
1258
      (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1259
       None, 0, lambda ctx, item: item["pnode"]),
1260
      (query._MakeField("num", "Num", constants.QFT_NUMBER, "Num"),
1261
       None, 0, lambda ctx, item: item["num"]),
1262
      ], [])
1263

    
1264
    data = [
1265
      { "pnode": "node1", "num": 100, },
1266
      { "pnode": "node1", "num": 25, },
1267
      { "pnode": "node2", "num": 90, },
1268
      { "pnode": "node2", "num": 30, },
1269
      ]
1270

    
1271
    q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1272
                    qfilter=["|", ["=", "pnode", "node1"],
1273
                                  ["=", "pnode", "node2"],
1274
                                  ["=", "pnode", "node1"]])
1275
    self.assertEqual(q.RequestedNames(), ["node1", "node2"],
1276
                     msg="Did not return unique names")
1277
    self.assertFalse(q.RequestedData())
1278
    self.assertEqual(q.Query(data),
1279
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1280
       [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1281
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1282
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1283
    self.assertEqual(q.Query(data, sort_by_name=False),
1284
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1285
       [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1286
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1287
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1288

    
1289
    data = [
1290
      { "pnode": "nodeX", "num": 50, },
1291
      { "pnode": "nodeY", "num": 40, },
1292
      { "pnode": "nodeX", "num": 30, },
1293
      { "pnode": "nodeX", "num": 20, },
1294
      { "pnode": "nodeM", "num": 10, },
1295
      ]
1296

    
1297
    q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1298
                    qfilter=["|", ["=", "pnode", "nodeX"],
1299
                                  ["=", "pnode", "nodeY"],
1300
                                  ["=", "pnode", "nodeY"],
1301
                                  ["=", "pnode", "nodeY"],
1302
                                  ["=", "pnode", "nodeM"]])
1303
    self.assertEqual(q.RequestedNames(), ["nodeX", "nodeY", "nodeM"],
1304
                     msg="Did not return unique names")
1305
    self.assertFalse(q.RequestedData())
1306

    
1307
    # First sorted by name, then input order
1308
    self.assertEqual(q.Query(data, sort_by_name=True),
1309
      [[(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)],
1310
       [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1311
       [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1312
       [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1313
       [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)]])
1314

    
1315
    # Input order
1316
    self.assertEqual(q.Query(data, sort_by_name=False),
1317
      [[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1318
       [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)],
1319
       [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1320
       [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1321
       [(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)]])
1322

    
1323
  def testFilter(self):
1324
    (DK_A, DK_B) = range(1000, 1002)
1325

    
1326
    fielddefs = query._PrepareFieldList([
1327
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1328
       DK_A, 0, lambda ctx, item: item["name"]),
1329
      (query._MakeField("other", "Other", constants.QFT_TEXT, "Other"),
1330
       DK_B, 0, lambda ctx, item: item["other"]),
1331
      ], [])
1332

    
1333
    data = [
1334
      { "name": "node1", "other": "foo", },
1335
      { "name": "node2", "other": "bar", },
1336
      { "name": "node3", "other": "Hello", },
1337
      ]
1338

    
1339
    # Empty filter
1340
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1341
                    qfilter=["|"])
1342
    self.assertTrue(q.RequestedNames() is None)
1343
    self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1344
    self.assertEqual(q.Query(data), [])
1345

    
1346
    # Normal filter
1347
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1348
                    qfilter=["=", "name", "node1"])
1349
    self.assertEqual(q.RequestedNames(), ["node1"])
1350
    self.assertEqual(q.Query(data),
1351
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")]])
1352

    
1353
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1354
                    qfilter=(["|", ["=", "name", "node1"],
1355
                                   ["=", "name", "node3"]]))
1356
    self.assertEqual(q.RequestedNames(), ["node1", "node3"])
1357
    self.assertEqual(q.Query(data),
1358
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1359
       [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1360

    
1361
    # Complex filter
1362
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1363
                    qfilter=(["|", ["=", "name", "node1"],
1364
                                   ["|", ["=", "name", "node3"],
1365
                                         ["=", "name", "node2"]],
1366
                                   ["=", "name", "node3"]]))
1367
    self.assertEqual(q.RequestedNames(), ["node1", "node3", "node2"])
1368
    self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1369
    self.assertEqual(q.Query(data),
1370
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1371
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")],
1372
       [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1373

    
1374
    # Filter data type mismatch
1375
    for i in [-1, 0, 1, 123, [], None, True, False]:
1376
      self.assertRaises(errors.ParameterError, query.Query,
1377
                        fielddefs, ["name", "other"], namefield="name",
1378
                        qfilter=["=", "name", i])
1379

    
1380
    # Negative filter
1381
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1382
                    qfilter=["!", ["|", ["=", "name", "node1"],
1383
                                        ["=", "name", "node3"]]])
1384
    self.assertTrue(q.RequestedNames() is None)
1385
    self.assertEqual(q.Query(data),
1386
      [[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1387

    
1388
    # Not equal
1389
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1390
                    qfilter=["!=", "name", "node3"])
1391
    self.assertTrue(q.RequestedNames() is None)
1392
    self.assertEqual(q.Query(data),
1393
      [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1394
       [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1395

    
1396
    # Data type
1397
    q = query.Query(fielddefs, [], namefield="name",
1398
                    qfilter=["|", ["=", "other", "bar"],
1399
                                  ["=", "name", "foo"]])
1400
    self.assertTrue(q.RequestedNames() is None)
1401
    self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1402
    self.assertEqual(q.Query(data), [[]])
1403

    
1404
    # Only one data type
1405
    q = query.Query(fielddefs, ["other"], namefield="name",
1406
                    qfilter=["=", "other", "bar"])
1407
    self.assertTrue(q.RequestedNames() is None)
1408
    self.assertEqual(q.RequestedData(), set([DK_B]))
1409
    self.assertEqual(q.Query(data), [[(constants.RS_NORMAL, "bar")]])
1410

    
1411
    q = query.Query(fielddefs, [], namefield="name",
1412
                    qfilter=["=", "other", "bar"])
1413
    self.assertTrue(q.RequestedNames() is None)
1414
    self.assertEqual(q.RequestedData(), set([DK_B]))
1415
    self.assertEqual(q.Query(data), [[]])
1416

    
1417
  def testFilterContains(self):
1418
    fielddefs = query._PrepareFieldList([
1419
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1420
       None, 0, lambda ctx, item: item["name"]),
1421
      (query._MakeField("other", "Other", constants.QFT_OTHER, "Other"),
1422
       None, 0, lambda ctx, item: item["other"]),
1423
      ], [])
1424

    
1425
    data = [
1426
      { "name": "node2", "other": ["x", "y", "bar"], },
1427
      { "name": "node3", "other": "Hello", },
1428
      { "name": "node1", "other": ["a", "b", "foo"], },
1429
      { "name": "empty", "other": []},
1430
      ]
1431

    
1432
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1433
                    qfilter=["=[]", "other", "bar"])
1434
    self.assertTrue(q.RequestedNames() is None)
1435
    self.assertEqual(q.Query(data), [
1436
      [(constants.RS_NORMAL, "node2"),
1437
       (constants.RS_NORMAL, ["x", "y", "bar"])],
1438
      ])
1439

    
1440
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1441
                    qfilter=["|", ["=[]", "other", "bar"],
1442
                                  ["=[]", "other", "a"],
1443
                                  ["=[]", "other", "b"]])
1444
    self.assertTrue(q.RequestedNames() is None)
1445
    self.assertEqual(q.Query(data), [
1446
      [(constants.RS_NORMAL, "node1"),
1447
       (constants.RS_NORMAL, ["a", "b", "foo"])],
1448
      [(constants.RS_NORMAL, "node2"),
1449
       (constants.RS_NORMAL, ["x", "y", "bar"])],
1450
      ])
1451
    self.assertEqual(q.OldStyleQuery(data), [
1452
      ["node1", ["a", "b", "foo"]],
1453
      ["node2", ["x", "y", "bar"]],
1454
      ])
1455

    
1456
    # Boolean test
1457
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1458
                    qfilter=["?", "other"])
1459
    self.assertEqual(q.OldStyleQuery(data), [
1460
      ["node1", ["a", "b", "foo"]],
1461
      ["node2", ["x", "y", "bar"]],
1462
      ["node3", "Hello"],
1463
      ])
1464

    
1465
    q = query.Query(fielddefs, ["name", "other"], namefield="name",
1466
                    qfilter=["!", ["?", "other"]])
1467
    self.assertEqual(q.OldStyleQuery(data), [
1468
      ["empty", []],
1469
      ])
1470

    
1471
  def testFilterHostname(self):
1472
    fielddefs = query._PrepareFieldList([
1473
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1474
       None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1475
      ], [])
1476

    
1477
    data = [
1478
      { "name": "node1.example.com", },
1479
      { "name": "node2.example.com", },
1480
      { "name": "node2.example.net", },
1481
      ]
1482

    
1483
    q = query.Query(fielddefs, ["name"], namefield="name",
1484
                    qfilter=["=", "name", "node2"])
1485
    self.assertEqual(q.RequestedNames(), ["node2"])
1486
    self.assertEqual(q.Query(data), [
1487
      [(constants.RS_NORMAL, "node2.example.com")],
1488
      [(constants.RS_NORMAL, "node2.example.net")],
1489
      ])
1490

    
1491
    q = query.Query(fielddefs, ["name"], namefield="name",
1492
                    qfilter=["=", "name", "node1"])
1493
    self.assertEqual(q.RequestedNames(), ["node1"])
1494
    self.assertEqual(q.Query(data), [
1495
      [(constants.RS_NORMAL, "node1.example.com")],
1496
      ])
1497

    
1498
    q = query.Query(fielddefs, ["name"], namefield="name",
1499
                    qfilter=["=", "name", "othername"])
1500
    self.assertEqual(q.RequestedNames(), ["othername"])
1501
    self.assertEqual(q.Query(data), [])
1502

    
1503
    q = query.Query(fielddefs, ["name"], namefield="name",
1504
                    qfilter=["|", ["=", "name", "node1.example.com"],
1505
                                  ["=", "name", "node2"]])
1506
    self.assertEqual(q.RequestedNames(), ["node1.example.com", "node2"])
1507
    self.assertEqual(q.Query(data), [
1508
      [(constants.RS_NORMAL, "node1.example.com")],
1509
      [(constants.RS_NORMAL, "node2.example.com")],
1510
      [(constants.RS_NORMAL, "node2.example.net")],
1511
      ])
1512
    self.assertEqual(q.OldStyleQuery(data), [
1513
      ["node1.example.com"],
1514
      ["node2.example.com"],
1515
      ["node2.example.net"],
1516
      ])
1517

    
1518
    q = query.Query(fielddefs, ["name"], namefield="name",
1519
                    qfilter=["!=", "name", "node1"])
1520
    self.assertTrue(q.RequestedNames() is None)
1521
    self.assertEqual(q.Query(data), [
1522
      [(constants.RS_NORMAL, "node2.example.com")],
1523
      [(constants.RS_NORMAL, "node2.example.net")],
1524
      ])
1525
    self.assertEqual(q.OldStyleQuery(data), [
1526
      ["node2.example.com"],
1527
      ["node2.example.net"],
1528
      ])
1529

    
1530
  def testFilterBoolean(self):
1531
    fielddefs = query._PrepareFieldList([
1532
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1533
       None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1534
      (query._MakeField("value", "Value", constants.QFT_BOOL, "Value"),
1535
       None, 0, lambda ctx, item: item["value"]),
1536
      ], [])
1537

    
1538
    data = [
1539
      { "name": "node1", "value": False, },
1540
      { "name": "node2", "value": True, },
1541
      { "name": "node3", "value": True, },
1542
      ]
1543

    
1544
    q = query.Query(fielddefs, ["name", "value"],
1545
                    qfilter=["|", ["=", "value", False],
1546
                                  ["=", "value", True]])
1547
    self.assertTrue(q.RequestedNames() is None)
1548
    self.assertEqual(q.Query(data), [
1549
      [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1550
      [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1551
      [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1552
      ])
1553

    
1554
    q = query.Query(fielddefs, ["name", "value"],
1555
                    qfilter=["|", ["=", "value", False],
1556
                                  ["!", ["=", "value", False]]])
1557
    self.assertTrue(q.RequestedNames() is None)
1558
    self.assertEqual(q.Query(data), [
1559
      [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1560
      [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1561
      [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1562
      ])
1563

    
1564
    # Comparing bool with string
1565
    for i in ["False", "True", "0", "1", "no", "yes", "N", "Y"]:
1566
      self.assertRaises(errors.ParameterError, query.Query,
1567
                        fielddefs, ["name", "value"],
1568
                        qfilter=["=", "value", i])
1569

    
1570
    # Truth filter
1571
    q = query.Query(fielddefs, ["name", "value"], qfilter=["?", "value"])
1572
    self.assertTrue(q.RequestedNames() is None)
1573
    self.assertEqual(q.Query(data), [
1574
      [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1575
      [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1576
      ])
1577

    
1578
    # Negative bool filter
1579
    q = query.Query(fielddefs, ["name", "value"], qfilter=["!", ["?", "value"]])
1580
    self.assertTrue(q.RequestedNames() is None)
1581
    self.assertEqual(q.Query(data), [
1582
      [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1583
      ])
1584

    
1585
    # Complex truth filter
1586
    q = query.Query(fielddefs, ["name", "value"],
1587
                    qfilter=["|", ["&", ["=", "name", "node1"],
1588
                                        ["!", ["?", "value"]]],
1589
                                  ["?", "value"]])
1590
    self.assertTrue(q.RequestedNames() is None)
1591
    self.assertEqual(q.Query(data), [
1592
      [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1593
      [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1594
      [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1595
      ])
1596

    
1597
  def testFilterRegex(self):
1598
    fielddefs = query._PrepareFieldList([
1599
      (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1600
       None, 0, lambda ctx, item: item["name"]),
1601
      ], [])
1602

    
1603
    data = [
1604
      { "name": "node1.example.com", },
1605
      { "name": "node2.site.example.com", },
1606
      { "name": "node2.example.net", },
1607

    
1608
      # Empty name
1609
      { "name": "", },
1610
      ]
1611

    
1612
    q = query.Query(fielddefs, ["name"], namefield="name",
1613
                    qfilter=["=~", "name", "site"])
1614
    self.assertTrue(q.RequestedNames() is None)
1615
    self.assertEqual(q.Query(data), [
1616
      [(constants.RS_NORMAL, "node2.site.example.com")],
1617
      ])
1618

    
1619
    q = query.Query(fielddefs, ["name"], namefield="name",
1620
                    qfilter=["=~", "name", "^node2"])
1621
    self.assertTrue(q.RequestedNames() is None)
1622
    self.assertEqual(q.Query(data), [
1623
      [(constants.RS_NORMAL, "node2.example.net")],
1624
      [(constants.RS_NORMAL, "node2.site.example.com")],
1625
      ])
1626

    
1627
    q = query.Query(fielddefs, ["name"], namefield="name",
1628
                    qfilter=["=~", "name", r"(?i)\.COM$"])
1629
    self.assertTrue(q.RequestedNames() is None)
1630
    self.assertEqual(q.Query(data), [
1631
      [(constants.RS_NORMAL, "node1.example.com")],
1632
      [(constants.RS_NORMAL, "node2.site.example.com")],
1633
      ])
1634

    
1635
    q = query.Query(fielddefs, ["name"], namefield="name",
1636
                    qfilter=["=~", "name", r"."])
1637
    self.assertTrue(q.RequestedNames() is None)
1638
    self.assertEqual(q.Query(data), [
1639
      [(constants.RS_NORMAL, "node1.example.com")],
1640
      [(constants.RS_NORMAL, "node2.example.net")],
1641
      [(constants.RS_NORMAL, "node2.site.example.com")],
1642
      ])
1643

    
1644
    q = query.Query(fielddefs, ["name"], namefield="name",
1645
                    qfilter=["=~", "name", r"^$"])
1646
    self.assertTrue(q.RequestedNames() is None)
1647
    self.assertEqual(q.Query(data), [
1648
      [(constants.RS_NORMAL, "")],
1649
      ])
1650

    
1651
    # Invalid regular expression
1652
    self.assertRaises(errors.ParameterError, query.Query, fielddefs, ["name"],
1653
                      qfilter=["=~", "name", r"["])
1654

    
1655

    
1656
if __name__ == "__main__":
1657
  testutils.GanetiTestProgram()