Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.qlang_unittest.py @ 0f85ebd9

History | View | Annotate | Download (9.6 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 f8638e28 Michael Hanselmann
  def testForcedFilter(self):
190 f8638e28 Michael Hanselmann
    for i in [None, [], ["1", "2"], ["", "", ""], ["a", "b", "c", "d"]]:
191 f8638e28 Michael Hanselmann
      self.assertRaises(errors.OpPrereqError, qlang.MakeFilter, i, True)
192 f8638e28 Michael Hanselmann
193 f8638e28 Michael Hanselmann
    # Glob pattern shouldn't parse as filter
194 f8638e28 Michael Hanselmann
    self.assertRaises(errors.QueryFilterParseError,
195 f8638e28 Michael Hanselmann
                      qlang.MakeFilter, ["*.site"], True)
196 f8638e28 Michael Hanselmann
197 f8638e28 Michael Hanselmann
    # Plain name parses as boolean filter
198 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web1"], True), [qlang.OP_TRUE, "web1"])
199 f8638e28 Michael Hanselmann
200 f8638e28 Michael Hanselmann
  def testFilter(self):
201 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo/bar"], False),
202 f8638e28 Michael Hanselmann
                     [qlang.OP_TRUE, "foo/bar"])
203 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["foo=='bar'"], False),
204 f8638e28 Michael Hanselmann
                     [qlang.OP_EQUAL, "foo", "bar"])
205 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["field=*'*.site'"], False),
206 f8638e28 Michael Hanselmann
                     [qlang.OP_REGEXP, "field",
207 f8638e28 Michael Hanselmann
                      utils.DnsNameGlobPattern("*.site")])
208 f8638e28 Michael Hanselmann
209 f8638e28 Michael Hanselmann
    # Plain name parses as name filter, not boolean
210 f8638e28 Michael Hanselmann
    for name in ["node1", "n-o-d-e", "n_o_d_e", "node1.example.com",
211 f8638e28 Michael Hanselmann
                 "node1.example.com."]:
212 f8638e28 Michael Hanselmann
      self.assertEqual(qlang.MakeFilter([name], False),
213 f8638e28 Michael Hanselmann
                       [qlang.OP_OR, [qlang.OP_EQUAL, "name", name]])
214 f8638e28 Michael Hanselmann
215 f8638e28 Michael Hanselmann
    # Invalid filters
216 f8638e28 Michael Hanselmann
    for i in ["foo==bar", "foo+=1"]:
217 f8638e28 Michael Hanselmann
      self.assertRaises(errors.QueryFilterParseError,
218 f8638e28 Michael Hanselmann
                        qlang.MakeFilter, [i], False)
219 f8638e28 Michael Hanselmann
220 f8638e28 Michael Hanselmann
  def testGlob(self):
221 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.site"], False),
222 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
223 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("*.site")]])
224 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["web?.example"], False),
225 f8638e28 Michael Hanselmann
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
226 f8638e28 Michael Hanselmann
                                    utils.DnsNameGlobPattern("web?.example")]])
227 f8638e28 Michael Hanselmann
    self.assertEqual(qlang.MakeFilter(["*.a", "*.b", "?.c"], False),
228 f8638e28 Michael Hanselmann
                     [qlang.OP_OR,
229 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
230 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.a")],
231 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
232 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("*.b")],
233 f8638e28 Michael Hanselmann
                      [qlang.OP_REGEXP, "name",
234 f8638e28 Michael Hanselmann
                       utils.DnsNameGlobPattern("?.c")]])
235 3f2f55bb Michael Hanselmann
236 3f2f55bb Michael Hanselmann
237 a123dc19 Michael Hanselmann
if __name__ == "__main__":
238 a123dc19 Michael Hanselmann
  testutils.GanetiTestProgram()