Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.qlang_unittest.py @ 2e5c33db

History | View | Annotate | Download (9.6 kB)

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

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

    
21

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

    
24
import unittest
25
import string
26

    
27
from ganeti import utils
28
from ganeti import errors
29
from ganeti import qlang
30
from ganeti import query
31

    
32
import testutils
33

    
34

    
35
class TestMakeSimpleFilter(unittest.TestCase):
36
  def _Test(self, field, names, expected, parse_exp=None):
37
    if parse_exp is None:
38
      parse_exp = names
39

    
40
    qfilter = qlang.MakeSimpleFilter(field, names)
41
    self.assertEqual(qfilter, expected)
42

    
43
  def test(self):
44
    self._Test("name", None, None, parse_exp=[])
45
    self._Test("name", [], None)
46
    self._Test("name", ["node1.example.com"],
47
               ["|", ["=", "name", "node1.example.com"]])
48
    self._Test("xyz", ["a", "b", "c"],
49
               ["|", ["=", "xyz", "a"], ["=", "xyz", "b"], ["=", "xyz", "c"]])
50

    
51

    
52
class TestParseFilter(unittest.TestCase):
53
  def setUp(self):
54
    self.parser = qlang.BuildFilterParser()
55

    
56
  def _Test(self, qfilter, expected, expect_filter=True):
57
    self.assertEqual(qlang.MakeFilter([qfilter], not expect_filter), expected)
58
    self.assertEqual(qlang.ParseFilter(qfilter, parser=self.parser), expected)
59

    
60
  def test(self):
61
    self._Test("name==\"foobar\"", [qlang.OP_EQUAL, "name", "foobar"])
62
    self._Test("name=='foobar'", [qlang.OP_EQUAL, "name", "foobar"])
63

    
64
    self._Test("valA==1 and valB==2 or valC==3",
65
               [qlang.OP_OR,
66
                [qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
67
                               [qlang.OP_EQUAL, "valB", 2]],
68
                [qlang.OP_EQUAL, "valC", 3]])
69

    
70
    self._Test(("(name\n==\"foobar\") and (xyz==\"va)ue\" and k == 256 or"
71
                " x ==\t\"y\"\n) and mc"),
72
               [qlang.OP_AND,
73
                [qlang.OP_EQUAL, "name", "foobar"],
74
                [qlang.OP_OR,
75
                 [qlang.OP_AND, [qlang.OP_EQUAL, "xyz", "va)ue"],
76
                                [qlang.OP_EQUAL, "k", 256]],
77
                 [qlang.OP_EQUAL, "x", "y"]],
78
                [qlang.OP_TRUE, "mc"]])
79

    
80
    self._Test("(xyz==\"v\" or k == 256 and x == \"y\")",
81
               [qlang.OP_OR,
82
                [qlang.OP_EQUAL, "xyz", "v"],
83
                [qlang.OP_AND, [qlang.OP_EQUAL, "k", 256],
84
                               [qlang.OP_EQUAL, "x", "y"]]])
85

    
86
    self._Test("valA==1 and valB==2 and valC==3",
87
               [qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
88
                              [qlang.OP_EQUAL, "valB", 2],
89
                              [qlang.OP_EQUAL, "valC", 3]])
90
    self._Test("master or field",
91
               [qlang.OP_OR, [qlang.OP_TRUE, "master"],
92
                             [qlang.OP_TRUE, "field"]])
93
    self._Test("mem == 128", [qlang.OP_EQUAL, "mem", 128])
94
    self._Test("negfield != -1", [qlang.OP_NOT_EQUAL, "negfield", -1])
95
    self._Test("master", [qlang.OP_TRUE, "master"],
96
               expect_filter=False)
97
    self._Test("not master", [qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
98
    for op in ["not", "and", "or"]:
99
      self._Test("%sxyz" % op, [qlang.OP_TRUE, "%sxyz" % op],
100
                 expect_filter=False)
101
      self._Test("not %sxyz" % op,
102
                 [qlang.OP_NOT, [qlang.OP_TRUE, "%sxyz" % op]])
103
      self._Test("  not \t%sfoo" % op,
104
                 [qlang.OP_NOT, [qlang.OP_TRUE, "%sfoo" % op]])
105
      self._Test("%sname =~ m/abc/" % op,
106
                 [qlang.OP_REGEXP, "%sname" % op, "abc"])
107
    self._Test("master and not other",
108
               [qlang.OP_AND, [qlang.OP_TRUE, "master"],
109
                              [qlang.OP_NOT, [qlang.OP_TRUE, "other"]]])
110
    self._Test("not (master or other == 4)",
111
               [qlang.OP_NOT,
112
                [qlang.OP_OR, [qlang.OP_TRUE, "master"],
113
                              [qlang.OP_EQUAL, "other", 4]]])
114
    self._Test("some==\"val\\\"ue\"", [qlang.OP_EQUAL, "some", "val\\\"ue"])
115
    self._Test("123 in ips", [qlang.OP_CONTAINS, "ips", 123])
116
    self._Test("99 not in ips", [qlang.OP_NOT, [qlang.OP_CONTAINS, "ips", 99]])
117
    self._Test("\"a\" in valA and \"b\" not in valB",
118
               [qlang.OP_AND, [qlang.OP_CONTAINS, "valA", "a"],
119
                              [qlang.OP_NOT, [qlang.OP_CONTAINS, "valB", "b"]]])
120

    
121
    self._Test("name =~ m/test/", [qlang.OP_REGEXP, "name", "test"])
122
    self._Test("name =~ m/^node.*example.com$/i",
123
               [qlang.OP_REGEXP, "name", "(?i)^node.*example.com$"])
124
    self._Test("(name =~ m/^node.*example.com$/s and master) or pip =~ |^3.*|",
125
               [qlang.OP_OR,
126
                [qlang.OP_AND,
127
                 [qlang.OP_REGEXP, "name", "(?s)^node.*example.com$"],
128
                 [qlang.OP_TRUE, "master"]],
129
                [qlang.OP_REGEXP, "pip", "^3.*"]])
130
    for flags in ["si", "is", "ssss", "iiiisiii"]:
131
      self._Test("name =~ m/gi/%s" % flags,
132
                 [qlang.OP_REGEXP, "name", "(?%s)gi" % "".join(sorted(flags))])
133

    
134
    for i in qlang._KNOWN_REGEXP_DELIM:
135
      self._Test("name =~ m%stest%s" % (i, i),
136
                 [qlang.OP_REGEXP, "name", "test"])
137
      self._Test("name !~ m%stest%s" % (i, i),
138
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
139
      self._Test("not\tname =~ m%stest%s" % (i, i),
140
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
141
      self._Test("notname =~ m%stest%s" % (i, i),
142
                 [qlang.OP_REGEXP, "notname", "test"])
143

    
144
    self._Test("name =* '*.site'",
145
               [qlang.OP_REGEXP, "name", utils.DnsNameGlobPattern("*.site")])
146
    self._Test("field !* '*.example.*'",
147
               [qlang.OP_NOT, [qlang.OP_REGEXP, "field",
148
                               utils.DnsNameGlobPattern("*.example.*")]])
149

    
150
  def testAllFields(self):
151
    for name in frozenset(i for d in query.ALL_FIELD_LISTS for i in d.keys()):
152
      self._Test("%s == \"value\"" % name, [qlang.OP_EQUAL, name, "value"])
153

    
154
  def testError(self):
155
    # Invalid field names, meaning no boolean check is done
156
    tests = ["#invalid!filter#", "m/x/,"]
157

    
158
    # Unknown regexp flag
159
    tests.append("name=~m#a#g")
160

    
161
    # Incomplete regexp group
162
    tests.append("name=~^[^")
163

    
164
    # Valid flag, but in uppercase
165
    tests.append("asdf =~ m|abc|I")
166

    
167
    # Non-matching regexp delimiters
168
    tests.append("name =~ /foobarbaz#")
169

    
170
    for qfilter in tests:
171
      try:
172
        qlang.ParseFilter(qfilter, parser=self.parser)
173
      except errors.QueryFilterParseError, err:
174
        self.assertEqual(len(err.GetDetails()), 3)
175
      else:
176
        self.fail("Invalid filter '%s' did not raise exception" % qfilter)
177

    
178

    
179
class TestMakeFilter(unittest.TestCase):
180
  def testNoNames(self):
181
    self.assertEqual(qlang.MakeFilter([], False), None)
182
    self.assertEqual(qlang.MakeFilter(None, False), None)
183

    
184
  def testPlainNames(self):
185
    self.assertEqual(qlang.MakeFilter(["web1", "web2"], False),
186
                     [qlang.OP_OR, [qlang.OP_EQUAL, "name", "web1"],
187
                                   [qlang.OP_EQUAL, "name", "web2"]])
188

    
189
  def testForcedFilter(self):
190
    for i in [None, [], ["1", "2"], ["", "", ""], ["a", "b", "c", "d"]]:
191
      self.assertRaises(errors.OpPrereqError, qlang.MakeFilter, i, True)
192

    
193
    # Glob pattern shouldn't parse as filter
194
    self.assertRaises(errors.QueryFilterParseError,
195
                      qlang.MakeFilter, ["*.site"], True)
196

    
197
    # Plain name parses as boolean filter
198
    self.assertEqual(qlang.MakeFilter(["web1"], True), [qlang.OP_TRUE, "web1"])
199

    
200
  def testFilter(self):
201
    self.assertEqual(qlang.MakeFilter(["foo/bar"], False),
202
                     [qlang.OP_TRUE, "foo/bar"])
203
    self.assertEqual(qlang.MakeFilter(["foo=='bar'"], False),
204
                     [qlang.OP_EQUAL, "foo", "bar"])
205
    self.assertEqual(qlang.MakeFilter(["field=*'*.site'"], False),
206
                     [qlang.OP_REGEXP, "field",
207
                      utils.DnsNameGlobPattern("*.site")])
208

    
209
    # Plain name parses as name filter, not boolean
210
    for name in ["node1", "n-o-d-e", "n_o_d_e", "node1.example.com",
211
                 "node1.example.com."]:
212
      self.assertEqual(qlang.MakeFilter([name], False),
213
                       [qlang.OP_OR, [qlang.OP_EQUAL, "name", name]])
214

    
215
    # Invalid filters
216
    for i in ["foo==bar", "foo+=1"]:
217
      self.assertRaises(errors.QueryFilterParseError,
218
                        qlang.MakeFilter, [i], False)
219

    
220
  def testGlob(self):
221
    self.assertEqual(qlang.MakeFilter(["*.site"], False),
222
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
223
                                    utils.DnsNameGlobPattern("*.site")]])
224
    self.assertEqual(qlang.MakeFilter(["web?.example"], False),
225
                     [qlang.OP_OR, [qlang.OP_REGEXP, "name",
226
                                    utils.DnsNameGlobPattern("web?.example")]])
227
    self.assertEqual(qlang.MakeFilter(["*.a", "*.b", "?.c"], False),
228
                     [qlang.OP_OR,
229
                      [qlang.OP_REGEXP, "name",
230
                       utils.DnsNameGlobPattern("*.a")],
231
                      [qlang.OP_REGEXP, "name",
232
                       utils.DnsNameGlobPattern("*.b")],
233
                      [qlang.OP_REGEXP, "name",
234
                       utils.DnsNameGlobPattern("?.c")]])
235

    
236

    
237
if __name__ == "__main__":
238
  testutils.GanetiTestProgram()