Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.qlang_unittest.py @ 08f8c82c

History | View | Annotate | Download (7.6 kB)

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

    
4
# Copyright (C) 2010 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
    filter_ = qlang.MakeSimpleFilter(field, names)
41
    self.assertEqual(filter_, 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, filter_, expected, expect_filter=True):
57
    if expect_filter:
58
      self.assertTrue(qlang.MaybeFilter(filter_),
59
                      msg="'%s' was not recognized as a filter" % filter_)
60
    else:
61
      self.assertFalse(qlang.MaybeFilter(filter_),
62
                       msg=("'%s' should not be recognized as a filter" %
63
                            filter_))
64
    self.assertEqual(qlang.ParseFilter(filter_, parser=self.parser), expected)
65

    
66
  def test(self):
67
    self._Test("name==\"foobar\"", [qlang.OP_EQUAL, "name", "foobar"])
68
    self._Test("name=='foobar'", [qlang.OP_EQUAL, "name", "foobar"])
69

    
70
    self._Test("valA==1 and valB==2 or valC==3",
71
               [qlang.OP_OR,
72
                [qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
73
                               [qlang.OP_EQUAL, "valB", 2]],
74
                [qlang.OP_EQUAL, "valC", 3]])
75

    
76
    self._Test(("(name\n==\"foobar\") and (xyz==\"va)ue\" and k == 256 or"
77
                " x ==\t\"y\"\n) and mc"),
78
               [qlang.OP_AND,
79
                [qlang.OP_EQUAL, "name", "foobar"],
80
                [qlang.OP_OR,
81
                 [qlang.OP_AND, [qlang.OP_EQUAL, "xyz", "va)ue"],
82
                                [qlang.OP_EQUAL, "k", 256]],
83
                 [qlang.OP_EQUAL, "x", "y"]],
84
                [qlang.OP_TRUE, "mc"]])
85

    
86
    self._Test("(xyz==\"v\" or k == 256 and x == \"y\")",
87
               [qlang.OP_OR,
88
                [qlang.OP_EQUAL, "xyz", "v"],
89
                [qlang.OP_AND, [qlang.OP_EQUAL, "k", 256],
90
                               [qlang.OP_EQUAL, "x", "y"]]])
91

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

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

    
140
    for i in qlang._KNOWN_REGEXP_DELIM:
141
      self._Test("name =~ m%stest%s" % (i, i),
142
                 [qlang.OP_REGEXP, "name", "test"])
143
      self._Test("name !~ m%stest%s" % (i, i),
144
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
145
      self._Test("not\tname =~ m%stest%s" % (i, i),
146
                 [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
147
      self._Test("notname =~ m%stest%s" % (i, i),
148
                 [qlang.OP_REGEXP, "notname", "test"])
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 filter_ in tests:
171
      try:
172
        qlang.ParseFilter(filter_, 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" % filter_)
177

    
178

    
179
class TestMaybeFilter(unittest.TestCase):
180
  def test(self):
181
    self.assertTrue(qlang.MaybeFilter(""))
182
    self.assertTrue(qlang.MaybeFilter("foo/bar"))
183
    self.assertTrue(qlang.MaybeFilter("foo==bar"))
184

    
185
    for i in set("()!~" + string.whitespace) | qlang.FILTER_DETECTION_CHARS:
186
      self.assertTrue(qlang.MaybeFilter(i),
187
                      msg="%r not recognized as filter" % i)
188

    
189
    self.assertFalse(qlang.MaybeFilter("node1"))
190
    self.assertFalse(qlang.MaybeFilter("n-o-d-e"))
191
    self.assertFalse(qlang.MaybeFilter("n_o_d_e"))
192
    self.assertFalse(qlang.MaybeFilter("node1.example.com"))
193
    self.assertFalse(qlang.MaybeFilter("node1.example.com."))
194

    
195

    
196
if __name__ == "__main__":
197
  testutils.GanetiTestProgram()