Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.qlang_unittest.py @ 03ec545a

History | View | Annotate | Download (9.9 kB)

1 a123dc19 Michael Hanselmann
#!/usr/bin/python
2 a123dc19 Michael Hanselmann
#
3 a123dc19 Michael Hanselmann
4 2e5c33db Iustin Pop
# Copyright (C) 2010, 2011 Google Inc.
5 a123dc19 Michael Hanselmann
#
6 a123dc19 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 a123dc19 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 a123dc19 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 a123dc19 Michael Hanselmann
# (at your option) any later version.
10 a123dc19 Michael Hanselmann
#
11 a123dc19 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 a123dc19 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a123dc19 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a123dc19 Michael Hanselmann
# General Public License for more details.
15 a123dc19 Michael Hanselmann
#
16 a123dc19 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 a123dc19 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 a123dc19 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a123dc19 Michael Hanselmann
# 02110-1301, USA.
20 a123dc19 Michael Hanselmann
21 a123dc19 Michael Hanselmann
22 a123dc19 Michael Hanselmann
"""Script for testing ganeti.qlang"""
23 a123dc19 Michael Hanselmann
24 a123dc19 Michael Hanselmann
import unittest
25 3f2f55bb Michael Hanselmann
import string
26 a123dc19 Michael Hanselmann
27 a123dc19 Michael Hanselmann
from ganeti import utils
28 a123dc19 Michael Hanselmann
from ganeti import errors
29 a123dc19 Michael Hanselmann
from ganeti import qlang
30 7578ab0a Michael Hanselmann
from ganeti import query
31 a123dc19 Michael Hanselmann
32 a123dc19 Michael Hanselmann
import testutils
33 a123dc19 Michael Hanselmann
34 a123dc19 Michael Hanselmann
35 60cba7f8 Michael Hanselmann
class TestMakeSimpleFilter(unittest.TestCase):
36 60cba7f8 Michael Hanselmann
  def _Test(self, field, names, expected, parse_exp=None):
37 60cba7f8 Michael Hanselmann
    if parse_exp is None:
38 60cba7f8 Michael Hanselmann
      parse_exp = names
39 60cba7f8 Michael Hanselmann
40 2e5c33db Iustin Pop
    qfilter = qlang.MakeSimpleFilter(field, names)
41 2e5c33db Iustin Pop
    self.assertEqual(qfilter, expected)
42 60cba7f8 Michael Hanselmann
43 60cba7f8 Michael Hanselmann
  def test(self):
44 60cba7f8 Michael Hanselmann
    self._Test("name", None, None, parse_exp=[])
45 60cba7f8 Michael Hanselmann
    self._Test("name", [], None)
46 60cba7f8 Michael Hanselmann
    self._Test("name", ["node1.example.com"],
47 60cba7f8 Michael Hanselmann
               ["|", ["=", "name", "node1.example.com"]])
48 60cba7f8 Michael Hanselmann
    self._Test("xyz", ["a", "b", "c"],
49 60cba7f8 Michael Hanselmann
               ["|", ["=", "xyz", "a"], ["=", "xyz", "b"], ["=", "xyz", "c"]])
50 60cba7f8 Michael Hanselmann
51 60cba7f8 Michael Hanselmann
52 7578ab0a Michael Hanselmann
class TestParseFilter(unittest.TestCase):
53 7578ab0a Michael Hanselmann
  def setUp(self):
54 7578ab0a Michael Hanselmann
    self.parser = qlang.BuildFilterParser()
55 7578ab0a Michael Hanselmann
56 2e5c33db Iustin Pop
  def _Test(self, qfilter, expected, expect_filter=True):
57 2e5c33db Iustin Pop
    self.assertEqual(qlang.MakeFilter([qfilter], not expect_filter), expected)
58 2e5c33db Iustin Pop
    self.assertEqual(qlang.ParseFilter(qfilter, parser=self.parser), expected)
59 7578ab0a Michael Hanselmann
60 7578ab0a Michael Hanselmann
  def test(self):
61 7578ab0a Michael Hanselmann
    self._Test("name==\"foobar\"", [qlang.OP_EQUAL, "name", "foobar"])
62 7578ab0a Michael Hanselmann
    self._Test("name=='foobar'", [qlang.OP_EQUAL, "name", "foobar"])
63 7578ab0a Michael Hanselmann
64 7578ab0a Michael Hanselmann
    self._Test("valA==1 and valB==2 or valC==3",
65 7578ab0a Michael Hanselmann
               [qlang.OP_OR,
66 7578ab0a Michael Hanselmann
                [qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
67 7578ab0a Michael Hanselmann
                               [qlang.OP_EQUAL, "valB", 2]],
68 7578ab0a Michael Hanselmann
                [qlang.OP_EQUAL, "valC", 3]])
69 7578ab0a Michael Hanselmann
70 7578ab0a Michael Hanselmann
    self._Test(("(name\n==\"foobar\") and (xyz==\"va)ue\" and k == 256 or"
71 7578ab0a Michael Hanselmann
                " x ==\t\"y\"\n) and mc"),
72 7578ab0a Michael Hanselmann
               [qlang.OP_AND,
73 7578ab0a Michael Hanselmann
                [qlang.OP_EQUAL, "name", "foobar"],
74 7578ab0a Michael Hanselmann
                [qlang.OP_OR,
75 7578ab0a Michael Hanselmann
                 [qlang.OP_AND, [qlang.OP_EQUAL, "xyz", "va)ue"],
76 7578ab0a Michael Hanselmann
                                [qlang.OP_EQUAL, "k", 256]],
77 7578ab0a Michael Hanselmann
                 [qlang.OP_EQUAL, "x", "y"]],
78 7578ab0a Michael Hanselmann
                [qlang.OP_TRUE, "mc"]])
79 7578ab0a Michael Hanselmann
80 7578ab0a Michael Hanselmann
    self._Test("(xyz==\"v\" or k == 256 and x == \"y\")",
81 7578ab0a Michael Hanselmann
               [qlang.OP_OR,
82 7578ab0a Michael Hanselmann
                [qlang.OP_EQUAL, "xyz", "v"],
83 7578ab0a Michael Hanselmann
                [qlang.OP_AND, [qlang.OP_EQUAL, "k", 256],
84 7578ab0a Michael Hanselmann
                               [qlang.OP_EQUAL, "x", "y"]]])
85 7578ab0a Michael Hanselmann
86 7578ab0a Michael Hanselmann
    self._Test("valA==1 and valB==2 and valC==3",
87 7578ab0a Michael Hanselmann
               [qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
88 7578ab0a Michael Hanselmann
                              [qlang.OP_EQUAL, "valB", 2],
89 7578ab0a Michael Hanselmann
                              [qlang.OP_EQUAL, "valC", 3]])
90 7578ab0a Michael Hanselmann
    self._Test("master or field",
91 7578ab0a Michael Hanselmann
               [qlang.OP_OR, [qlang.OP_TRUE, "master"],
92 7578ab0a Michael Hanselmann
                             [qlang.OP_TRUE, "field"]])
93 7578ab0a Michael Hanselmann
    self._Test("mem == 128", [qlang.OP_EQUAL, "mem", 128])
94 7578ab0a Michael Hanselmann
    self._Test("negfield != -1", [qlang.OP_NOT_EQUAL, "negfield", -1])
95 3f2f55bb Michael Hanselmann
    self._Test("master", [qlang.OP_TRUE, "master"],
96 3f2f55bb Michael Hanselmann
               expect_filter=False)
97 7578ab0a Michael Hanselmann
    self._Test("not master", [qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
98 7578ab0a Michael Hanselmann
    for op in ["not", "and", "or"]:
99 3f2f55bb Michael Hanselmann
      self._Test("%sxyz" % op, [qlang.OP_TRUE, "%sxyz" % op],
100 3f2f55bb Michael Hanselmann
                 expect_filter=False)
101 7578ab0a Michael Hanselmann
      self._Test("not %sxyz" % op,
102 7578ab0a Michael Hanselmann
                 [qlang.OP_NOT, [qlang.OP_TRUE, "%sxyz" % op]])
103 7578ab0a Michael Hanselmann
      self._Test("  not \t%sfoo" % op,
104 7578ab0a Michael Hanselmann
                 [qlang.OP_NOT, [qlang.OP_TRUE, "%sfoo" % op]])
105 7578ab0a Michael Hanselmann
      self._Test("%sname =~ m/abc/" % op,
106 7578ab0a Michael Hanselmann
                 [qlang.OP_REGEXP, "%sname" % op, "abc"])
107 7578ab0a Michael Hanselmann
    self._Test("master and not other",
108 7578ab0a Michael Hanselmann
               [qlang.OP_AND, [qlang.OP_TRUE, "master"],
109 7578ab0a Michael Hanselmann
                              [qlang.OP_NOT, [qlang.OP_TRUE, "other"]]])
110 7578ab0a Michael Hanselmann
    self._Test("not (master or other == 4)",
111 7578ab0a Michael Hanselmann
               [qlang.OP_NOT,
112 7578ab0a Michael Hanselmann
                [qlang.OP_OR, [qlang.OP_TRUE, "master"],
113 7578ab0a Michael Hanselmann
                              [qlang.OP_EQUAL, "other", 4]]])
114 7578ab0a Michael Hanselmann
    self._Test("some==\"val\\\"ue\"", [qlang.OP_EQUAL, "some", "val\\\"ue"])
115 7578ab0a Michael Hanselmann
    self._Test("123 in ips", [qlang.OP_CONTAINS, "ips", 123])
116 7578ab0a Michael Hanselmann
    self._Test("99 not in ips", [qlang.OP_NOT, [qlang.OP_CONTAINS, "ips", 99]])
117 7578ab0a Michael Hanselmann
    self._Test("\"a\" in valA and \"b\" not in valB",
118 7578ab0a Michael Hanselmann
               [qlang.OP_AND, [qlang.OP_CONTAINS, "valA", "a"],
119 7578ab0a Michael Hanselmann
                              [qlang.OP_NOT, [qlang.OP_CONTAINS, "valB", "b"]]])
120 7578ab0a Michael Hanselmann
121 7578ab0a Michael Hanselmann
    self._Test("name =~ m/test/", [qlang.OP_REGEXP, "name", "test"])
122 7578ab0a Michael Hanselmann
    self._Test("name =~ m/^node.*example.com$/i",
123 7578ab0a Michael Hanselmann
               [qlang.OP_REGEXP, "name", "(?i)^node.*example.com$"])
124 7578ab0a Michael Hanselmann
    self._Test("(name =~ m/^node.*example.com$/s and master) or pip =~ |^3.*|",
125 7578ab0a Michael Hanselmann
               [qlang.OP_OR,
126 7578ab0a Michael Hanselmann
                [qlang.OP_AND,
127 7578ab0a Michael Hanselmann
                 [qlang.OP_REGEXP, "name", "(?s)^node.*example.com$"],
128 7578ab0a Michael Hanselmann
                 [qlang.OP_TRUE, "master"]],
129 7578ab0a Michael Hanselmann
                [qlang.OP_REGEXP, "pip", "^3.*"]])
130 7578ab0a Michael Hanselmann
    for flags in ["si", "is", "ssss", "iiiisiii"]:
131 7578ab0a Michael Hanselmann
      self._Test("name =~ m/gi/%s" % flags,
132 7578ab0a Michael Hanselmann
                 [qlang.OP_REGEXP, "name", "(?%s)gi" % "".join(sorted(flags))])
133 7578ab0a Michael Hanselmann
134 7578ab0a Michael Hanselmann
    for i in qlang._KNOWN_REGEXP_DELIM:
135 7578ab0a Michael Hanselmann
      self._Test("name =~ m%stest%s" % (i, i),
136 7578ab0a Michael Hanselmann
                 [qlang.OP_REGEXP, "name", "test"])
137 7578ab0a Michael Hanselmann
      self._Test("name !~ m%stest%s" % (i, i),
138 7578ab0a Michael Hanselmann
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
139 7578ab0a Michael Hanselmann
      self._Test("not\tname =~ m%stest%s" % (i, i),
140 7578ab0a Michael Hanselmann
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
141 7578ab0a Michael Hanselmann
      self._Test("notname =~ m%stest%s" % (i, i),
142 7578ab0a Michael Hanselmann
                 [qlang.OP_REGEXP, "notname", "test"])
143 7578ab0a Michael Hanselmann
144 16629d10 Michael Hanselmann
    self._Test("name =* '*.site'",
145 16629d10 Michael Hanselmann
               [qlang.OP_REGEXP, "name", utils.DnsNameGlobPattern("*.site")])
146 16629d10 Michael Hanselmann
    self._Test("field !* '*.example.*'",
147 16629d10 Michael Hanselmann
               [qlang.OP_NOT, [qlang.OP_REGEXP, "field",
148 16629d10 Michael Hanselmann
                               utils.DnsNameGlobPattern("*.example.*")]])
149 16629d10 Michael Hanselmann
150 7578ab0a Michael Hanselmann
  def testAllFields(self):
151 7578ab0a Michael Hanselmann
    for name in frozenset(i for d in query.ALL_FIELD_LISTS for i in d.keys()):
152 7578ab0a Michael Hanselmann
      self._Test("%s == \"value\"" % name, [qlang.OP_EQUAL, name, "value"])
153 7578ab0a Michael Hanselmann
154 7578ab0a Michael Hanselmann
  def testError(self):
155 7578ab0a Michael Hanselmann
    # Invalid field names, meaning no boolean check is done
156 7578ab0a Michael Hanselmann
    tests = ["#invalid!filter#", "m/x/,"]
157 7578ab0a Michael Hanselmann
158 7578ab0a Michael Hanselmann
    # Unknown regexp flag
159 7578ab0a Michael Hanselmann
    tests.append("name=~m#a#g")
160 7578ab0a Michael Hanselmann
161 7578ab0a Michael Hanselmann
    # Incomplete regexp group
162 7578ab0a Michael Hanselmann
    tests.append("name=~^[^")
163 7578ab0a Michael Hanselmann
164 7578ab0a Michael Hanselmann
    # Valid flag, but in uppercase
165 7578ab0a Michael Hanselmann
    tests.append("asdf =~ m|abc|I")
166 7578ab0a Michael Hanselmann
167 7578ab0a Michael Hanselmann
    # Non-matching regexp delimiters
168 7578ab0a Michael Hanselmann
    tests.append("name =~ /foobarbaz#")
169 7578ab0a Michael Hanselmann
170 2e5c33db Iustin Pop
    for qfilter in tests:
171 7578ab0a Michael Hanselmann
      try:
172 2e5c33db Iustin Pop
        qlang.ParseFilter(qfilter, parser=self.parser)
173 7578ab0a Michael Hanselmann
      except errors.QueryFilterParseError, err:
174 7578ab0a Michael Hanselmann
        self.assertEqual(len(err.GetDetails()), 3)
175 7578ab0a Michael Hanselmann
      else:
176 2e5c33db Iustin Pop
        self.fail("Invalid filter '%s' did not raise exception" % qfilter)
177 7578ab0a Michael Hanselmann
178 7578ab0a Michael Hanselmann
179 f8638e28 Michael Hanselmann
class TestMakeFilter(unittest.TestCase):
180 f8638e28 Michael Hanselmann
  def testNoNames(self):
181 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter([], False), None)
182 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(None, False), None)
183 f8638e28 Michael Hanselmann
184 f8638e28 Michael Hanselmann
  def testPlainNames(self):
185 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web1", "web2"], False),
186 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_EQUAL, "name", "web1"],
187 f8638e28 Michael Hanselmann
                                   [qlang.OP_EQUAL, "name", "web2"]])
188 f8638e28 Michael Hanselmann
189 03ec545a Michael Hanselmann
  def testPlainNamesOtherNamefield(self):
190 03ec545a Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["mailA", "mailB"], False,
191 03ec545a Michael Hanselmann
                                      namefield="id"),
192 03ec545a Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_EQUAL, "id", "mailA"],
193 03ec545a Michael Hanselmann
                                   [qlang.OP_EQUAL, "id", "mailB"]])
194 03ec545a Michael Hanselmann
195 f8638e28 Michael Hanselmann
  def testForcedFilter(self):
196 f8638e28 Michael Hanselmann
    for i in [None, [], ["1", "2"], ["", "", ""], ["a", "b", "c", "d"]]:
197 f8638e28 Michael Hanselmann
      self.assertRaises(errors.OpPrereqError, qlang.MakeFilter, i, True)
198 f8638e28 Michael Hanselmann
199 f8638e28 Michael Hanselmann
    # Glob pattern shouldn't parse as filter
200 f8638e28 Michael Hanselmann
    self.assertRaises(errors.QueryFilterParseError,
201 f8638e28 Michael Hanselmann
                      qlang.MakeFilter, ["*.site"], True)
202 f8638e28 Michael Hanselmann
203 f8638e28 Michael Hanselmann
    # Plain name parses as boolean filter
204 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web1"], True), [qlang.OP_TRUE, "web1"])
205 f8638e28 Michael Hanselmann
206 f8638e28 Michael Hanselmann
  def testFilter(self):
207 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo/bar"], False),
208 f8638e28 Michael Hanselmann
                     [qlang.OP_TRUE, "foo/bar"])
209 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo=='bar'"], False),
210 f8638e28 Michael Hanselmann
                     [qlang.OP_EQUAL, "foo", "bar"])
211 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["field=*'*.site'"], False),
212 f8638e28 Michael Hanselmann
                     [qlang.OP_REGEXP, "field",
213 f8638e28 Michael Hanselmann
                      utils.DnsNameGlobPattern("*.site")])
214 f8638e28 Michael Hanselmann
215 f8638e28 Michael Hanselmann
    # Plain name parses as name filter, not boolean
216 f8638e28 Michael Hanselmann
    for name in ["node1", "n-o-d-e", "n_o_d_e", "node1.example.com",
217 f8638e28 Michael Hanselmann
                 "node1.example.com."]:
218 f8638e28 Michael Hanselmann
      self.assertEqual(qlang.MakeFilter([name], False),
219 f8638e28 Michael Hanselmann
                       [qlang.OP_OR, [qlang.OP_EQUAL, "name", name]])
220 f8638e28 Michael Hanselmann
221 f8638e28 Michael Hanselmann
    # Invalid filters
222 f8638e28 Michael Hanselmann
    for i in ["foo==bar", "foo+=1"]:
223 f8638e28 Michael Hanselmann
      self.assertRaises(errors.QueryFilterParseError,
224 f8638e28 Michael Hanselmann
                        qlang.MakeFilter, [i], False)
225 f8638e28 Michael Hanselmann
226 f8638e28 Michael Hanselmann
  def testGlob(self):
227 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.site"], False),
228 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
229 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("*.site")]])
230 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web?.example"], False),
231 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
232 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("web?.example")]])
233 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.a", "*.b", "?.c"], False),
234 f8638e28 Michael Hanselmann
                     [qlang.OP_OR,
235 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
236 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.a")],
237 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
238 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.b")],
239 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
240 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("?.c")]])
241 3f2f55bb Michael Hanselmann
242 3f2f55bb Michael Hanselmann
243 a123dc19 Michael Hanselmann
if __name__ == "__main__":
244 a123dc19 Michael Hanselmann
  testutils.GanetiTestProgram()