Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.qlang_unittest.py @ 91c17910

History | View | Annotate | Download (10.2 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 ad48eacc Michael Hanselmann
    self._Test("ctime < 1234", [qlang.OP_LT, "ctime", 1234])
151 ad48eacc Michael Hanselmann
    self._Test("ctime > 1234", [qlang.OP_GT, "ctime", 1234])
152 ad48eacc Michael Hanselmann
    self._Test("mtime <= 9999", [qlang.OP_LE, "mtime", 9999])
153 ad48eacc Michael Hanselmann
    self._Test("mtime >= 9999", [qlang.OP_GE, "mtime", 9999])
154 ad48eacc Michael Hanselmann
155 7578ab0a Michael Hanselmann
  def testAllFields(self):
156 7578ab0a Michael Hanselmann
    for name in frozenset(i for d in query.ALL_FIELD_LISTS for i in d.keys()):
157 7578ab0a Michael Hanselmann
      self._Test("%s == \"value\"" % name, [qlang.OP_EQUAL, name, "value"])
158 7578ab0a Michael Hanselmann
159 7578ab0a Michael Hanselmann
  def testError(self):
160 7578ab0a Michael Hanselmann
    # Invalid field names, meaning no boolean check is done
161 7578ab0a Michael Hanselmann
    tests = ["#invalid!filter#", "m/x/,"]
162 7578ab0a Michael Hanselmann
163 7578ab0a Michael Hanselmann
    # Unknown regexp flag
164 7578ab0a Michael Hanselmann
    tests.append("name=~m#a#g")
165 7578ab0a Michael Hanselmann
166 7578ab0a Michael Hanselmann
    # Incomplete regexp group
167 7578ab0a Michael Hanselmann
    tests.append("name=~^[^")
168 7578ab0a Michael Hanselmann
169 7578ab0a Michael Hanselmann
    # Valid flag, but in uppercase
170 7578ab0a Michael Hanselmann
    tests.append("asdf =~ m|abc|I")
171 7578ab0a Michael Hanselmann
172 7578ab0a Michael Hanselmann
    # Non-matching regexp delimiters
173 7578ab0a Michael Hanselmann
    tests.append("name =~ /foobarbaz#")
174 7578ab0a Michael Hanselmann
175 ad48eacc Michael Hanselmann
    # Invalid operators
176 ad48eacc Michael Hanselmann
    tests.append("name <> value")
177 ad48eacc Michael Hanselmann
    tests.append("name => value")
178 ad48eacc Michael Hanselmann
    tests.append("name =< value")
179 ad48eacc Michael Hanselmann
180 2e5c33db Iustin Pop
    for qfilter in tests:
181 7578ab0a Michael Hanselmann
      try:
182 2e5c33db Iustin Pop
        qlang.ParseFilter(qfilter, parser=self.parser)
183 7578ab0a Michael Hanselmann
      except errors.QueryFilterParseError, err:
184 7578ab0a Michael Hanselmann
        self.assertEqual(len(err.GetDetails()), 3)
185 7578ab0a Michael Hanselmann
      else:
186 2e5c33db Iustin Pop
        self.fail("Invalid filter '%s' did not raise exception" % qfilter)
187 7578ab0a Michael Hanselmann
188 7578ab0a Michael Hanselmann
189 f8638e28 Michael Hanselmann
class TestMakeFilter(unittest.TestCase):
190 f8638e28 Michael Hanselmann
  def testNoNames(self):
191 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter([], False), None)
192 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(None, False), None)
193 f8638e28 Michael Hanselmann
194 f8638e28 Michael Hanselmann
  def testPlainNames(self):
195 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web1", "web2"], False),
196 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_EQUAL, "name", "web1"],
197 f8638e28 Michael Hanselmann
                                   [qlang.OP_EQUAL, "name", "web2"]])
198 f8638e28 Michael Hanselmann
199 03ec545a Michael Hanselmann
  def testPlainNamesOtherNamefield(self):
200 03ec545a Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["mailA", "mailB"], False,
201 03ec545a Michael Hanselmann
                                      namefield="id"),
202 03ec545a Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_EQUAL, "id", "mailA"],
203 03ec545a Michael Hanselmann
                                   [qlang.OP_EQUAL, "id", "mailB"]])
204 03ec545a Michael Hanselmann
205 f8638e28 Michael Hanselmann
  def testForcedFilter(self):
206 f8638e28 Michael Hanselmann
    for i in [None, [], ["1", "2"], ["", "", ""], ["a", "b", "c", "d"]]:
207 f8638e28 Michael Hanselmann
      self.assertRaises(errors.OpPrereqError, qlang.MakeFilter, i, True)
208 f8638e28 Michael Hanselmann
209 f8638e28 Michael Hanselmann
    # Glob pattern shouldn't parse as filter
210 f8638e28 Michael Hanselmann
    self.assertRaises(errors.QueryFilterParseError,
211 f8638e28 Michael Hanselmann
                      qlang.MakeFilter, ["*.site"], True)
212 f8638e28 Michael Hanselmann
213 f8638e28 Michael Hanselmann
    # Plain name parses as boolean filter
214 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web1"], True), [qlang.OP_TRUE, "web1"])
215 f8638e28 Michael Hanselmann
216 f8638e28 Michael Hanselmann
  def testFilter(self):
217 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo/bar"], False),
218 f8638e28 Michael Hanselmann
                     [qlang.OP_TRUE, "foo/bar"])
219 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo=='bar'"], False),
220 f8638e28 Michael Hanselmann
                     [qlang.OP_EQUAL, "foo", "bar"])
221 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["field=*'*.site'"], False),
222 f8638e28 Michael Hanselmann
                     [qlang.OP_REGEXP, "field",
223 f8638e28 Michael Hanselmann
                      utils.DnsNameGlobPattern("*.site")])
224 f8638e28 Michael Hanselmann
225 f8638e28 Michael Hanselmann
    # Plain name parses as name filter, not boolean
226 f8638e28 Michael Hanselmann
    for name in ["node1", "n-o-d-e", "n_o_d_e", "node1.example.com",
227 f8638e28 Michael Hanselmann
                 "node1.example.com."]:
228 f8638e28 Michael Hanselmann
      self.assertEqual(qlang.MakeFilter([name], False),
229 f8638e28 Michael Hanselmann
                       [qlang.OP_OR, [qlang.OP_EQUAL, "name", name]])
230 f8638e28 Michael Hanselmann
231 f8638e28 Michael Hanselmann
    # Invalid filters
232 f8638e28 Michael Hanselmann
    for i in ["foo==bar", "foo+=1"]:
233 f8638e28 Michael Hanselmann
      self.assertRaises(errors.QueryFilterParseError,
234 f8638e28 Michael Hanselmann
                        qlang.MakeFilter, [i], False)
235 f8638e28 Michael Hanselmann
236 f8638e28 Michael Hanselmann
  def testGlob(self):
237 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.site"], False),
238 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
239 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("*.site")]])
240 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web?.example"], False),
241 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
242 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("web?.example")]])
243 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.a", "*.b", "?.c"], False),
244 f8638e28 Michael Hanselmann
                     [qlang.OP_OR,
245 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
246 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.a")],
247 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
248 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.b")],
249 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
250 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("?.c")]])
251 3f2f55bb Michael Hanselmann
252 3f2f55bb Michael Hanselmann
253 a123dc19 Michael Hanselmann
if __name__ == "__main__":
254 a123dc19 Michael Hanselmann
  testutils.GanetiTestProgram()