Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.qlang_unittest.py @ 16629d10

History | View | Annotate | Download (7.9 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
    self._Test("name =* '*.site'",
151
               [qlang.OP_REGEXP, "name", utils.DnsNameGlobPattern("*.site")])
152
    self._Test("field !* '*.example.*'",
153
               [qlang.OP_NOT, [qlang.OP_REGEXP, "field",
154
                               utils.DnsNameGlobPattern("*.example.*")]])
155

    
156
  def testAllFields(self):
157
    for name in frozenset(i for d in query.ALL_FIELD_LISTS for i in d.keys()):
158
      self._Test("%s == \"value\"" % name, [qlang.OP_EQUAL, name, "value"])
159

    
160
  def testError(self):
161
    # Invalid field names, meaning no boolean check is done
162
    tests = ["#invalid!filter#", "m/x/,"]
163

    
164
    # Unknown regexp flag
165
    tests.append("name=~m#a#g")
166

    
167
    # Incomplete regexp group
168
    tests.append("name=~^[^")
169

    
170
    # Valid flag, but in uppercase
171
    tests.append("asdf =~ m|abc|I")
172

    
173
    # Non-matching regexp delimiters
174
    tests.append("name =~ /foobarbaz#")
175

    
176
    for filter_ in tests:
177
      try:
178
        qlang.ParseFilter(filter_, parser=self.parser)
179
      except errors.QueryFilterParseError, err:
180
        self.assertEqual(len(err.GetDetails()), 3)
181
      else:
182
        self.fail("Invalid filter '%s' did not raise exception" % filter_)
183

    
184

    
185
class TestMaybeFilter(unittest.TestCase):
186
  def test(self):
187
    self.assertTrue(qlang.MaybeFilter(""))
188
    self.assertTrue(qlang.MaybeFilter("foo/bar"))
189
    self.assertTrue(qlang.MaybeFilter("foo==bar"))
190

    
191
    for i in set("()!~" + string.whitespace) | qlang.FILTER_DETECTION_CHARS:
192
      self.assertTrue(qlang.MaybeFilter(i),
193
                      msg="%r not recognized as filter" % i)
194

    
195
    self.assertFalse(qlang.MaybeFilter("node1"))
196
    self.assertFalse(qlang.MaybeFilter("n-o-d-e"))
197
    self.assertFalse(qlang.MaybeFilter("n_o_d_e"))
198
    self.assertFalse(qlang.MaybeFilter("node1.example.com"))
199
    self.assertFalse(qlang.MaybeFilter("node1.example.com."))
200

    
201

    
202
if __name__ == "__main__":
203
  testutils.GanetiTestProgram()