4 # Copyright (C) 2010, 2011, 2012 Google Inc.
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.
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.
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
22 """Script for testing ganeti.query"""
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
36 import ganeti.masterd.instance as gmi
41 class TestConstants(unittest.TestCase):
43 self.assertEqual(set(query._VERIFY_FN.keys()),
48 def __init__(self, data, **kwargs):
51 for name, value in kwargs.items():
52 setattr(self, name, value)
55 return iter(self.data)
58 def _GetDiskSize(nr, ctx, item):
63 return query._FS_UNAVAIL
66 class TestQuery(unittest.TestCase):
68 (STATIC, DISK) = range(10, 12)
70 fielddef = query._PrepareFieldList([
71 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
72 STATIC, 0, lambda ctx, item: item["name"]),
73 (query._MakeField("master", "Master", constants.QFT_BOOL, "Master"),
74 STATIC, 0, lambda ctx, item: ctx.mastername == item["name"]),
76 [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
77 constants.QFT_UNIT, "Disk size %s" % i),
78 DISK, 0, compat.partial(_GetDiskSize, i))
79 for i in range(4)], [])
81 q = query.Query(fielddef, ["name"])
82 self.assertEqual(q.RequestedData(), set([STATIC]))
83 self.assertEqual(len(q._fields), 1)
84 self.assertEqual(len(q.GetFields()), 1)
85 self.assertEqual(q.GetFields()[0].ToDict(),
86 objects.QueryFieldDefinition(name="name",
88 kind=constants.QFT_TEXT,
91 # Create data only once query has been prepared
93 { "name": "node1", "disks": [0, 1, 2], },
94 { "name": "node2", "disks": [3, 4], },
95 { "name": "node3", "disks": [5, 6, 7], },
98 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
99 [[(constants.RS_NORMAL, "node1")],
100 [(constants.RS_NORMAL, "node2")],
101 [(constants.RS_NORMAL, "node3")]])
102 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node3")),
103 [["node1"], ["node2"], ["node3"]])
105 q = query.Query(fielddef, ["name", "master"])
106 self.assertEqual(q.RequestedData(), set([STATIC]))
107 self.assertEqual(len(q._fields), 2)
108 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
109 [[(constants.RS_NORMAL, "node1"),
110 (constants.RS_NORMAL, False)],
111 [(constants.RS_NORMAL, "node2"),
112 (constants.RS_NORMAL, False)],
113 [(constants.RS_NORMAL, "node3"),
114 (constants.RS_NORMAL, True)],
117 q = query.Query(fielddef, ["name", "master", "disk0.size"])
118 self.assertEqual(q.RequestedData(), set([STATIC, DISK]))
119 self.assertEqual(len(q._fields), 3)
120 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
121 [[(constants.RS_NORMAL, "node1"),
122 (constants.RS_NORMAL, False),
123 (constants.RS_NORMAL, 0)],
124 [(constants.RS_NORMAL, "node2"),
125 (constants.RS_NORMAL, True),
126 (constants.RS_NORMAL, 3)],
127 [(constants.RS_NORMAL, "node3"),
128 (constants.RS_NORMAL, False),
129 (constants.RS_NORMAL, 5)],
132 # With unknown column
133 q = query.Query(fielddef, ["disk2.size", "disk1.size", "disk99.size",
135 self.assertEqual(q.RequestedData(), set([DISK]))
136 self.assertEqual(len(q._fields), 4)
137 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
138 [[(constants.RS_NORMAL, 2),
139 (constants.RS_NORMAL, 1),
140 (constants.RS_UNKNOWN, None),
141 (constants.RS_NORMAL, 0)],
142 [(constants.RS_UNAVAIL, None),
143 (constants.RS_NORMAL, 4),
144 (constants.RS_UNKNOWN, None),
145 (constants.RS_NORMAL, 3)],
146 [(constants.RS_NORMAL, 7),
147 (constants.RS_NORMAL, 6),
148 (constants.RS_UNKNOWN, None),
149 (constants.RS_NORMAL, 5)],
151 self.assertRaises(errors.OpPrereqError, q.OldStyleQuery,
152 _QueryData(data, mastername="node2"))
153 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()], [
154 { "name": "disk2.size", "title": "DiskSize2",
155 "kind": constants.QFT_UNIT, "doc": "Disk size 2", },
156 { "name": "disk1.size", "title": "DiskSize1",
157 "kind": constants.QFT_UNIT, "doc": "Disk size 1", },
158 { "name": "disk99.size", "title": "disk99.size",
159 "kind": constants.QFT_UNKNOWN,
160 "doc": "Unknown field 'disk99.size'", },
161 { "name": "disk0.size", "title": "DiskSize0",
162 "kind": constants.QFT_UNIT, "doc": "Disk size 0", },
166 q = query.Query(fielddef, [])
167 self.assertEqual(q.RequestedData(), set([]))
168 self.assertEqual(len(q._fields), 0)
169 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
171 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node2")),
173 self.assertEqual(q.GetFields(), [])
175 def testPrepareFieldList(self):
177 for (a, b) in [("name", "name"), ("NAME", "name")]:
178 self.assertRaises(AssertionError, query._PrepareFieldList, [
179 (query._MakeField("name", b, constants.QFT_TEXT, "Name"), None, 0,
181 (query._MakeField("other", a, constants.QFT_TEXT, "Other"), None, 0,
185 # Non-lowercase names
186 self.assertRaises(AssertionError, query._PrepareFieldList, [
187 (query._MakeField("NAME", "Name", constants.QFT_TEXT, "Name"), None, 0,
190 self.assertRaises(AssertionError, query._PrepareFieldList, [
191 (query._MakeField("Name", "Name", constants.QFT_TEXT, "Name"), None, 0,
196 self.assertRaises(AssertionError, query._PrepareFieldList, [
197 (query._MakeField("", "Name", constants.QFT_TEXT, "Name"), None, 0,
202 self.assertRaises(AssertionError, query._PrepareFieldList, [
203 (query._MakeField("name", "", constants.QFT_TEXT, "Name"), None, 0,
207 # Whitespace in title
208 self.assertRaises(AssertionError, query._PrepareFieldList, [
209 (query._MakeField("name", "Co lu mn", constants.QFT_TEXT, "Name"),
210 None, 0, lambda *args: None),
213 # No callable function
214 self.assertRaises(AssertionError, query._PrepareFieldList, [
215 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
219 # Invalid documentation
220 for doc in ["", ".", "Hello world\n", "Hello\nWo\nrld", "Hello World!",
221 "HelloWorld.", "only lowercase", ",", " x y z .\t", " "]:
222 self.assertRaises(AssertionError, query._PrepareFieldList, [
223 (query._MakeField("name", "Name", constants.QFT_TEXT, doc),
224 None, 0, lambda *args: None),
227 # Duplicate field name
228 self.assertRaises(ValueError, query._PrepareFieldList, [
229 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
230 None, 0, lambda *args: None),
231 (query._MakeField("name", "Other", constants.QFT_OTHER, "Other"),
232 None, 0, lambda *args: None),
235 def testUnknown(self):
236 fielddef = query._PrepareFieldList([
237 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
238 None, 0, lambda _, item: "name%s" % item),
239 (query._MakeField("other0", "Other0", constants.QFT_TIMESTAMP, "Other"),
240 None, 0, lambda *args: 1234),
241 (query._MakeField("nodata", "NoData", constants.QFT_NUMBER, "No data"),
242 None, 0, lambda *args: query._FS_NODATA ),
243 (query._MakeField("unavail", "Unavail", constants.QFT_BOOL, "Unavail"),
244 None, 0, lambda *args: query._FS_UNAVAIL),
247 for selected in [["foo"], ["Hello", "World"],
248 ["name1", "other", "foo"]]:
249 q = query.Query(fielddef, selected)
250 self.assertEqual(len(q._fields), len(selected))
251 self.assert_(compat.all(len(row) == len(selected)
252 for row in q.Query(_QueryData(range(1, 10)))))
253 self.assertEqual(q.Query(_QueryData(range(1, 10))),
254 [[(constants.RS_UNKNOWN, None)] * len(selected)
255 for i in range(1, 10)])
256 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()],
257 [{ "name": name, "title": name,
258 "kind": constants.QFT_UNKNOWN,
259 "doc": "Unknown field '%s'" % name}
260 for name in selected])
262 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail"])
263 self.assertEqual(len(q._fields), 4)
264 self.assertEqual(q.OldStyleQuery(_QueryData(range(1, 10))), [
265 ["name%s" % i, 1234, None, None]
266 for i in range(1, 10)
269 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail", "unk"])
270 self.assertEqual(len(q._fields), 5)
271 self.assertEqual(q.Query(_QueryData(range(1, 10))),
272 [[(constants.RS_NORMAL, "name%s" % i),
273 (constants.RS_NORMAL, 1234),
274 (constants.RS_NODATA, None),
275 (constants.RS_UNAVAIL, None),
276 (constants.RS_UNKNOWN, None)]
277 for i in range(1, 10)])
279 def testAliases(self):
281 (query._MakeField("a", "a-title", constants.QFT_TEXT, "Field A"),
282 None, 0, lambda *args: None),
283 (query._MakeField("b", "b-title", constants.QFT_TEXT, "Field B"),
284 None, 0, lambda *args: None),
287 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
289 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
290 [("c", "b"), ("c", "a")])
292 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
294 fdefs = query._PrepareFieldList(fields, [("c", "b")])
295 self.assertEqual(len(fdefs), 3)
296 self.assertEqual(fdefs["b"][1:], fdefs["c"][1:])
299 class TestGetNodeRole(unittest.TestCase):
304 (constants.NR_MASTER, "node1", objects.Node(name="node1")),
305 (constants.NR_MCANDIDATE, "master",
306 objects.Node(name="node1", master_candidate=True)),
307 (constants.NR_REGULAR, "master", objects.Node(name="node1")),
308 (constants.NR_DRAINED, "master",
309 objects.Node(name="node1", drained=True)),
310 (constants.NR_OFFLINE,
311 "master", objects.Node(name="node1", offline=True)),
314 for (role, master_name, node) in checks:
315 result = query._GetNodeRole(node, master_name)
316 self.assertEqual(result, role)
317 tested_role.add(result)
319 self.assertEqual(tested_role, constants.NR_ALL)
322 class TestNodeQuery(unittest.TestCase):
323 def _Create(self, selected):
324 return query.Query(query.NODE_FIELDS, selected)
326 def testSimple(self):
327 cluster = objects.Cluster(cluster_name="testcluster",
328 ndparams=constants.NDC_DEFAULTS.copy())
329 grp1 = objects.NodeGroup(name="default",
330 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
331 alloc_policy=constants.ALLOC_POLICY_PREFERRED,
332 ipolicy=objects.MakeEmptyIPolicy(),
335 grp2 = objects.NodeGroup(name="group2",
336 uuid="c0e89160-18e7-11e0-a46e-001d0904babe",
337 alloc_policy=constants.ALLOC_POLICY_PREFERRED,
338 ipolicy=objects.MakeEmptyIPolicy(),
339 ndparams={constants.ND_SPINDLE_COUNT: 2},
341 groups = {grp1.uuid: grp1, grp2.uuid: grp2}
343 objects.Node(name="node1", drained=False, group=grp1.uuid, ndparams={}),
344 objects.Node(name="node2", drained=True, group=grp2.uuid, ndparams={}),
345 objects.Node(name="node3", drained=False, group=grp1.uuid,
346 ndparams={constants.ND_SPINDLE_COUNT: 4}),
348 for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]:
349 nqd = query.NodeQueryData(nodes, live_data, None, None, None,
350 groups, None, cluster)
352 q = self._Create(["name", "drained"])
353 self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG]))
354 self.assertEqual(q.Query(nqd),
355 [[(constants.RS_NORMAL, "node1"),
356 (constants.RS_NORMAL, False)],
357 [(constants.RS_NORMAL, "node2"),
358 (constants.RS_NORMAL, True)],
359 [(constants.RS_NORMAL, "node3"),
360 (constants.RS_NORMAL, False)],
362 self.assertEqual(q.OldStyleQuery(nqd),
366 q = self._Create(["ndp/spindle_count"])
367 self.assertEqual(q.RequestedData(), set([query.NQ_GROUP]))
368 self.assertEqual(q.Query(nqd),
369 [[(constants.RS_NORMAL,
370 constants.NDC_DEFAULTS[constants.ND_SPINDLE_COUNT])],
371 [(constants.RS_NORMAL,
372 grp2.ndparams[constants.ND_SPINDLE_COUNT])],
373 [(constants.RS_NORMAL,
374 nodes[2].ndparams[constants.ND_SPINDLE_COUNT])],
378 selected = query.NODE_FIELDS.keys()
379 field_index = dict((field, idx) for idx, field in enumerate(selected))
381 q = self._Create(selected)
382 self.assertEqual(q.RequestedData(),
383 set([query.NQ_CONFIG, query.NQ_LIVE, query.NQ_INST,
384 query.NQ_GROUP, query.NQ_OOB]))
386 cluster = objects.Cluster(cluster_name="testcluster",
387 hvparams=constants.HVC_DEFAULTS,
389 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
392 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
394 ndparams=constants.NDC_DEFAULTS,
397 node_names = ["node%s" % i for i in range(20)]
398 master_name = node_names[3]
400 objects.Node(name=name,
401 primary_ip="192.0.2.%s" % idx,
402 secondary_ip="192.0.100.%s" % idx,
403 serial_no=7789 * idx,
404 master_candidate=(name != master_name and idx % 3 == 0),
409 master_capable=False,
414 uuid="fd9ccebe-6339-43c9-a82e-94bbe575%04d" % idx)
415 for idx, name in enumerate(node_names)
418 master_node = nodes[3]
419 master_node.AddTag("masternode")
420 master_node.AddTag("another")
421 master_node.AddTag("tag")
422 master_node.ctime = None
423 master_node.mtime = None
424 assert master_node.name == master_name
426 live_data_name = node_names[4]
427 assert live_data_name != master_name
430 "bootid": "a2504766-498e-4b25-b21e-d23098dc3af4",
437 "dfree": 5 * 1024 * 1024,
438 "dtotal": 100 * 1024 * 1024,
441 assert (sorted(query._NODE_LIVE_FIELDS.keys()) ==
442 sorted(fake_live_data.keys()))
444 live_data = dict.fromkeys(node_names, {})
445 live_data[live_data_name] = \
446 dict((query._NODE_LIVE_FIELDS[name][2], value)
447 for name, value in fake_live_data.items())
449 node_to_primary = dict((name, set()) for name in node_names)
450 node_to_primary[master_name].update(["inst1", "inst2"])
452 node_to_secondary = dict((name, set()) for name in node_names)
453 node_to_secondary[live_data_name].update(["instX", "instY", "instZ"])
455 ng_uuid = "492b4b74-8670-478a-b98d-4c53a76238e6"
457 ng_uuid: objects.NodeGroup(name="ng1", uuid=ng_uuid, ndparams={}),
460 oob_not_powered_node = node_names[0]
461 nodes[0].powered = False
462 oob_support = dict((name, False) for name in node_names)
463 oob_support[master_name] = True
464 oob_support[oob_not_powered_node] = True
466 master_node.group = ng_uuid
468 nqd = query.NodeQueryData(nodes, live_data, master_name,
469 node_to_primary, node_to_secondary, groups,
470 oob_support, cluster)
471 result = q.Query(nqd)
472 self.assert_(compat.all(len(row) == len(selected) for row in result))
473 self.assertEqual([row[field_index["name"]] for row in result],
474 [(constants.RS_NORMAL, name) for name in node_names])
476 node_to_row = dict((row[field_index["name"]][1], idx)
477 for idx, row in enumerate(result))
479 master_row = result[node_to_row[master_name]]
480 self.assert_(master_row[field_index["master"]])
481 self.assert_(master_row[field_index["role"]], "M")
482 self.assertEqual(master_row[field_index["group"]],
483 (constants.RS_NORMAL, "ng1"))
484 self.assertEqual(master_row[field_index["group.uuid"]],
485 (constants.RS_NORMAL, ng_uuid))
486 self.assertEqual(master_row[field_index["ctime"]],
487 (constants.RS_UNAVAIL, None))
488 self.assertEqual(master_row[field_index["mtime"]],
489 (constants.RS_UNAVAIL, None))
491 self.assert_(row[field_index["pip"]] == node.primary_ip and
492 row[field_index["sip"]] == node.secondary_ip and
493 set(row[field_index["tags"]]) == node.GetTags() and
494 row[field_index["serial_no"]] == node.serial_no and
495 row[field_index["role"]] == query._GetNodeRole(node,
497 (node.name == master_name or
498 (row[field_index["group"]] == "<unknown>" and
499 row[field_index["group.uuid"]] is None and
500 row[field_index["ctime"]] == (constants.RS_NORMAL,
502 row[field_index["mtime"]] == (constants.RS_NORMAL,
504 row[field_index["powered"]] == (constants.RS_NORMAL,
506 (node.name == oob_not_powered_node and
507 row[field_index["powered"]] == (constants.RS_NORMAL,
509 row[field_index["powered"]] == (constants.RS_UNAVAIL, None)
510 for row, node in zip(result, nodes))
512 live_data_row = result[node_to_row[live_data_name]]
514 for (field, value) in fake_live_data.items():
515 self.assertEqual(live_data_row[field_index[field]],
516 (constants.RS_NORMAL, value))
518 self.assertEqual(master_row[field_index["pinst_cnt"]],
519 (constants.RS_NORMAL, 2))
520 self.assertEqual(live_data_row[field_index["sinst_cnt"]],
521 (constants.RS_NORMAL, 3))
522 self.assertEqual(master_row[field_index["pinst_list"]],
523 (constants.RS_NORMAL,
524 list(node_to_primary[master_name])))
525 self.assertEqual(live_data_row[field_index["sinst_list"]],
526 (constants.RS_NORMAL,
527 list(node_to_secondary[live_data_name])))
529 def testGetLiveNodeField(self):
531 objects.Node(name="node1", drained=False, offline=False,
533 objects.Node(name="node2", drained=True, offline=False,
535 objects.Node(name="node3", drained=False, offline=False,
537 objects.Node(name="node4", drained=False, offline=True,
539 objects.Node(name="node5", drained=False, offline=False,
542 live_data = dict.fromkeys([node.name for node in nodes], {})
545 nqd = query.NodeQueryData(None, None, None, None, None, None, None, None)
546 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
551 ctx = _QueryData(None, curlive_data={
555 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
559 # Wrong format/datatype
560 ctx = _QueryData(None, curlive_data={
561 "hello": ["Hello World"],
564 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
569 assert nodes[3].offline
570 ctx = _QueryData(None, curlive_data={})
571 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
573 query._FS_OFFLINE, None)
576 ctx = _QueryData(None, curlive_data={"hello": 123})
577 self.assertRaises(AssertionError, query._GetLiveNodeField,
578 "hello", constants.QFT_BOOL, ctx, nodes[0])
580 # Non-vm_capable node
581 assert not nodes[4].vm_capable
582 ctx = _QueryData(None, curlive_data={})
583 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
585 query._FS_UNAVAIL, None)
588 class TestInstanceQuery(unittest.TestCase):
589 def _Create(self, selected):
590 return query.Query(query.INSTANCE_FIELDS, selected)
592 def testSimple(self):
593 q = self._Create(["name", "be/maxmem", "ip"])
594 self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
596 cluster = objects.Cluster(cluster_name="testcluster",
597 hvparams=constants.HVC_DEFAULTS,
599 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
602 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
608 objects.Instance(name="inst1", hvparams={}, beparams={}, osparams={},
610 objects.Instance(name="inst2", hvparams={}, nics=[], osparams={},
613 constants.BE_MAXMEM: 512,
615 objects.Instance(name="inst3", hvparams={}, beparams={}, osparams={},
616 os="dos", nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
619 iqd = query.InstanceQueryData(instances, cluster, None, [], [], {},
620 set(), {}, None, None)
621 self.assertEqual(q.Query(iqd),
622 [[(constants.RS_NORMAL, "inst1"),
623 (constants.RS_NORMAL, 128),
624 (constants.RS_UNAVAIL, None),
626 [(constants.RS_NORMAL, "inst2"),
627 (constants.RS_NORMAL, 512),
628 (constants.RS_UNAVAIL, None),
630 [(constants.RS_NORMAL, "inst3"),
631 (constants.RS_NORMAL, 128),
632 (constants.RS_NORMAL, "192.0.2.99"),
634 self.assertEqual(q.OldStyleQuery(iqd),
635 [["inst1", 128, None],
636 ["inst2", 512, None],
637 ["inst3", 128, "192.0.2.99"]])
640 selected = query.INSTANCE_FIELDS.keys()
641 fieldidx = dict((field, idx) for idx, field in enumerate(selected))
643 macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
646 q = self._Create(selected)
647 self.assertEqual(q.RequestedData(),
648 set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE,
649 query.IQ_CONSOLE, query.IQ_NODES]))
651 cluster = objects.Cluster(cluster_name="testcluster",
652 hvparams=constants.HVC_DEFAULTS,
654 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
657 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
660 tcpudp_port_pool=set(),
663 "clean_install": "yes",
667 offline_nodes = ["nodeoff1", "nodeoff2"]
668 bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
669 nodes = ["node%s" % i for i in range(10)] + bad_nodes
672 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
673 uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
674 ctime=1291244000, mtime=1291244400, serial_no=30,
675 admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_PVM,
677 primary_node="node1",
678 disk_template=constants.DT_PLAIN,
681 objects.Instance(name="inst2", hvparams={}, nics=[],
682 uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
683 ctime=1291211000, mtime=1291211077, serial_no=1,
684 admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_HVM,
686 primary_node="node5",
687 disk_template=constants.DT_DISKLESS,
690 constants.BE_MAXMEM: 512,
691 constants.BE_MINMEM: 256,
694 objects.Instance(name="inst3", hvparams={}, beparams={},
695 uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
696 ctime=1291011000, mtime=1291013000, serial_no=1923,
697 admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_KVM,
699 primary_node="node6",
700 disk_template=constants.DT_DRBD8,
703 objects.NIC(ip="192.0.2.99", mac=macs.pop(),
705 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
707 objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
710 objects.Instance(name="inst4", hvparams={}, beparams={},
711 uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
712 ctime=1291244390, mtime=1291244395, serial_no=25,
713 admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_PVM,
715 primary_node="nodeoff2",
716 disk_template=constants.DT_DRBD8,
719 objects.NIC(ip="192.0.2.1", mac=macs.pop(),
721 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
723 objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
724 objects.NIC(ip="192.0.2.3", mac=macs.pop(),
726 constants.NIC_MODE: constants.NIC_MODE_ROUTED,
728 objects.NIC(ip="192.0.2.4", mac=macs.pop(),
730 constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
731 constants.NIC_LINK: "eth123",
735 objects.Instance(name="inst5", hvparams={}, nics=[],
736 uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
737 ctime=1231211000, mtime=1261200000, serial_no=3,
738 admin_state=constants.ADMINST_UP, hypervisor=constants.HT_XEN_HVM,
740 primary_node="nodebad2",
741 disk_template=constants.DT_DISKLESS,
744 constants.BE_MAXMEM: 512,
745 constants.BE_MINMEM: 512,
748 objects.Instance(name="inst6", hvparams={}, nics=[],
749 uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
750 ctime=7513, mtime=11501, serial_no=13390,
751 admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_HVM,
753 primary_node="node7",
754 disk_template=constants.DT_DISKLESS,
757 constants.BE_MAXMEM: 768,
758 constants.BE_MINMEM: 256,
761 "clean_install": "no",
763 objects.Instance(name="inst7", hvparams={}, nics=[],
764 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
765 ctime=None, mtime=None, serial_no=1947,
766 admin_state=constants.ADMINST_DOWN, hypervisor=constants.HT_XEN_HVM,
768 primary_node="node6",
769 disk_template=constants.DT_DISKLESS,
773 objects.Instance(name="inst8", hvparams={}, nics=[],
774 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920f",
775 ctime=None, mtime=None, serial_no=19478,
776 admin_state=constants.ADMINST_OFFLINE, hypervisor=constants.HT_XEN_HVM,
778 primary_node="node6",
779 disk_template=constants.DT_DISKLESS,
785 assert not utils.FindDuplicates(inst.name for inst in instances)
787 instbyname = dict((inst.name, inst) for inst in instances)
789 disk_usage = dict((inst.name,
790 gmi.ComputeDiskSize(inst.disk_template,
792 for disk in inst.disks]))
793 for inst in instances)
796 "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
797 "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
815 wrongnode_inst = set(["inst7"])
817 consinfo = dict((inst.name, None) for inst in instances)
818 consinfo["inst7"] = \
819 objects.InstanceConsole(instance="inst7", kind=constants.CONS_SSH,
820 host=instbyname["inst7"].primary_node,
821 user=constants.GANETI_RUNAS,
822 command=["hostname"]).ToDict()
824 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
825 offline_nodes, bad_nodes, live_data,
826 wrongnode_inst, consinfo, {}, {})
827 result = q.Query(iqd)
828 self.assertEqual(len(result), len(instances))
829 self.assert_(compat.all(len(row) == len(selected)
832 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
833 "Offline nodes not included in bad nodes"
835 tested_status = set()
837 for (inst, row) in zip(instances, result):
838 assert inst.primary_node in nodes
840 self.assertEqual(row[fieldidx["name"]],
841 (constants.RS_NORMAL, inst.name))
843 if inst.primary_node in offline_nodes:
844 exp_status = constants.INSTST_NODEOFFLINE
845 elif inst.primary_node in bad_nodes:
846 exp_status = constants.INSTST_NODEDOWN
847 elif inst.name in live_data:
848 if inst.name in wrongnode_inst:
849 exp_status = constants.INSTST_WRONGNODE
850 elif inst.admin_state == constants.ADMINST_UP:
851 exp_status = constants.INSTST_RUNNING
853 exp_status = constants.INSTST_ERRORUP
854 elif inst.admin_state == constants.ADMINST_UP:
855 exp_status = constants.INSTST_ERRORDOWN
856 elif inst.admin_state == constants.ADMINST_DOWN:
857 exp_status = constants.INSTST_ADMINDOWN
859 exp_status = constants.INSTST_ADMINOFFLINE
861 self.assertEqual(row[fieldidx["status"]],
862 (constants.RS_NORMAL, exp_status))
864 (_, status) = row[fieldidx["status"]]
865 tested_status.add(status)
867 #FIXME(dynmem): check oper_ram vs min/max mem
868 for (field, livefield) in [("oper_vcpus", "vcpus")]:
869 if inst.primary_node in bad_nodes:
870 exp = (constants.RS_NODATA, None)
871 elif inst.name in live_data:
872 value = live_data[inst.name].get(livefield, None)
874 exp = (constants.RS_UNAVAIL, None)
876 exp = (constants.RS_NORMAL, value)
878 exp = (constants.RS_UNAVAIL, None)
880 self.assertEqual(row[fieldidx[field]], exp)
882 bridges = inst_bridges.get(inst.name, [])
883 self.assertEqual(row[fieldidx["nic.bridges"]],
884 (constants.RS_NORMAL, bridges))
886 self.assertEqual(row[fieldidx["bridge"]],
887 (constants.RS_NORMAL, bridges[0]))
889 self.assertEqual(row[fieldidx["bridge"]],
890 (constants.RS_UNAVAIL, None))
892 for i in range(constants.MAX_NICS):
893 if i < len(bridges) and bridges[i] is not None:
894 exp = (constants.RS_NORMAL, bridges[i])
896 exp = (constants.RS_UNAVAIL, None)
897 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
899 if inst.primary_node in bad_nodes:
900 exp = (constants.RS_NODATA, None)
902 exp = (constants.RS_NORMAL, inst.name in live_data)
903 self.assertEqual(row[fieldidx["oper_state"]], exp)
905 cust_exp = (constants.RS_NORMAL, {})
906 if inst.os == "deb99":
907 if inst.name == "inst6":
908 exp = (constants.RS_NORMAL, {"clean_install": "no"})
911 exp = (constants.RS_NORMAL, {"clean_install": "yes"})
913 exp = (constants.RS_NORMAL, {})
914 self.assertEqual(row[fieldidx["osparams"]], exp)
915 self.assertEqual(row[fieldidx["custom_osparams"]], cust_exp)
917 usage = disk_usage[inst.name]
920 self.assertEqual(row[fieldidx["disk_usage"]],
921 (constants.RS_NORMAL, usage))
923 for alias, target in [("sda_size", "disk.size/0"),
924 ("sdb_size", "disk.size/1"),
925 ("vcpus", "be/vcpus"),
927 ("mac", "nic.mac/0"),
928 ("bridge", "nic.bridge/0"),
929 ("nic_mode", "nic.mode/0"),
930 ("nic_link", "nic.link/0"),
932 self.assertEqual(row[fieldidx[alias]], row[fieldidx[target]])
934 for field in ["ctime", "mtime"]:
935 if getattr(inst, field) is None:
937 exp = (constants.RS_UNAVAIL, None)
939 exp = (constants.RS_NORMAL, getattr(inst, field))
940 self.assertEqual(row[fieldidx[field]], exp)
942 self._CheckInstanceConsole(inst, row[fieldidx["console"]])
944 # Ensure all possible status' have been tested
945 self.assertEqual(tested_status, constants.INSTST_ALL)
947 def _CheckInstanceConsole(self, instance, (status, consdata)):
948 if instance.name == "inst7":
949 self.assertEqual(status, constants.RS_NORMAL)
950 console = objects.InstanceConsole.FromDict(consdata)
951 self.assertTrue(console.Validate())
952 self.assertEqual(console.host, instance.primary_node)
954 self.assertEqual(status, constants.RS_UNAVAIL)
957 class TestGroupQuery(unittest.TestCase):
960 self.custom_diskparams = {
961 constants.DT_DRBD8: {
962 constants.DRBD_DEFAULT_METAVG: "foobar",
967 objects.NodeGroup(name="default",
968 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
969 alloc_policy=constants.ALLOC_POLICY_PREFERRED,
970 ipolicy=objects.MakeEmptyIPolicy(),
974 objects.NodeGroup(name="restricted",
975 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
976 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT,
977 ipolicy=objects.MakeEmptyIPolicy(),
979 diskparams=self.custom_diskparams,
982 self.cluster = objects.Cluster(cluster_name="testcluster",
983 hvparams=constants.HVC_DEFAULTS,
985 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
988 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
990 ndparams=constants.NDC_DEFAULTS,
991 ipolicy=constants.IPOLICY_DEFAULTS,
992 diskparams=constants.DISK_DT_DEFAULTS,
995 def _Create(self, selected):
996 return query.Query(query.GROUP_FIELDS, selected)
998 def testSimple(self):
999 q = self._Create(["name", "uuid", "alloc_policy"])
1000 gqd = query.GroupQueryData(self.cluster, self.groups, None, None, False)
1002 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
1004 self.assertEqual(q.Query(gqd),
1005 [[(constants.RS_NORMAL, "default"),
1006 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
1007 (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
1009 [(constants.RS_NORMAL, "restricted"),
1010 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
1011 (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
1015 def testNodes(self):
1017 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
1018 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
1021 q = self._Create(["name", "node_cnt", "node_list"])
1022 gqd = query.GroupQueryData(self.cluster, self.groups, groups_to_nodes, None,
1025 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
1027 self.assertEqual(q.Query(gqd),
1028 [[(constants.RS_NORMAL, "default"),
1029 (constants.RS_NORMAL, 2),
1030 (constants.RS_NORMAL, ["node1", "node2"]),
1032 [(constants.RS_NORMAL, "restricted"),
1033 (constants.RS_NORMAL, 3),
1034 (constants.RS_NORMAL, ["node1", "node9", "node10"]),
1038 def testInstances(self):
1039 groups_to_instances = {
1040 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
1041 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
1044 q = self._Create(["pinst_cnt", "pinst_list"])
1045 gqd = query.GroupQueryData(self.cluster, self.groups, None,
1046 groups_to_instances, False)
1048 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
1050 self.assertEqual(q.Query(gqd),
1051 [[(constants.RS_NORMAL, 2),
1052 (constants.RS_NORMAL, ["inst1", "inst2"]),
1054 [(constants.RS_NORMAL, 3),
1055 (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
1059 def testDiskparams(self):
1060 q = self._Create(["name", "uuid", "diskparams", "custom_diskparams"])
1061 gqd = query.GroupQueryData(self.cluster, self.groups, None, None, True)
1063 self.assertEqual(q.RequestedData(),
1064 set([query.GQ_CONFIG, query.GQ_DISKPARAMS]))
1066 self.assertEqual(q.Query(gqd),
1067 [[(constants.RS_NORMAL, "default"),
1068 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
1069 (constants.RS_NORMAL, constants.DISK_DT_DEFAULTS),
1070 (constants.RS_NORMAL, {}),
1072 [(constants.RS_NORMAL, "restricted"),
1073 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
1074 (constants.RS_NORMAL, objects.FillDiskParams(constants.DISK_DT_DEFAULTS,
1075 self.custom_diskparams)),
1076 (constants.RS_NORMAL, self.custom_diskparams),
1081 class TestOsQuery(unittest.TestCase):
1082 def _Create(self, selected):
1083 return query.Query(query.OS_FIELDS, selected)
1086 variants = ["v00", "plain", "v3", "var0", "v33", "v20"]
1087 api_versions = [10, 0, 15, 5]
1088 parameters = ["zpar3", "apar9"]
1090 assert variants != sorted(variants) and variants != utils.NiceSort(variants)
1091 assert (api_versions != sorted(api_versions) and
1092 api_versions != utils.NiceSort(variants))
1093 assert (parameters != sorted(parameters) and
1094 parameters != utils.NiceSort(parameters))
1097 query.OsInfo(name="debian", valid=False, hidden=False, blacklisted=False,
1098 variants=set(), api_versions=set(), parameters=set(),
1099 node_status={ "some": "status", }),
1100 query.OsInfo(name="dos", valid=True, hidden=False, blacklisted=True,
1101 variants=set(variants),
1102 api_versions=set(api_versions),
1103 parameters=set(parameters),
1104 node_status={ "some": "other", "status": None, }),
1108 q = self._Create(["name", "valid", "hidden", "blacklisted", "variants",
1109 "api_versions", "parameters", "node_status"])
1110 self.assertEqual(q.RequestedData(), set([]))
1111 self.assertEqual(q.Query(data),
1112 [[(constants.RS_NORMAL, "debian"),
1113 (constants.RS_NORMAL, False),
1114 (constants.RS_NORMAL, False),
1115 (constants.RS_NORMAL, False),
1116 (constants.RS_NORMAL, []),
1117 (constants.RS_NORMAL, []),
1118 (constants.RS_NORMAL, []),
1119 (constants.RS_NORMAL, {"some": "status"})],
1120 [(constants.RS_NORMAL, "dos"),
1121 (constants.RS_NORMAL, True),
1122 (constants.RS_NORMAL, False),
1123 (constants.RS_NORMAL, True),
1124 (constants.RS_NORMAL,
1125 ["plain", "v00", "v3", "v20", "v33", "var0"]),
1126 (constants.RS_NORMAL, [0, 5, 10, 15]),
1127 (constants.RS_NORMAL, ["apar9", "zpar3"]),
1128 (constants.RS_NORMAL,
1129 { "some": "other", "status": None, })
1133 class TestQueryFields(unittest.TestCase):
1134 def testAllFields(self):
1135 for fielddefs in query.ALL_FIELD_LISTS:
1136 result = query.QueryFields(fielddefs, None)
1137 self.assert_(isinstance(result, dict))
1138 response = objects.QueryFieldsResponse.FromDict(result)
1139 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1140 [(fdef2.name, fdef2.title)
1141 for (fdef2, _, _, _) in utils.NiceSort(fielddefs.values(),
1142 key=lambda x: x[0].name)])
1144 def testSomeFields(self):
1145 rnd = random.Random(5357)
1148 for fielddefs in query.ALL_FIELD_LISTS:
1149 if len(fielddefs) > 20:
1150 sample_size = rnd.randint(5, 20)
1152 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
1153 fields = [fdef for (fdef, _, _, _) in rnd.sample(fielddefs.values(),
1155 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
1156 self.assert_(isinstance(result, dict))
1157 response = objects.QueryFieldsResponse.FromDict(result)
1158 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1159 [(fdef2.name, fdef2.title) for fdef2 in fields])
1162 class TestQueryFilter(unittest.TestCase):
1163 def testRequestedNames(self):
1164 for (what, fielddefs) in query.ALL_FIELDS.items():
1165 if what == constants.QR_JOB:
1169 genval = lambda i: i * 10
1170 randvals = [17361, 22015, 13193, 15215]
1174 genval = lambda i: "x%s" % i
1175 randvals = ["x17361", "x22015", "x13193", "x15215"]
1176 if what == constants.QR_EXPORT:
1177 namefield = "export"
1181 assert namefield in fielddefs
1183 reqnames = [genval(i) for i in range(4)]
1184 innerfilter = [["=", namefield, v] for v in reqnames]
1187 q = query.Query(fielddefs, [namefield],
1188 qfilter=["=", namefield, nameval], namefield=None)
1189 self.assertEqual(q.RequestedNames(), None)
1192 q = query.Query(fielddefs, [namefield], qfilter=None, namefield=namefield)
1193 self.assertEqual(q.RequestedNames(), None)
1196 q = query.Query(fielddefs, [namefield], qfilter=["|"],
1197 namefield=namefield)
1198 self.assertEqual(q.RequestedNames(), None)
1201 q = query.Query(fielddefs, [namefield], qfilter=["|"] + innerfilter,
1202 namefield=namefield)
1203 self.assertEqual(q.RequestedNames(), reqnames)
1205 # Check reverse order
1206 q = query.Query(fielddefs, [namefield],
1207 qfilter=["|"] + list(reversed(innerfilter)),
1208 namefield=namefield)
1209 self.assertEqual(q.RequestedNames(), list(reversed(reqnames)))
1212 q = query.Query(fielddefs, [namefield],
1213 qfilter=["|"] + innerfilter + list(reversed(innerfilter)),
1214 namefield=namefield)
1215 self.assertEqual(q.RequestedNames(), reqnames)
1217 # Unknown name field
1218 self.assertRaises(AssertionError, query.Query, fielddefs, [namefield],
1219 namefield="_unknown_field_")
1222 q = query.Query(fielddefs, [namefield],
1223 qfilter=["|", ["=", namefield, nameval],
1224 ["&", ["=", namefield, namevalempty]]],
1225 namefield=namefield)
1226 self.assertTrue(q.RequestedNames() is None)
1229 q = query.Query(fielddefs, [namefield],
1230 qfilter=["|", ["=", namefield, nameval],
1231 ["!", ["=", namefield, namevalempty]]],
1232 namefield=namefield)
1233 self.assertTrue(q.RequestedNames() is None)
1235 # Filter with only OR (names must be in correct order)
1236 q = query.Query(fielddefs, [namefield],
1237 qfilter=["|", ["=", namefield, randvals[0]],
1238 ["|", ["=", namefield, randvals[1]]],
1239 ["|", ["|", ["=", namefield, randvals[2]]]],
1240 ["=", namefield, randvals[3]]],
1241 namefield=namefield)
1242 self.assertEqual(q.RequestedNames(), randvals)
1245 def _GenNestedFilter(namefield, op, depth, nameval):
1246 nested = ["=", namefield, nameval]
1247 for i in range(depth):
1248 nested = [op, nested]
1251 def testCompileFilter(self):
1252 levels_max = query._FilterCompilerHelper._LEVELS_MAX
1254 for (what, fielddefs) in query.ALL_FIELDS.items():
1255 if what == constants.QR_JOB:
1258 elif what == constants.QR_EXPORT:
1259 namefield = "export"
1266 [], ["="], ["=", "foo"], ["unknownop"], ["!"],
1267 ["=", "_unknown_field", "value"],
1268 self._GenNestedFilter(namefield, "|", levels_max, nameval),
1269 self._GenNestedFilter(namefield, "|", levels_max * 3, nameval),
1270 self._GenNestedFilter(namefield, "!", levels_max, nameval),
1273 for qfilter in checks:
1274 self.assertRaises(errors.ParameterError, query._CompileFilter,
1275 fielddefs, None, qfilter)
1277 for op in ["|", "!"]:
1278 qfilter = self._GenNestedFilter(namefield, op, levels_max - 1, nameval)
1279 self.assertTrue(callable(query._CompileFilter(fielddefs, None,
1282 def testQueryInputOrder(self):
1283 fielddefs = query._PrepareFieldList([
1284 (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1285 None, 0, lambda ctx, item: item["pnode"]),
1286 (query._MakeField("snode", "SNode", constants.QFT_TEXT, "Secondary"),
1287 None, 0, lambda ctx, item: item["snode"]),
1291 { "pnode": "node1", "snode": "node44", },
1292 { "pnode": "node30", "snode": "node90", },
1293 { "pnode": "node25", "snode": "node1", },
1294 { "pnode": "node20", "snode": "node1", },
1297 qfilter = ["|", ["=", "pnode", "node1"], ["=", "snode", "node1"]]
1299 q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode",
1301 self.assertTrue(q.RequestedNames() is None)
1302 self.assertFalse(q.RequestedData())
1303 self.assertEqual(q.Query(data),
1304 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1305 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1306 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1308 # Try again with reversed input data
1309 self.assertEqual(q.Query(reversed(data)),
1310 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1311 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1312 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1314 # No name field, result must be in incoming order
1315 q = query.Query(fielddefs, ["pnode", "snode"], namefield=None,
1317 self.assertFalse(q.RequestedData())
1318 self.assertEqual(q.Query(data),
1319 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1320 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1321 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1322 self.assertEqual(q.OldStyleQuery(data), [
1323 ["node1", "node44"],
1324 ["node25", "node1"],
1325 ["node20", "node1"],
1327 self.assertEqual(q.Query(reversed(data)),
1328 [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1329 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1330 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1331 self.assertEqual(q.OldStyleQuery(reversed(data)), [
1332 ["node20", "node1"],
1333 ["node25", "node1"],
1334 ["node1", "node44"],
1337 # Name field, but no sorting, result must be in incoming order
1338 q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode")
1339 self.assertFalse(q.RequestedData())
1340 self.assertEqual(q.Query(data, sort_by_name=False),
1341 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1342 [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1343 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1344 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1345 self.assertEqual(q.OldStyleQuery(data, sort_by_name=False), [
1346 ["node1", "node44"],
1347 ["node30", "node90"],
1348 ["node25", "node1"],
1349 ["node20", "node1"],
1351 self.assertEqual(q.Query(reversed(data), sort_by_name=False),
1352 [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1353 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1354 [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1355 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1356 self.assertEqual(q.OldStyleQuery(reversed(data), sort_by_name=False), [
1357 ["node20", "node1"],
1358 ["node25", "node1"],
1359 ["node30", "node90"],
1360 ["node1", "node44"],
1363 def testEqualNamesOrder(self):
1364 fielddefs = query._PrepareFieldList([
1365 (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1366 None, 0, lambda ctx, item: item["pnode"]),
1367 (query._MakeField("num", "Num", constants.QFT_NUMBER, "Num"),
1368 None, 0, lambda ctx, item: item["num"]),
1372 { "pnode": "node1", "num": 100, },
1373 { "pnode": "node1", "num": 25, },
1374 { "pnode": "node2", "num": 90, },
1375 { "pnode": "node2", "num": 30, },
1378 q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1379 qfilter=["|", ["=", "pnode", "node1"],
1380 ["=", "pnode", "node2"],
1381 ["=", "pnode", "node1"]])
1382 self.assertEqual(q.RequestedNames(), ["node1", "node2"],
1383 msg="Did not return unique names")
1384 self.assertFalse(q.RequestedData())
1385 self.assertEqual(q.Query(data),
1386 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1387 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1388 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1389 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1390 self.assertEqual(q.Query(data, sort_by_name=False),
1391 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1392 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1393 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1394 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1397 { "pnode": "nodeX", "num": 50, },
1398 { "pnode": "nodeY", "num": 40, },
1399 { "pnode": "nodeX", "num": 30, },
1400 { "pnode": "nodeX", "num": 20, },
1401 { "pnode": "nodeM", "num": 10, },
1404 q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1405 qfilter=["|", ["=", "pnode", "nodeX"],
1406 ["=", "pnode", "nodeY"],
1407 ["=", "pnode", "nodeY"],
1408 ["=", "pnode", "nodeY"],
1409 ["=", "pnode", "nodeM"]])
1410 self.assertEqual(q.RequestedNames(), ["nodeX", "nodeY", "nodeM"],
1411 msg="Did not return unique names")
1412 self.assertFalse(q.RequestedData())
1414 # First sorted by name, then input order
1415 self.assertEqual(q.Query(data, sort_by_name=True),
1416 [[(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)],
1417 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1418 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1419 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1420 [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)]])
1423 self.assertEqual(q.Query(data, sort_by_name=False),
1424 [[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1425 [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)],
1426 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1427 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1428 [(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)]])
1430 def testFilter(self):
1431 (DK_A, DK_B) = range(1000, 1002)
1433 fielddefs = query._PrepareFieldList([
1434 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1435 DK_A, 0, lambda ctx, item: item["name"]),
1436 (query._MakeField("other", "Other", constants.QFT_TEXT, "Other"),
1437 DK_B, 0, lambda ctx, item: item["other"]),
1441 { "name": "node1", "other": "foo", },
1442 { "name": "node2", "other": "bar", },
1443 { "name": "node3", "other": "Hello", },
1447 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1449 self.assertTrue(q.RequestedNames() is None)
1450 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1451 self.assertEqual(q.Query(data), [])
1454 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1455 qfilter=["=", "name", "node1"])
1456 self.assertEqual(q.RequestedNames(), ["node1"])
1457 self.assertEqual(q.Query(data),
1458 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")]])
1460 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1461 qfilter=(["|", ["=", "name", "node1"],
1462 ["=", "name", "node3"]]))
1463 self.assertEqual(q.RequestedNames(), ["node1", "node3"])
1464 self.assertEqual(q.Query(data),
1465 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1466 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1469 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1470 qfilter=(["|", ["=", "name", "node1"],
1471 ["|", ["=", "name", "node3"],
1472 ["=", "name", "node2"]],
1473 ["=", "name", "node3"]]))
1474 self.assertEqual(q.RequestedNames(), ["node1", "node3", "node2"])
1475 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1476 self.assertEqual(q.Query(data),
1477 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1478 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")],
1479 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1481 # Filter data type mismatch
1482 for i in [-1, 0, 1, 123, [], None, True, False]:
1483 self.assertRaises(errors.ParameterError, query.Query,
1484 fielddefs, ["name", "other"], namefield="name",
1485 qfilter=["=", "name", i])
1488 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1489 qfilter=["!", ["|", ["=", "name", "node1"],
1490 ["=", "name", "node3"]]])
1491 self.assertTrue(q.RequestedNames() is None)
1492 self.assertEqual(q.Query(data),
1493 [[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1496 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1497 qfilter=["!=", "name", "node3"])
1498 self.assertTrue(q.RequestedNames() is None)
1499 self.assertEqual(q.Query(data),
1500 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1501 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1504 q = query.Query(fielddefs, [], namefield="name",
1505 qfilter=["|", ["=", "other", "bar"],
1506 ["=", "name", "foo"]])
1507 self.assertTrue(q.RequestedNames() is None)
1508 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1509 self.assertEqual(q.Query(data), [[]])
1511 # Only one data type
1512 q = query.Query(fielddefs, ["other"], namefield="name",
1513 qfilter=["=", "other", "bar"])
1514 self.assertTrue(q.RequestedNames() is None)
1515 self.assertEqual(q.RequestedData(), set([DK_B]))
1516 self.assertEqual(q.Query(data), [[(constants.RS_NORMAL, "bar")]])
1518 q = query.Query(fielddefs, [], namefield="name",
1519 qfilter=["=", "other", "bar"])
1520 self.assertTrue(q.RequestedNames() is None)
1521 self.assertEqual(q.RequestedData(), set([DK_B]))
1522 self.assertEqual(q.Query(data), [[]])
1524 def testFilterContains(self):
1525 fielddefs = query._PrepareFieldList([
1526 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1527 None, 0, lambda ctx, item: item["name"]),
1528 (query._MakeField("other", "Other", constants.QFT_OTHER, "Other"),
1529 None, 0, lambda ctx, item: item["other"]),
1533 { "name": "node2", "other": ["x", "y", "bar"], },
1534 { "name": "node3", "other": "Hello", },
1535 { "name": "node1", "other": ["a", "b", "foo"], },
1536 { "name": "empty", "other": []},
1539 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1540 qfilter=["=[]", "other", "bar"])
1541 self.assertTrue(q.RequestedNames() is None)
1542 self.assertEqual(q.Query(data), [
1543 [(constants.RS_NORMAL, "node2"),
1544 (constants.RS_NORMAL, ["x", "y", "bar"])],
1547 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1548 qfilter=["|", ["=[]", "other", "bar"],
1549 ["=[]", "other", "a"],
1550 ["=[]", "other", "b"]])
1551 self.assertTrue(q.RequestedNames() is None)
1552 self.assertEqual(q.Query(data), [
1553 [(constants.RS_NORMAL, "node1"),
1554 (constants.RS_NORMAL, ["a", "b", "foo"])],
1555 [(constants.RS_NORMAL, "node2"),
1556 (constants.RS_NORMAL, ["x", "y", "bar"])],
1558 self.assertEqual(q.OldStyleQuery(data), [
1559 ["node1", ["a", "b", "foo"]],
1560 ["node2", ["x", "y", "bar"]],
1564 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1565 qfilter=["?", "other"])
1566 self.assertEqual(q.OldStyleQuery(data), [
1567 ["node1", ["a", "b", "foo"]],
1568 ["node2", ["x", "y", "bar"]],
1572 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1573 qfilter=["!", ["?", "other"]])
1574 self.assertEqual(q.OldStyleQuery(data), [
1578 def testFilterHostname(self):
1579 fielddefs = query._PrepareFieldList([
1580 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1581 None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1585 { "name": "node1.example.com", },
1586 { "name": "node2.example.com", },
1587 { "name": "node2.example.net", },
1590 q = query.Query(fielddefs, ["name"], namefield="name",
1591 qfilter=["=", "name", "node2"])
1592 self.assertEqual(q.RequestedNames(), ["node2"])
1593 self.assertEqual(q.Query(data), [
1594 [(constants.RS_NORMAL, "node2.example.com")],
1595 [(constants.RS_NORMAL, "node2.example.net")],
1598 q = query.Query(fielddefs, ["name"], namefield="name",
1599 qfilter=["=", "name", "node1"])
1600 self.assertEqual(q.RequestedNames(), ["node1"])
1601 self.assertEqual(q.Query(data), [
1602 [(constants.RS_NORMAL, "node1.example.com")],
1605 q = query.Query(fielddefs, ["name"], namefield="name",
1606 qfilter=["=", "name", "othername"])
1607 self.assertEqual(q.RequestedNames(), ["othername"])
1608 self.assertEqual(q.Query(data), [])
1610 q = query.Query(fielddefs, ["name"], namefield="name",
1611 qfilter=["|", ["=", "name", "node1.example.com"],
1612 ["=", "name", "node2"]])
1613 self.assertEqual(q.RequestedNames(), ["node1.example.com", "node2"])
1614 self.assertEqual(q.Query(data), [
1615 [(constants.RS_NORMAL, "node1.example.com")],
1616 [(constants.RS_NORMAL, "node2.example.com")],
1617 [(constants.RS_NORMAL, "node2.example.net")],
1619 self.assertEqual(q.OldStyleQuery(data), [
1620 ["node1.example.com"],
1621 ["node2.example.com"],
1622 ["node2.example.net"],
1625 q = query.Query(fielddefs, ["name"], namefield="name",
1626 qfilter=["!=", "name", "node1"])
1627 self.assertTrue(q.RequestedNames() is None)
1628 self.assertEqual(q.Query(data), [
1629 [(constants.RS_NORMAL, "node2.example.com")],
1630 [(constants.RS_NORMAL, "node2.example.net")],
1632 self.assertEqual(q.OldStyleQuery(data), [
1633 ["node2.example.com"],
1634 ["node2.example.net"],
1637 def testFilterBoolean(self):
1638 fielddefs = query._PrepareFieldList([
1639 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1640 None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1641 (query._MakeField("value", "Value", constants.QFT_BOOL, "Value"),
1642 None, 0, lambda ctx, item: item["value"]),
1646 { "name": "node1", "value": False, },
1647 { "name": "node2", "value": True, },
1648 { "name": "node3", "value": True, },
1651 q = query.Query(fielddefs, ["name", "value"],
1652 qfilter=["|", ["=", "value", False],
1653 ["=", "value", True]])
1654 self.assertTrue(q.RequestedNames() is None)
1655 self.assertEqual(q.Query(data), [
1656 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1657 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1658 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1661 q = query.Query(fielddefs, ["name", "value"],
1662 qfilter=["|", ["=", "value", False],
1663 ["!", ["=", "value", False]]])
1664 self.assertTrue(q.RequestedNames() is None)
1665 self.assertEqual(q.Query(data), [
1666 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1667 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1668 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1671 # Comparing bool with string
1672 for i in ["False", "True", "0", "1", "no", "yes", "N", "Y"]:
1673 self.assertRaises(errors.ParameterError, query.Query,
1674 fielddefs, ["name", "value"],
1675 qfilter=["=", "value", i])
1678 q = query.Query(fielddefs, ["name", "value"], qfilter=["?", "value"])
1679 self.assertTrue(q.RequestedNames() is None)
1680 self.assertEqual(q.Query(data), [
1681 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1682 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1685 # Negative bool filter
1686 q = query.Query(fielddefs, ["name", "value"], qfilter=["!", ["?", "value"]])
1687 self.assertTrue(q.RequestedNames() is None)
1688 self.assertEqual(q.Query(data), [
1689 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1692 # Complex truth filter
1693 q = query.Query(fielddefs, ["name", "value"],
1694 qfilter=["|", ["&", ["=", "name", "node1"],
1695 ["!", ["?", "value"]]],
1697 self.assertTrue(q.RequestedNames() is None)
1698 self.assertEqual(q.Query(data), [
1699 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1700 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1701 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1704 def testFilterRegex(self):
1705 fielddefs = query._PrepareFieldList([
1706 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1707 None, 0, lambda ctx, item: item["name"]),
1711 { "name": "node1.example.com", },
1712 { "name": "node2.site.example.com", },
1713 { "name": "node2.example.net", },
1719 q = query.Query(fielddefs, ["name"], namefield="name",
1720 qfilter=["=~", "name", "site"])
1721 self.assertTrue(q.RequestedNames() is None)
1722 self.assertEqual(q.Query(data), [
1723 [(constants.RS_NORMAL, "node2.site.example.com")],
1726 q = query.Query(fielddefs, ["name"], namefield="name",
1727 qfilter=["=~", "name", "^node2"])
1728 self.assertTrue(q.RequestedNames() is None)
1729 self.assertEqual(q.Query(data), [
1730 [(constants.RS_NORMAL, "node2.example.net")],
1731 [(constants.RS_NORMAL, "node2.site.example.com")],
1734 q = query.Query(fielddefs, ["name"], namefield="name",
1735 qfilter=["=~", "name", r"(?i)\.COM$"])
1736 self.assertTrue(q.RequestedNames() is None)
1737 self.assertEqual(q.Query(data), [
1738 [(constants.RS_NORMAL, "node1.example.com")],
1739 [(constants.RS_NORMAL, "node2.site.example.com")],
1742 q = query.Query(fielddefs, ["name"], namefield="name",
1743 qfilter=["=~", "name", r"."])
1744 self.assertTrue(q.RequestedNames() is None)
1745 self.assertEqual(q.Query(data), [
1746 [(constants.RS_NORMAL, "node1.example.com")],
1747 [(constants.RS_NORMAL, "node2.example.net")],
1748 [(constants.RS_NORMAL, "node2.site.example.com")],
1751 q = query.Query(fielddefs, ["name"], namefield="name",
1752 qfilter=["=~", "name", r"^$"])
1753 self.assertTrue(q.RequestedNames() is None)
1754 self.assertEqual(q.Query(data), [
1755 [(constants.RS_NORMAL, "")],
1758 # Invalid regular expression
1759 self.assertRaises(errors.ParameterError, query.Query, fielddefs, ["name"],
1760 qfilter=["=~", "name", r"["])
1762 def testFilterLessGreater(self):
1763 fielddefs = query._PrepareFieldList([
1764 (query._MakeField("value", "Value", constants.QFT_NUMBER, "Value"),
1765 None, 0, lambda ctx, item: item),
1770 q = query.Query(fielddefs, ["value"],
1771 qfilter=["<", "value", 20])
1772 self.assertTrue(q.RequestedNames() is None)
1773 self.assertEqual(q.Query(data),
1774 [[(constants.RS_NORMAL, i)] for i in range(20)])
1776 q = query.Query(fielddefs, ["value"],
1777 qfilter=["<=", "value", 30])
1778 self.assertTrue(q.RequestedNames() is None)
1779 self.assertEqual(q.Query(data),
1780 [[(constants.RS_NORMAL, i)] for i in range(31)])
1782 q = query.Query(fielddefs, ["value"],
1783 qfilter=[">", "value", 40])
1784 self.assertTrue(q.RequestedNames() is None)
1785 self.assertEqual(q.Query(data),
1786 [[(constants.RS_NORMAL, i)] for i in range(41, 100)])
1788 q = query.Query(fielddefs, ["value"],
1789 qfilter=[">=", "value", 50])
1790 self.assertTrue(q.RequestedNames() is None)
1791 self.assertEqual(q.Query(data),
1792 [[(constants.RS_NORMAL, i)] for i in range(50, 100)])
1794 def testFilterLessGreaterJobId(self):
1795 fielddefs = query._PrepareFieldList([
1796 (query._MakeField("id", "ID", constants.QFT_TEXT, "Job ID"),
1797 None, query.QFF_JOB_ID, lambda ctx, item: item),
1800 data = ["1", "2", "3", "10", "102", "120", "125", "15", "100", "7"]
1802 assert data != utils.NiceSort(data), "Test data should not be sorted"
1804 q = query.Query(fielddefs, ["id"], qfilter=["<", "id", "20"])
1805 self.assertTrue(q.RequestedNames() is None)
1806 self.assertEqual(q.Query(data), [
1807 [(constants.RS_NORMAL, "1")],
1808 [(constants.RS_NORMAL, "2")],
1809 [(constants.RS_NORMAL, "3")],
1810 [(constants.RS_NORMAL, "10")],
1811 [(constants.RS_NORMAL, "15")],
1812 [(constants.RS_NORMAL, "7")],
1815 q = query.Query(fielddefs, ["id"], qfilter=[">=", "id", "100"])
1816 self.assertTrue(q.RequestedNames() is None)
1817 self.assertEqual(q.Query(data), [
1818 [(constants.RS_NORMAL, "102")],
1819 [(constants.RS_NORMAL, "120")],
1820 [(constants.RS_NORMAL, "125")],
1821 [(constants.RS_NORMAL, "100")],
1824 # Integers are no valid job IDs
1825 self.assertRaises(errors.ParameterError, query.Query,
1826 fielddefs, ["id"], qfilter=[">=", "id", 10])
1828 def testFilterLessGreaterSplitTimestamp(self):
1829 fielddefs = query._PrepareFieldList([
1830 (query._MakeField("ts", "Timestamp", constants.QFT_OTHER, "Timestamp"),
1831 None, query.QFF_SPLIT_TIMESTAMP, lambda ctx, item: item),
1836 utils.SplitTime(0.1),
1837 utils.SplitTime(18224.7872),
1838 utils.SplitTime(919896.12623),
1839 utils.SplitTime(999),
1840 utils.SplitTime(989.9999),
1843 for i in [0, [0, 0]]:
1844 q = query.Query(fielddefs, ["ts"], qfilter=["<", "ts", i])
1845 self.assertTrue(q.RequestedNames() is None)
1846 self.assertEqual(q.Query(data), [])
1848 q = query.Query(fielddefs, ["ts"], qfilter=["<", "ts", 1000])
1849 self.assertTrue(q.RequestedNames() is None)
1850 self.assertEqual(q.Query(data), [
1851 [(constants.RS_NORMAL, (0, 0))],
1852 [(constants.RS_NORMAL, (0, 100000))],
1853 [(constants.RS_NORMAL, (999, 0))],
1854 [(constants.RS_NORMAL, (989, 999900))],
1857 q = query.Query(fielddefs, ["ts"], qfilter=[">=", "ts", 5000.3])
1858 self.assertTrue(q.RequestedNames() is None)
1859 self.assertEqual(q.Query(data), [
1860 [(constants.RS_NORMAL, (18224, 787200))],
1861 [(constants.RS_NORMAL, (919896, 126230))],
1864 for i in [18224.7772, utils.SplitTime(18224.7772)]:
1865 q = query.Query(fielddefs, ["ts"], qfilter=[">=", "ts", i])
1866 self.assertTrue(q.RequestedNames() is None)
1867 self.assertEqual(q.Query(data), [
1868 [(constants.RS_NORMAL, (18224, 787200))],
1869 [(constants.RS_NORMAL, (919896, 126230))],
1872 q = query.Query(fielddefs, ["ts"], qfilter=[">", "ts", 18224.7880])
1873 self.assertTrue(q.RequestedNames() is None)
1874 self.assertEqual(q.Query(data), [
1875 [(constants.RS_NORMAL, (919896, 126230))],
1879 if __name__ == "__main__":
1880 testutils.GanetiTestProgram()