root / test / py / ganeti.cli_unittest.py @ da5f09ef
History | View | Annotate | Download (43.3 kB)
1 |
#!/usr/bin/python
|
---|---|
2 |
#
|
3 |
|
4 |
# Copyright (C) 2008, 2011, 2012, 2013 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 unittesting the cli module"""
|
23 |
|
24 |
import unittest |
25 |
import time |
26 |
from cStringIO import StringIO |
27 |
|
28 |
import ganeti |
29 |
import testutils |
30 |
|
31 |
from ganeti import constants |
32 |
from ganeti import cli |
33 |
from ganeti import errors |
34 |
from ganeti import utils |
35 |
from ganeti import objects |
36 |
from ganeti import qlang |
37 |
from ganeti.errors import OpPrereqError, ParameterError |
38 |
|
39 |
|
40 |
class TestParseTimespec(unittest.TestCase): |
41 |
"""Testing case for ParseTimespec"""
|
42 |
|
43 |
def testValidTimes(self): |
44 |
"""Test valid timespecs"""
|
45 |
test_data = [ |
46 |
("1s", 1), |
47 |
("1", 1), |
48 |
("1m", 60), |
49 |
("1h", 60 * 60), |
50 |
("1d", 60 * 60 * 24), |
51 |
("1w", 60 * 60 * 24 * 7), |
52 |
("4h", 4 * 60 * 60), |
53 |
("61m", 61 * 60), |
54 |
] |
55 |
for value, expected_result in test_data: |
56 |
self.failUnlessEqual(cli.ParseTimespec(value), expected_result)
|
57 |
|
58 |
def testInvalidTime(self): |
59 |
"""Test invalid timespecs"""
|
60 |
test_data = [ |
61 |
"1y",
|
62 |
"",
|
63 |
"aaa",
|
64 |
"s",
|
65 |
] |
66 |
for value in test_data: |
67 |
self.failUnlessRaises(OpPrereqError, cli.ParseTimespec, value)
|
68 |
|
69 |
|
70 |
class TestSplitKeyVal(unittest.TestCase): |
71 |
"""Testing case for cli._SplitKeyVal"""
|
72 |
DATA = "a=b,c,no_d,-e"
|
73 |
RESULT = {"a": "b", "c": True, "d": False, "e": None} |
74 |
|
75 |
def testSplitKeyVal(self): |
76 |
"""Test splitting"""
|
77 |
self.failUnlessEqual(cli._SplitKeyVal("option", self.DATA), self.RESULT) |
78 |
|
79 |
def testDuplicateParam(self): |
80 |
"""Test duplicate parameters"""
|
81 |
for data in ("a=1,a=2", "a,no_a"): |
82 |
self.failUnlessRaises(ParameterError, cli._SplitKeyVal,
|
83 |
"option", data)
|
84 |
|
85 |
def testEmptyData(self): |
86 |
"""Test how we handle splitting an empty string"""
|
87 |
self.failUnlessEqual(cli._SplitKeyVal("option", ""), {}) |
88 |
|
89 |
|
90 |
class TestIdentKeyVal(unittest.TestCase): |
91 |
"""Testing case for cli.check_ident_key_val"""
|
92 |
|
93 |
def testIdentKeyVal(self): |
94 |
"""Test identkeyval"""
|
95 |
def cikv(value): |
96 |
return cli.check_ident_key_val("option", "opt", value) |
97 |
|
98 |
self.assertEqual(cikv("foo:bar"), ("foo", {"bar": True})) |
99 |
self.assertEqual(cikv("foo:bar=baz"), ("foo", {"bar": "baz"})) |
100 |
self.assertEqual(cikv("bar:b=c,c=a"), ("bar", {"b": "c", "c": "a"})) |
101 |
self.assertEqual(cikv("no_bar"), ("bar", False)) |
102 |
self.assertRaises(ParameterError, cikv, "no_bar:foo") |
103 |
self.assertRaises(ParameterError, cikv, "no_bar:foo=baz") |
104 |
self.assertEqual(cikv("-foo"), ("foo", None)) |
105 |
self.assertRaises(ParameterError, cikv, "-foo:a=c") |
106 |
|
107 |
# Check negative numbers
|
108 |
self.assertEqual(cikv("-1:remove"), ("-1", { |
109 |
"remove": True, |
110 |
})) |
111 |
self.assertEqual(cikv("-29447:add,size=4G"), ("-29447", { |
112 |
"add": True, |
113 |
"size": "4G", |
114 |
})) |
115 |
for i in ["-:", "-"]: |
116 |
self.assertEqual(cikv(i), ("", None)) |
117 |
|
118 |
|
119 |
class TestToStream(unittest.TestCase): |
120 |
"""Test the ToStream functions"""
|
121 |
|
122 |
def testBasic(self): |
123 |
for data in ["foo", |
124 |
"foo %s",
|
125 |
"foo %(test)s",
|
126 |
"foo %s %s",
|
127 |
"",
|
128 |
]: |
129 |
buf = StringIO() |
130 |
cli._ToStream(buf, data) |
131 |
self.failUnlessEqual(buf.getvalue(), data + "\n") |
132 |
|
133 |
def testParams(self): |
134 |
buf = StringIO() |
135 |
cli._ToStream(buf, "foo %s", 1) |
136 |
self.failUnlessEqual(buf.getvalue(), "foo 1\n") |
137 |
buf = StringIO() |
138 |
cli._ToStream(buf, "foo %s", (15,16)) |
139 |
self.failUnlessEqual(buf.getvalue(), "foo (15, 16)\n") |
140 |
buf = StringIO() |
141 |
cli._ToStream(buf, "foo %s %s", "a", "b") |
142 |
self.failUnlessEqual(buf.getvalue(), "foo a b\n") |
143 |
|
144 |
|
145 |
class TestGenerateTable(unittest.TestCase): |
146 |
HEADERS = dict([("f%s" % i, "Field%s" % i) for i in range(5)]) |
147 |
|
148 |
FIELDS1 = ["f1", "f2"] |
149 |
DATA1 = [ |
150 |
["abc", 1234], |
151 |
["foobar", 56], |
152 |
["b", -14], |
153 |
] |
154 |
|
155 |
def _test(self, headers, fields, separator, data, |
156 |
numfields, unitfields, units, expected): |
157 |
table = cli.GenerateTable(headers, fields, separator, data, |
158 |
numfields=numfields, unitfields=unitfields, |
159 |
units=units) |
160 |
self.assertEqual(table, expected)
|
161 |
|
162 |
def testPlain(self): |
163 |
exp = [ |
164 |
"Field1 Field2",
|
165 |
"abc 1234",
|
166 |
"foobar 56",
|
167 |
"b -14",
|
168 |
] |
169 |
self._test(self.HEADERS, self.FIELDS1, None, self.DATA1, |
170 |
None, None, "m", exp) |
171 |
|
172 |
def testNoFields(self): |
173 |
self._test(self.HEADERS, [], None, [[], []], |
174 |
None, None, "m", ["", "", ""]) |
175 |
self._test(None, [], None, [[], []], |
176 |
None, None, "m", ["", ""]) |
177 |
|
178 |
def testSeparator(self): |
179 |
for sep in ["#", ":", ",", "^", "!", "%", "|", "###", "%%", "!!!", "||"]: |
180 |
exp = [ |
181 |
"Field1%sField2" % sep,
|
182 |
"abc%s1234" % sep,
|
183 |
"foobar%s56" % sep,
|
184 |
"b%s-14" % sep,
|
185 |
] |
186 |
self._test(self.HEADERS, self.FIELDS1, sep, self.DATA1, |
187 |
None, None, "m", exp) |
188 |
|
189 |
def testNoHeader(self): |
190 |
exp = [ |
191 |
"abc 1234",
|
192 |
"foobar 56",
|
193 |
"b -14",
|
194 |
] |
195 |
self._test(None, self.FIELDS1, None, self.DATA1, |
196 |
None, None, "m", exp) |
197 |
|
198 |
def testUnknownField(self): |
199 |
headers = { |
200 |
"f1": "Field1", |
201 |
} |
202 |
exp = [ |
203 |
"Field1 UNKNOWN",
|
204 |
"abc 1234",
|
205 |
"foobar 56",
|
206 |
"b -14",
|
207 |
] |
208 |
self._test(headers, ["f1", "UNKNOWN"], None, self.DATA1, |
209 |
None, None, "m", exp) |
210 |
|
211 |
def testNumfields(self): |
212 |
fields = ["f1", "f2", "f3"] |
213 |
data = [ |
214 |
["abc", 1234, 0], |
215 |
["foobar", 56, 3], |
216 |
["b", -14, "-"], |
217 |
] |
218 |
exp = [ |
219 |
"Field1 Field2 Field3",
|
220 |
"abc 1234 0",
|
221 |
"foobar 56 3",
|
222 |
"b -14 -",
|
223 |
] |
224 |
self._test(self.HEADERS, fields, None, data, |
225 |
["f2", "f3"], None, "m", exp) |
226 |
|
227 |
def testUnitfields(self): |
228 |
expnosep = [ |
229 |
"Field1 Field2 Field3",
|
230 |
"abc 1234 0M",
|
231 |
"foobar 56 3M",
|
232 |
"b -14 -",
|
233 |
] |
234 |
|
235 |
expsep = [ |
236 |
"Field1:Field2:Field3",
|
237 |
"abc:1234:0M",
|
238 |
"foobar:56:3M",
|
239 |
"b:-14:-",
|
240 |
] |
241 |
|
242 |
for sep, expected in [(None, expnosep), (":", expsep)]: |
243 |
fields = ["f1", "f2", "f3"] |
244 |
data = [ |
245 |
["abc", 1234, 0], |
246 |
["foobar", 56, 3], |
247 |
["b", -14, "-"], |
248 |
] |
249 |
self._test(self.HEADERS, fields, sep, data, |
250 |
["f2", "f3"], ["f3"], "h", expected) |
251 |
|
252 |
def testUnusual(self): |
253 |
data = [ |
254 |
["%", "xyz"], |
255 |
["%%", "abc"], |
256 |
] |
257 |
exp = [ |
258 |
"Field1 Field2",
|
259 |
"% xyz",
|
260 |
"%% abc",
|
261 |
] |
262 |
self._test(self.HEADERS, ["f1", "f2"], None, data, |
263 |
None, None, "m", exp) |
264 |
|
265 |
|
266 |
class TestFormatQueryResult(unittest.TestCase): |
267 |
def test(self): |
268 |
fields = [ |
269 |
objects.QueryFieldDefinition(name="name", title="Name", |
270 |
kind=constants.QFT_TEXT), |
271 |
objects.QueryFieldDefinition(name="size", title="Size", |
272 |
kind=constants.QFT_NUMBER), |
273 |
objects.QueryFieldDefinition(name="act", title="Active", |
274 |
kind=constants.QFT_BOOL), |
275 |
objects.QueryFieldDefinition(name="mem", title="Memory", |
276 |
kind=constants.QFT_UNIT), |
277 |
objects.QueryFieldDefinition(name="other", title="SomeList", |
278 |
kind=constants.QFT_OTHER), |
279 |
] |
280 |
|
281 |
response = objects.QueryResponse(fields=fields, data=[ |
282 |
[(constants.RS_NORMAL, "nodeA"), (constants.RS_NORMAL, 128), |
283 |
(constants.RS_NORMAL, False), (constants.RS_NORMAL, 1468006), |
284 |
(constants.RS_NORMAL, [])], |
285 |
[(constants.RS_NORMAL, "other"), (constants.RS_NORMAL, 512), |
286 |
(constants.RS_NORMAL, True), (constants.RS_NORMAL, 16), |
287 |
(constants.RS_NORMAL, [1, 2, 3])], |
288 |
[(constants.RS_NORMAL, "xyz"), (constants.RS_NORMAL, 1024), |
289 |
(constants.RS_NORMAL, True), (constants.RS_NORMAL, 4096), |
290 |
(constants.RS_NORMAL, [{}, {}])], |
291 |
]) |
292 |
|
293 |
self.assertEqual(cli.FormatQueryResult(response, unit="h", header=True), |
294 |
(cli.QR_NORMAL, [ |
295 |
"Name Size Active Memory SomeList",
|
296 |
"nodeA 128 N 1.4T []",
|
297 |
"other 512 Y 16M [1, 2, 3]",
|
298 |
"xyz 1024 Y 4.0G [{}, {}]",
|
299 |
])) |
300 |
|
301 |
def testTimestampAndUnit(self): |
302 |
fields = [ |
303 |
objects.QueryFieldDefinition(name="name", title="Name", |
304 |
kind=constants.QFT_TEXT), |
305 |
objects.QueryFieldDefinition(name="size", title="Size", |
306 |
kind=constants.QFT_UNIT), |
307 |
objects.QueryFieldDefinition(name="mtime", title="ModTime", |
308 |
kind=constants.QFT_TIMESTAMP), |
309 |
] |
310 |
|
311 |
response = objects.QueryResponse(fields=fields, data=[ |
312 |
[(constants.RS_NORMAL, "a"), (constants.RS_NORMAL, 1024), |
313 |
(constants.RS_NORMAL, 0)],
|
314 |
[(constants.RS_NORMAL, "b"), (constants.RS_NORMAL, 144996), |
315 |
(constants.RS_NORMAL, 1291746295)],
|
316 |
]) |
317 |
|
318 |
self.assertEqual(cli.FormatQueryResult(response, unit="m", header=True), |
319 |
(cli.QR_NORMAL, [ |
320 |
"Name Size ModTime",
|
321 |
"a 1024 %s" % utils.FormatTime(0), |
322 |
"b 144996 %s" % utils.FormatTime(1291746295), |
323 |
])) |
324 |
|
325 |
def testOverride(self): |
326 |
fields = [ |
327 |
objects.QueryFieldDefinition(name="name", title="Name", |
328 |
kind=constants.QFT_TEXT), |
329 |
objects.QueryFieldDefinition(name="cust", title="Custom", |
330 |
kind=constants.QFT_OTHER), |
331 |
objects.QueryFieldDefinition(name="xt", title="XTime", |
332 |
kind=constants.QFT_TIMESTAMP), |
333 |
] |
334 |
|
335 |
response = objects.QueryResponse(fields=fields, data=[ |
336 |
[(constants.RS_NORMAL, "x"), (constants.RS_NORMAL, ["a", "b", "c"]), |
337 |
(constants.RS_NORMAL, 1234)],
|
338 |
[(constants.RS_NORMAL, "y"), (constants.RS_NORMAL, range(10)), |
339 |
(constants.RS_NORMAL, 1291746295)],
|
340 |
]) |
341 |
|
342 |
override = { |
343 |
"cust": (utils.CommaJoin, False), |
344 |
"xt": (hex, True), |
345 |
} |
346 |
|
347 |
self.assertEqual(cli.FormatQueryResult(response, unit="h", header=True, |
348 |
format_override=override), |
349 |
(cli.QR_NORMAL, [ |
350 |
"Name Custom XTime",
|
351 |
"x a, b, c 0x4d2",
|
352 |
"y 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 0x4cfe7bf7",
|
353 |
])) |
354 |
|
355 |
def testSeparator(self): |
356 |
fields = [ |
357 |
objects.QueryFieldDefinition(name="name", title="Name", |
358 |
kind=constants.QFT_TEXT), |
359 |
objects.QueryFieldDefinition(name="count", title="Count", |
360 |
kind=constants.QFT_NUMBER), |
361 |
objects.QueryFieldDefinition(name="desc", title="Description", |
362 |
kind=constants.QFT_TEXT), |
363 |
] |
364 |
|
365 |
response = objects.QueryResponse(fields=fields, data=[ |
366 |
[(constants.RS_NORMAL, "instance1.example.com"),
|
367 |
(constants.RS_NORMAL, 21125), (constants.RS_NORMAL, "Hello World!")], |
368 |
[(constants.RS_NORMAL, "mail.other.net"),
|
369 |
(constants.RS_NORMAL, -9000), (constants.RS_NORMAL, "a,b,c")], |
370 |
]) |
371 |
|
372 |
for sep in [":", "|", "#", "|||", "###", "@@@", "@#@"]: |
373 |
for header in [None, "Name%sCount%sDescription" % (sep, sep)]: |
374 |
exp = [] |
375 |
if header:
|
376 |
exp.append(header) |
377 |
exp.extend([ |
378 |
"instance1.example.com%s21125%sHello World!" % (sep, sep),
|
379 |
"mail.other.net%s-9000%sa,b,c" % (sep, sep),
|
380 |
]) |
381 |
|
382 |
self.assertEqual(cli.FormatQueryResult(response, separator=sep,
|
383 |
header=bool(header)),
|
384 |
(cli.QR_NORMAL, exp)) |
385 |
|
386 |
def testStatusWithUnknown(self): |
387 |
fields = [ |
388 |
objects.QueryFieldDefinition(name="id", title="ID", |
389 |
kind=constants.QFT_NUMBER), |
390 |
objects.QueryFieldDefinition(name="unk", title="unk", |
391 |
kind=constants.QFT_UNKNOWN), |
392 |
objects.QueryFieldDefinition(name="unavail", title="Unavail", |
393 |
kind=constants.QFT_BOOL), |
394 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
395 |
kind=constants.QFT_TEXT), |
396 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
397 |
kind=constants.QFT_TEXT), |
398 |
] |
399 |
|
400 |
response = objects.QueryResponse(fields=fields, data=[ |
401 |
[(constants.RS_NORMAL, 1), (constants.RS_UNKNOWN, None), |
402 |
(constants.RS_NORMAL, False), (constants.RS_NORMAL, ""), |
403 |
(constants.RS_OFFLINE, None)],
|
404 |
[(constants.RS_NORMAL, 2), (constants.RS_UNKNOWN, None), |
405 |
(constants.RS_NODATA, None), (constants.RS_NORMAL, "x"), |
406 |
(constants.RS_OFFLINE, None)],
|
407 |
[(constants.RS_NORMAL, 3), (constants.RS_UNKNOWN, None), |
408 |
(constants.RS_NORMAL, False), (constants.RS_UNAVAIL, None), |
409 |
(constants.RS_OFFLINE, None)],
|
410 |
]) |
411 |
|
412 |
self.assertEqual(cli.FormatQueryResult(response, header=True, |
413 |
separator="|", verbose=True), |
414 |
(cli.QR_UNKNOWN, [ |
415 |
"ID|unk|Unavail|NoData|OffLine",
|
416 |
"1|(unknown)|N||(offline)",
|
417 |
"2|(unknown)|(nodata)|x|(offline)",
|
418 |
"3|(unknown)|N|(unavail)|(offline)",
|
419 |
])) |
420 |
self.assertEqual(cli.FormatQueryResult(response, header=True, |
421 |
separator="|", verbose=False), |
422 |
(cli.QR_UNKNOWN, [ |
423 |
"ID|unk|Unavail|NoData|OffLine",
|
424 |
"1|??|N||*",
|
425 |
"2|??|?|x|*",
|
426 |
"3|??|N|-|*",
|
427 |
])) |
428 |
|
429 |
def testNoData(self): |
430 |
fields = [ |
431 |
objects.QueryFieldDefinition(name="id", title="ID", |
432 |
kind=constants.QFT_NUMBER), |
433 |
objects.QueryFieldDefinition(name="name", title="Name", |
434 |
kind=constants.QFT_TEXT), |
435 |
] |
436 |
|
437 |
response = objects.QueryResponse(fields=fields, data=[]) |
438 |
|
439 |
self.assertEqual(cli.FormatQueryResult(response, header=True), |
440 |
(cli.QR_NORMAL, ["ID Name"]))
|
441 |
|
442 |
def testNoDataWithUnknown(self): |
443 |
fields = [ |
444 |
objects.QueryFieldDefinition(name="id", title="ID", |
445 |
kind=constants.QFT_NUMBER), |
446 |
objects.QueryFieldDefinition(name="unk", title="unk", |
447 |
kind=constants.QFT_UNKNOWN), |
448 |
] |
449 |
|
450 |
response = objects.QueryResponse(fields=fields, data=[]) |
451 |
|
452 |
self.assertEqual(cli.FormatQueryResult(response, header=False), |
453 |
(cli.QR_UNKNOWN, [])) |
454 |
|
455 |
def testStatus(self): |
456 |
fields = [ |
457 |
objects.QueryFieldDefinition(name="id", title="ID", |
458 |
kind=constants.QFT_NUMBER), |
459 |
objects.QueryFieldDefinition(name="unavail", title="Unavail", |
460 |
kind=constants.QFT_BOOL), |
461 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
462 |
kind=constants.QFT_TEXT), |
463 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
464 |
kind=constants.QFT_TEXT), |
465 |
] |
466 |
|
467 |
response = objects.QueryResponse(fields=fields, data=[ |
468 |
[(constants.RS_NORMAL, 1), (constants.RS_NORMAL, False), |
469 |
(constants.RS_NORMAL, ""), (constants.RS_OFFLINE, None)], |
470 |
[(constants.RS_NORMAL, 2), (constants.RS_NODATA, None), |
471 |
(constants.RS_NORMAL, "x"), (constants.RS_NORMAL, "abc")], |
472 |
[(constants.RS_NORMAL, 3), (constants.RS_NORMAL, False), |
473 |
(constants.RS_UNAVAIL, None), (constants.RS_OFFLINE, None)], |
474 |
]) |
475 |
|
476 |
self.assertEqual(cli.FormatQueryResult(response, header=False, |
477 |
separator="|", verbose=True), |
478 |
(cli.QR_INCOMPLETE, [ |
479 |
"1|N||(offline)",
|
480 |
"2|(nodata)|x|abc",
|
481 |
"3|N|(unavail)|(offline)",
|
482 |
])) |
483 |
self.assertEqual(cli.FormatQueryResult(response, header=False, |
484 |
separator="|", verbose=False), |
485 |
(cli.QR_INCOMPLETE, [ |
486 |
"1|N||*",
|
487 |
"2|?|x|abc",
|
488 |
"3|N|-|*",
|
489 |
])) |
490 |
|
491 |
def testInvalidFieldType(self): |
492 |
fields = [ |
493 |
objects.QueryFieldDefinition(name="x", title="x", |
494 |
kind="#some#other#type"),
|
495 |
] |
496 |
|
497 |
response = objects.QueryResponse(fields=fields, data=[]) |
498 |
|
499 |
self.assertRaises(NotImplementedError, cli.FormatQueryResult, response) |
500 |
|
501 |
def testInvalidFieldStatus(self): |
502 |
fields = [ |
503 |
objects.QueryFieldDefinition(name="x", title="x", |
504 |
kind=constants.QFT_TEXT), |
505 |
] |
506 |
|
507 |
response = objects.QueryResponse(fields=fields, data=[[(-1, None)]]) |
508 |
self.assertRaises(NotImplementedError, cli.FormatQueryResult, response) |
509 |
|
510 |
response = objects.QueryResponse(fields=fields, data=[[(-1, "x")]]) |
511 |
self.assertRaises(AssertionError, cli.FormatQueryResult, response) |
512 |
|
513 |
def testEmptyFieldTitle(self): |
514 |
fields = [ |
515 |
objects.QueryFieldDefinition(name="x", title="", |
516 |
kind=constants.QFT_TEXT), |
517 |
] |
518 |
|
519 |
response = objects.QueryResponse(fields=fields, data=[]) |
520 |
self.assertRaises(AssertionError, cli.FormatQueryResult, response) |
521 |
|
522 |
|
523 |
class _MockJobPollCb(cli.JobPollCbBase, cli.JobPollReportCbBase): |
524 |
def __init__(self, tc, job_id): |
525 |
self.tc = tc
|
526 |
self.job_id = job_id
|
527 |
self._wfjcr = []
|
528 |
self._jobstatus = []
|
529 |
self._expect_notchanged = False |
530 |
self._expect_log = []
|
531 |
|
532 |
def CheckEmpty(self): |
533 |
self.tc.assertFalse(self._wfjcr) |
534 |
self.tc.assertFalse(self._jobstatus) |
535 |
self.tc.assertFalse(self._expect_notchanged) |
536 |
self.tc.assertFalse(self._expect_log) |
537 |
|
538 |
def AddWfjcResult(self, *args): |
539 |
self._wfjcr.append(args)
|
540 |
|
541 |
def AddQueryJobsResult(self, *args): |
542 |
self._jobstatus.append(args)
|
543 |
|
544 |
def WaitForJobChangeOnce(self, job_id, fields, |
545 |
prev_job_info, prev_log_serial): |
546 |
self.tc.assertEqual(job_id, self.job_id) |
547 |
self.tc.assertEqualValues(fields, ["status"]) |
548 |
self.tc.assertFalse(self._expect_notchanged) |
549 |
self.tc.assertFalse(self._expect_log) |
550 |
|
551 |
(exp_prev_job_info, exp_prev_log_serial, result) = self._wfjcr.pop(0) |
552 |
self.tc.assertEqualValues(prev_job_info, exp_prev_job_info)
|
553 |
self.tc.assertEqual(prev_log_serial, exp_prev_log_serial)
|
554 |
|
555 |
if result == constants.JOB_NOTCHANGED:
|
556 |
self._expect_notchanged = True |
557 |
elif result:
|
558 |
(_, logmsgs) = result |
559 |
if logmsgs:
|
560 |
self._expect_log.extend(logmsgs)
|
561 |
|
562 |
return result
|
563 |
|
564 |
def QueryJobs(self, job_ids, fields): |
565 |
self.tc.assertEqual(job_ids, [self.job_id]) |
566 |
self.tc.assertEqualValues(fields, ["status", "opstatus", "opresult"]) |
567 |
self.tc.assertFalse(self._expect_notchanged) |
568 |
self.tc.assertFalse(self._expect_log) |
569 |
|
570 |
result = self._jobstatus.pop(0) |
571 |
self.tc.assertEqual(len(fields), len(result)) |
572 |
return [result]
|
573 |
|
574 |
def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg): |
575 |
self.tc.assertEqual(job_id, self.job_id) |
576 |
self.tc.assertEqualValues((serial, timestamp, log_type, log_msg),
|
577 |
self._expect_log.pop(0)) |
578 |
|
579 |
def ReportNotChanged(self, job_id, status): |
580 |
self.tc.assertEqual(job_id, self.job_id) |
581 |
self.tc.assert_(self._expect_notchanged) |
582 |
self._expect_notchanged = False |
583 |
|
584 |
|
585 |
class TestGenericPollJob(testutils.GanetiTestCase): |
586 |
def testSuccessWithLog(self): |
587 |
job_id = 29609
|
588 |
cbs = _MockJobPollCb(self, job_id)
|
589 |
|
590 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
591 |
|
592 |
cbs.AddWfjcResult(None, None, |
593 |
((constants.JOB_STATUS_QUEUED, ), None))
|
594 |
|
595 |
cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
|
596 |
constants.JOB_NOTCHANGED) |
597 |
|
598 |
cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
|
599 |
((constants.JOB_STATUS_RUNNING, ), |
600 |
[(1, utils.SplitTime(1273491611.0), |
601 |
constants.ELOG_MESSAGE, "Step 1"),
|
602 |
(2, utils.SplitTime(1273491615.9), |
603 |
constants.ELOG_MESSAGE, "Step 2"),
|
604 |
(3, utils.SplitTime(1273491625.02), |
605 |
constants.ELOG_MESSAGE, "Step 3"),
|
606 |
(4, utils.SplitTime(1273491635.05), |
607 |
constants.ELOG_MESSAGE, "Step 4"),
|
608 |
(37, utils.SplitTime(1273491645.0), |
609 |
constants.ELOG_MESSAGE, "Step 5"),
|
610 |
(203, utils.SplitTime(127349155.0), |
611 |
constants.ELOG_MESSAGE, "Step 6")]))
|
612 |
|
613 |
cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 203,
|
614 |
((constants.JOB_STATUS_RUNNING, ), |
615 |
[(300, utils.SplitTime(1273491711.01), |
616 |
constants.ELOG_MESSAGE, "Step X"),
|
617 |
(302, utils.SplitTime(1273491815.8), |
618 |
constants.ELOG_MESSAGE, "Step Y"),
|
619 |
(303, utils.SplitTime(1273491925.32), |
620 |
constants.ELOG_MESSAGE, "Step Z")]))
|
621 |
|
622 |
cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 303,
|
623 |
((constants.JOB_STATUS_SUCCESS, ), None))
|
624 |
|
625 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_SUCCESS, |
626 |
[constants.OP_STATUS_SUCCESS, |
627 |
constants.OP_STATUS_SUCCESS], |
628 |
["Hello World", "Foo man bar"]) |
629 |
|
630 |
self.assertEqual(["Hello World", "Foo man bar"], |
631 |
cli.GenericPollJob(job_id, cbs, cbs)) |
632 |
cbs.CheckEmpty() |
633 |
|
634 |
def testJobLost(self): |
635 |
job_id = 13746
|
636 |
|
637 |
cbs = _MockJobPollCb(self, job_id)
|
638 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
639 |
cbs.AddWfjcResult(None, None, None) |
640 |
self.assertRaises(errors.JobLost, cli.GenericPollJob, job_id, cbs, cbs)
|
641 |
cbs.CheckEmpty() |
642 |
|
643 |
def testError(self): |
644 |
job_id = 31088
|
645 |
|
646 |
cbs = _MockJobPollCb(self, job_id)
|
647 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
648 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
649 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
650 |
[constants.OP_STATUS_SUCCESS, |
651 |
constants.OP_STATUS_ERROR], |
652 |
["Hello World", "Error code 123"]) |
653 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
654 |
cbs.CheckEmpty() |
655 |
|
656 |
def testError2(self): |
657 |
job_id = 22235
|
658 |
|
659 |
cbs = _MockJobPollCb(self, job_id)
|
660 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
661 |
encexc = errors.EncodeException(errors.LockError("problem"))
|
662 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
663 |
[constants.OP_STATUS_ERROR], [encexc]) |
664 |
self.assertRaises(errors.LockError, cli.GenericPollJob, job_id, cbs, cbs)
|
665 |
cbs.CheckEmpty() |
666 |
|
667 |
def testWeirdError(self): |
668 |
job_id = 28847
|
669 |
|
670 |
cbs = _MockJobPollCb(self, job_id)
|
671 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
672 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
673 |
[constants.OP_STATUS_RUNNING, |
674 |
constants.OP_STATUS_RUNNING], |
675 |
[None, None]) |
676 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
677 |
cbs.CheckEmpty() |
678 |
|
679 |
def testCancel(self): |
680 |
job_id = 4275
|
681 |
|
682 |
cbs = _MockJobPollCb(self, job_id)
|
683 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
684 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_CANCELING, ), None)) |
685 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_CANCELING, |
686 |
[constants.OP_STATUS_CANCELING, |
687 |
constants.OP_STATUS_CANCELING], |
688 |
[None, None]) |
689 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
690 |
cbs.CheckEmpty() |
691 |
|
692 |
|
693 |
class TestFormatLogMessage(unittest.TestCase): |
694 |
def test(self): |
695 |
self.assertEqual(cli.FormatLogMessage(constants.ELOG_MESSAGE,
|
696 |
"Hello World"),
|
697 |
"Hello World")
|
698 |
self.assertRaises(TypeError, cli.FormatLogMessage, |
699 |
constants.ELOG_MESSAGE, [1, 2, 3]) |
700 |
|
701 |
self.assert_(cli.FormatLogMessage("some other type", (1, 2, 3))) |
702 |
|
703 |
|
704 |
class TestParseFields(unittest.TestCase): |
705 |
def test(self): |
706 |
self.assertEqual(cli.ParseFields(None, []), []) |
707 |
self.assertEqual(cli.ParseFields("name,foo,hello", []), |
708 |
["name", "foo", "hello"]) |
709 |
self.assertEqual(cli.ParseFields(None, ["def", "ault", "fields", "here"]), |
710 |
["def", "ault", "fields", "here"]) |
711 |
self.assertEqual(cli.ParseFields("name,foo", ["def", "ault"]), |
712 |
["name", "foo"]) |
713 |
self.assertEqual(cli.ParseFields("+name,foo", ["def", "ault"]), |
714 |
["def", "ault", "name", "foo"]) |
715 |
|
716 |
|
717 |
class TestConstants(unittest.TestCase): |
718 |
def testPriority(self): |
719 |
self.assertEqual(set(cli._PRIONAME_TO_VALUE.values()), |
720 |
set(constants.OP_PRIO_SUBMIT_VALID))
|
721 |
self.assertEqual(list(value for _, value in cli._PRIORITY_NAMES), |
722 |
sorted(constants.OP_PRIO_SUBMIT_VALID, reverse=True)) |
723 |
|
724 |
|
725 |
class TestParseNicOption(unittest.TestCase): |
726 |
def test(self): |
727 |
self.assertEqual(cli.ParseNicOption([("0", { "link": "eth0", })]), |
728 |
[{ "link": "eth0", }]) |
729 |
self.assertEqual(cli.ParseNicOption([("5", { "ip": "192.0.2.7", })]), |
730 |
[{}, {}, {}, {}, {}, { "ip": "192.0.2.7", }]) |
731 |
|
732 |
def testErrors(self): |
733 |
for i in [None, "", "abc", "zero", "Hello World", "\0", []]: |
734 |
self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
|
735 |
[(i, { "link": "eth0", })]) |
736 |
self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
|
737 |
[("0", i)])
|
738 |
|
739 |
self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
|
740 |
[(0, { True: False, })]) |
741 |
|
742 |
self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
|
743 |
[(3, { "mode": [], })]) |
744 |
|
745 |
|
746 |
class TestFormatResultError(unittest.TestCase): |
747 |
def testNormal(self): |
748 |
for verbose in [False, True]: |
749 |
self.assertRaises(AssertionError, cli.FormatResultError, |
750 |
constants.RS_NORMAL, verbose) |
751 |
|
752 |
def testUnknown(self): |
753 |
for verbose in [False, True]: |
754 |
self.assertRaises(NotImplementedError, cli.FormatResultError, |
755 |
"#some!other!status#", verbose)
|
756 |
|
757 |
def test(self): |
758 |
for status in constants.RS_ALL: |
759 |
if status == constants.RS_NORMAL:
|
760 |
continue
|
761 |
|
762 |
self.assertNotEqual(cli.FormatResultError(status, False), |
763 |
cli.FormatResultError(status, True))
|
764 |
|
765 |
result = cli.FormatResultError(status, True)
|
766 |
self.assertTrue(result.startswith("(")) |
767 |
self.assertTrue(result.endswith(")")) |
768 |
|
769 |
|
770 |
class TestGetOnlineNodes(unittest.TestCase): |
771 |
class _FakeClient: |
772 |
def __init__(self): |
773 |
self._query = []
|
774 |
|
775 |
def AddQueryResult(self, *args): |
776 |
self._query.append(args)
|
777 |
|
778 |
def CountPending(self): |
779 |
return len(self._query) |
780 |
|
781 |
def Query(self, res, fields, qfilter): |
782 |
if res != constants.QR_NODE:
|
783 |
raise Exception("Querying wrong resource") |
784 |
|
785 |
(exp_fields, check_filter, result) = self._query.pop(0) |
786 |
|
787 |
if exp_fields != fields:
|
788 |
raise Exception("Expected fields %s, got %s" % (exp_fields, fields)) |
789 |
|
790 |
if not (qfilter is None or check_filter(qfilter)): |
791 |
raise Exception("Filter doesn't match expectations") |
792 |
|
793 |
return objects.QueryResponse(fields=None, data=result) |
794 |
|
795 |
def testEmpty(self): |
796 |
cl = self._FakeClient()
|
797 |
|
798 |
cl.AddQueryResult(["name", "offline", "sip"], None, []) |
799 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl), []) |
800 |
self.assertEqual(cl.CountPending(), 0) |
801 |
|
802 |
def testNoSpecialFilter(self): |
803 |
cl = self._FakeClient()
|
804 |
|
805 |
cl.AddQueryResult(["name", "offline", "sip"], None, [ |
806 |
[(constants.RS_NORMAL, "master.example.com"),
|
807 |
(constants.RS_NORMAL, False),
|
808 |
(constants.RS_NORMAL, "192.0.2.1")],
|
809 |
[(constants.RS_NORMAL, "node2.example.com"),
|
810 |
(constants.RS_NORMAL, False),
|
811 |
(constants.RS_NORMAL, "192.0.2.2")],
|
812 |
]) |
813 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl), |
814 |
["master.example.com", "node2.example.com"]) |
815 |
self.assertEqual(cl.CountPending(), 0) |
816 |
|
817 |
def testNoMaster(self): |
818 |
cl = self._FakeClient()
|
819 |
|
820 |
def _CheckFilter(qfilter): |
821 |
self.assertEqual(qfilter, [qlang.OP_NOT, [qlang.OP_TRUE, "master"]]) |
822 |
return True |
823 |
|
824 |
cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [ |
825 |
[(constants.RS_NORMAL, "node2.example.com"),
|
826 |
(constants.RS_NORMAL, False),
|
827 |
(constants.RS_NORMAL, "192.0.2.2")],
|
828 |
]) |
829 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl, filter_master=True), |
830 |
["node2.example.com"])
|
831 |
self.assertEqual(cl.CountPending(), 0) |
832 |
|
833 |
def testSecondaryIpAddress(self): |
834 |
cl = self._FakeClient()
|
835 |
|
836 |
cl.AddQueryResult(["name", "offline", "sip"], None, [ |
837 |
[(constants.RS_NORMAL, "master.example.com"),
|
838 |
(constants.RS_NORMAL, False),
|
839 |
(constants.RS_NORMAL, "192.0.2.1")],
|
840 |
[(constants.RS_NORMAL, "node2.example.com"),
|
841 |
(constants.RS_NORMAL, False),
|
842 |
(constants.RS_NORMAL, "192.0.2.2")],
|
843 |
]) |
844 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl, secondary_ips=True), |
845 |
["192.0.2.1", "192.0.2.2"]) |
846 |
self.assertEqual(cl.CountPending(), 0) |
847 |
|
848 |
def testNoMasterFilterNodeName(self): |
849 |
cl = self._FakeClient()
|
850 |
|
851 |
def _CheckFilter(qfilter): |
852 |
self.assertEqual(qfilter,
|
853 |
[qlang.OP_AND, |
854 |
[qlang.OP_OR] + [[qlang.OP_EQUAL, "name", name]
|
855 |
for name in ["node2", "node3"]], |
856 |
[qlang.OP_NOT, [qlang.OP_TRUE, "master"]]])
|
857 |
return True |
858 |
|
859 |
cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [ |
860 |
[(constants.RS_NORMAL, "node2.example.com"),
|
861 |
(constants.RS_NORMAL, False),
|
862 |
(constants.RS_NORMAL, "192.0.2.12")],
|
863 |
[(constants.RS_NORMAL, "node3.example.com"),
|
864 |
(constants.RS_NORMAL, False),
|
865 |
(constants.RS_NORMAL, "192.0.2.13")],
|
866 |
]) |
867 |
self.assertEqual(cli.GetOnlineNodes(["node2", "node3"], cl=cl, |
868 |
secondary_ips=True, filter_master=True), |
869 |
["192.0.2.12", "192.0.2.13"]) |
870 |
self.assertEqual(cl.CountPending(), 0) |
871 |
|
872 |
def testOfflineNodes(self): |
873 |
cl = self._FakeClient()
|
874 |
|
875 |
cl.AddQueryResult(["name", "offline", "sip"], None, [ |
876 |
[(constants.RS_NORMAL, "master.example.com"),
|
877 |
(constants.RS_NORMAL, False),
|
878 |
(constants.RS_NORMAL, "192.0.2.1")],
|
879 |
[(constants.RS_NORMAL, "node2.example.com"),
|
880 |
(constants.RS_NORMAL, True),
|
881 |
(constants.RS_NORMAL, "192.0.2.2")],
|
882 |
[(constants.RS_NORMAL, "node3.example.com"),
|
883 |
(constants.RS_NORMAL, True),
|
884 |
(constants.RS_NORMAL, "192.0.2.3")],
|
885 |
]) |
886 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl, nowarn=True), |
887 |
["master.example.com"])
|
888 |
self.assertEqual(cl.CountPending(), 0) |
889 |
|
890 |
def testNodeGroup(self): |
891 |
cl = self._FakeClient()
|
892 |
|
893 |
def _CheckFilter(qfilter): |
894 |
self.assertEqual(qfilter,
|
895 |
[qlang.OP_OR, [qlang.OP_EQUAL, "group", "foobar"], |
896 |
[qlang.OP_EQUAL, "group.uuid", "foobar"]]) |
897 |
return True |
898 |
|
899 |
cl.AddQueryResult(["name", "offline", "sip"], _CheckFilter, [ |
900 |
[(constants.RS_NORMAL, "master.example.com"),
|
901 |
(constants.RS_NORMAL, False),
|
902 |
(constants.RS_NORMAL, "192.0.2.1")],
|
903 |
[(constants.RS_NORMAL, "node3.example.com"),
|
904 |
(constants.RS_NORMAL, False),
|
905 |
(constants.RS_NORMAL, "192.0.2.3")],
|
906 |
]) |
907 |
self.assertEqual(cli.GetOnlineNodes(None, cl=cl, nodegroup="foobar"), |
908 |
["master.example.com", "node3.example.com"]) |
909 |
self.assertEqual(cl.CountPending(), 0) |
910 |
|
911 |
|
912 |
class TestFormatTimestamp(unittest.TestCase): |
913 |
def testGood(self): |
914 |
self.assertEqual(cli.FormatTimestamp((0, 1)), |
915 |
time.strftime("%F %T", time.localtime(0)) + ".000001") |
916 |
self.assertEqual(cli.FormatTimestamp((1332944009, 17376)), |
917 |
(time.strftime("%F %T", time.localtime(1332944009)) + |
918 |
".017376"))
|
919 |
|
920 |
def testWrong(self): |
921 |
for i in [0, [], {}, "", [1]]: |
922 |
self.assertEqual(cli.FormatTimestamp(i), "?") |
923 |
|
924 |
|
925 |
class TestFormatUsage(unittest.TestCase): |
926 |
def test(self): |
927 |
binary = "gnt-unittest"
|
928 |
commands = { |
929 |
"cmdA":
|
930 |
(NotImplemented, NotImplemented, NotImplemented, NotImplemented, |
931 |
"description of A"),
|
932 |
"bbb":
|
933 |
(NotImplemented, NotImplemented, NotImplemented, NotImplemented, |
934 |
"Hello World," * 10), |
935 |
"longname":
|
936 |
(NotImplemented, NotImplemented, NotImplemented, NotImplemented, |
937 |
"Another description"),
|
938 |
} |
939 |
|
940 |
self.assertEqual(list(cli._FormatUsage(binary, commands)), [ |
941 |
"Usage: gnt-unittest {command} [options...] [argument...]",
|
942 |
"gnt-unittest <command> --help to see details, or man gnt-unittest",
|
943 |
"",
|
944 |
"Commands:",
|
945 |
(" bbb - Hello World,Hello World,Hello World,Hello World,Hello"
|
946 |
" World,Hello"),
|
947 |
" World,Hello World,Hello World,Hello World,Hello World,",
|
948 |
" cmdA - description of A",
|
949 |
" longname - Another description",
|
950 |
"",
|
951 |
]) |
952 |
|
953 |
|
954 |
class TestParseArgs(unittest.TestCase): |
955 |
def testNoArguments(self): |
956 |
for argv in [[], ["gnt-unittest"]]: |
957 |
try:
|
958 |
cli._ParseArgs("gnt-unittest", argv, {}, {}, set()) |
959 |
except cli._ShowUsage, err:
|
960 |
self.assertTrue(err.exit_error)
|
961 |
else:
|
962 |
self.fail("Did not raise exception") |
963 |
|
964 |
def testVersion(self): |
965 |
for argv in [["test", "--version"], ["test", "--version", "somethingelse"]]: |
966 |
try:
|
967 |
cli._ParseArgs("test", argv, {}, {}, set()) |
968 |
except cli._ShowVersion:
|
969 |
pass
|
970 |
else:
|
971 |
self.fail("Did not raise exception") |
972 |
|
973 |
def testHelp(self): |
974 |
for argv in [["test", "--help"], ["test", "--help", "somethingelse"]]: |
975 |
try:
|
976 |
cli._ParseArgs("test", argv, {}, {}, set()) |
977 |
except cli._ShowUsage, err:
|
978 |
self.assertFalse(err.exit_error)
|
979 |
else:
|
980 |
self.fail("Did not raise exception") |
981 |
|
982 |
def testUnknownCommandOrAlias(self): |
983 |
for argv in [["test", "list"], ["test", "somethingelse", "--help"]]: |
984 |
try:
|
985 |
cli._ParseArgs("test", argv, {}, {}, set()) |
986 |
except cli._ShowUsage, err:
|
987 |
self.assertTrue(err.exit_error)
|
988 |
else:
|
989 |
self.fail("Did not raise exception") |
990 |
|
991 |
def testInvalidAliasList(self): |
992 |
cmd = { |
993 |
"list": NotImplemented, |
994 |
"foo": NotImplemented, |
995 |
} |
996 |
aliases = { |
997 |
"list": NotImplemented, |
998 |
"foo": NotImplemented, |
999 |
} |
1000 |
assert sorted(cmd.keys()) == sorted(aliases.keys()) |
1001 |
self.assertRaises(AssertionError, cli._ParseArgs, "test", |
1002 |
["test", "list"], cmd, aliases, set()) |
1003 |
|
1004 |
def testAliasForNonExistantCommand(self): |
1005 |
cmd = {} |
1006 |
aliases = { |
1007 |
"list": NotImplemented, |
1008 |
} |
1009 |
self.assertRaises(errors.ProgrammerError, cli._ParseArgs, "test", |
1010 |
["test", "list"], cmd, aliases, set()) |
1011 |
|
1012 |
|
1013 |
class TestQftNames(unittest.TestCase): |
1014 |
def testComplete(self): |
1015 |
self.assertEqual(frozenset(cli._QFT_NAMES), constants.QFT_ALL) |
1016 |
|
1017 |
def testUnique(self): |
1018 |
lcnames = map(lambda s: s.lower(), cli._QFT_NAMES.values()) |
1019 |
self.assertFalse(utils.FindDuplicates(lcnames))
|
1020 |
|
1021 |
def testUppercase(self): |
1022 |
for name in cli._QFT_NAMES.values(): |
1023 |
self.assertEqual(name[0], name[0].upper()) |
1024 |
|
1025 |
|
1026 |
class TestFieldDescValues(unittest.TestCase): |
1027 |
def testKnownKind(self): |
1028 |
fdef = objects.QueryFieldDefinition(name="aname",
|
1029 |
title="Atitle",
|
1030 |
kind=constants.QFT_TEXT, |
1031 |
doc="aaa doc aaa")
|
1032 |
self.assertEqual(cli._FieldDescValues(fdef),
|
1033 |
["aname", "Text", "Atitle", "aaa doc aaa"]) |
1034 |
|
1035 |
def testUnknownKind(self): |
1036 |
kind = "#foo#"
|
1037 |
|
1038 |
self.assertFalse(kind in constants.QFT_ALL) |
1039 |
self.assertFalse(kind in cli._QFT_NAMES) |
1040 |
|
1041 |
fdef = objects.QueryFieldDefinition(name="zname", title="Ztitle", |
1042 |
kind=kind, doc="zzz doc zzz")
|
1043 |
self.assertEqual(cli._FieldDescValues(fdef),
|
1044 |
["zname", kind, "Ztitle", "zzz doc zzz"]) |
1045 |
|
1046 |
|
1047 |
class TestSerializeGenericInfo(unittest.TestCase): |
1048 |
"""Test case for cli._SerializeGenericInfo"""
|
1049 |
def _RunTest(self, data, expected): |
1050 |
buf = StringIO() |
1051 |
cli._SerializeGenericInfo(buf, data, 0)
|
1052 |
self.assertEqual(buf.getvalue(), expected)
|
1053 |
|
1054 |
def testSimple(self): |
1055 |
test_samples = [ |
1056 |
("abc", "abc\n"), |
1057 |
([], "\n"),
|
1058 |
({}, "\n"),
|
1059 |
(["1", "2", "3"], "- 1\n- 2\n- 3\n"), |
1060 |
([("z", "26")], "z: 26\n"), |
1061 |
({"z": "26"}, "z: 26\n"), |
1062 |
([("z", "26"), ("a", "1")], "z: 26\na: 1\n"), |
1063 |
({"z": "26", "a": "1"}, "a: 1\nz: 26\n"), |
1064 |
] |
1065 |
for (data, expected) in test_samples: |
1066 |
self._RunTest(data, expected)
|
1067 |
|
1068 |
def testLists(self): |
1069 |
adict = { |
1070 |
"aa": "11", |
1071 |
"bb": "22", |
1072 |
"cc": "33", |
1073 |
} |
1074 |
adict_exp = ("- aa: 11\n"
|
1075 |
" bb: 22\n"
|
1076 |
" cc: 33\n")
|
1077 |
anobj = [ |
1078 |
("zz", "11"), |
1079 |
("ww", "33"), |
1080 |
("xx", "22"), |
1081 |
] |
1082 |
anobj_exp = ("- zz: 11\n"
|
1083 |
" ww: 33\n"
|
1084 |
" xx: 22\n")
|
1085 |
alist = ["aa", "cc", "bb"] |
1086 |
alist_exp = ("- - aa\n"
|
1087 |
" - cc\n"
|
1088 |
" - bb\n")
|
1089 |
test_samples = [ |
1090 |
(adict, adict_exp), |
1091 |
(anobj, anobj_exp), |
1092 |
(alist, alist_exp), |
1093 |
] |
1094 |
for (base_data, base_expected) in test_samples: |
1095 |
for k in range(1, 4): |
1096 |
data = k * [base_data] |
1097 |
expected = k * base_expected |
1098 |
self._RunTest(data, expected)
|
1099 |
|
1100 |
def testDictionaries(self): |
1101 |
data = [ |
1102 |
("aaa", ["x", "y"]), |
1103 |
("bbb", {
|
1104 |
"w": "1", |
1105 |
"z": "2", |
1106 |
}), |
1107 |
("ccc", [
|
1108 |
("xyz", "123"), |
1109 |
("efg", "456"), |
1110 |
]), |
1111 |
] |
1112 |
expected = ("aaa: \n"
|
1113 |
" - x\n"
|
1114 |
" - y\n"
|
1115 |
"bbb: \n"
|
1116 |
" w: 1\n"
|
1117 |
" z: 2\n"
|
1118 |
"ccc: \n"
|
1119 |
" xyz: 123\n"
|
1120 |
" efg: 456\n")
|
1121 |
self._RunTest(data, expected)
|
1122 |
self._RunTest(dict(data), expected) |
1123 |
|
1124 |
|
1125 |
class TestCreateIPolicyFromOpts(unittest.TestCase): |
1126 |
"""Test case for cli.CreateIPolicyFromOpts."""
|
1127 |
def _RecursiveCheckMergedDicts(self, default_pol, diff_pol, merged_pol): |
1128 |
self.assertTrue(type(default_pol) is dict) |
1129 |
self.assertTrue(type(diff_pol) is dict) |
1130 |
self.assertTrue(type(merged_pol) is dict) |
1131 |
self.assertEqual(frozenset(default_pol.keys()), |
1132 |
frozenset(merged_pol.keys()))
|
1133 |
for (key, val) in merged_pol.items(): |
1134 |
if key in diff_pol: |
1135 |
if type(val) is dict: |
1136 |
self._RecursiveCheckMergedDicts(default_pol[key], diff_pol[key], val)
|
1137 |
else:
|
1138 |
self.assertEqual(val, diff_pol[key])
|
1139 |
else:
|
1140 |
self.assertEqual(val, default_pol[key])
|
1141 |
|
1142 |
def testClusterPolicy(self): |
1143 |
exp_pol0 = { |
1144 |
constants.ISPECS_MINMAX: { |
1145 |
constants.ISPECS_MIN: {}, |
1146 |
constants.ISPECS_MAX: {}, |
1147 |
}, |
1148 |
constants.ISPECS_STD: {}, |
1149 |
} |
1150 |
exp_pol1 = { |
1151 |
constants.ISPECS_MINMAX: { |
1152 |
constants.ISPECS_MIN: { |
1153 |
constants.ISPEC_CPU_COUNT: 2,
|
1154 |
constants.ISPEC_DISK_COUNT: 1,
|
1155 |
}, |
1156 |
constants.ISPECS_MAX: { |
1157 |
constants.ISPEC_MEM_SIZE: 12*1024, |
1158 |
constants.ISPEC_DISK_COUNT: 2,
|
1159 |
}, |
1160 |
}, |
1161 |
constants.ISPECS_STD: { |
1162 |
constants.ISPEC_CPU_COUNT: 2,
|
1163 |
constants.ISPEC_DISK_COUNT: 2,
|
1164 |
}, |
1165 |
constants.IPOLICY_VCPU_RATIO: 3.1,
|
1166 |
} |
1167 |
exp_pol2 = { |
1168 |
constants.ISPECS_MINMAX: { |
1169 |
constants.ISPECS_MIN: { |
1170 |
constants.ISPEC_DISK_SIZE: 512,
|
1171 |
constants.ISPEC_NIC_COUNT: 2,
|
1172 |
}, |
1173 |
constants.ISPECS_MAX: { |
1174 |
constants.ISPEC_NIC_COUNT: 3,
|
1175 |
}, |
1176 |
}, |
1177 |
constants.ISPECS_STD: { |
1178 |
constants.ISPEC_CPU_COUNT: 2,
|
1179 |
constants.ISPEC_NIC_COUNT: 3,
|
1180 |
}, |
1181 |
constants.IPOLICY_SPINDLE_RATIO: 1.3,
|
1182 |
constants.IPOLICY_DTS: ["templates"],
|
1183 |
} |
1184 |
for fillall in [False, True]: |
1185 |
pol0 = cli.CreateIPolicyFromOpts( |
1186 |
ispecs_mem_size={}, |
1187 |
ispecs_cpu_count={}, |
1188 |
ispecs_disk_count={}, |
1189 |
ispecs_disk_size={}, |
1190 |
ispecs_nic_count={}, |
1191 |
ipolicy_disk_templates=None,
|
1192 |
ipolicy_vcpu_ratio=None,
|
1193 |
ipolicy_spindle_ratio=None,
|
1194 |
fill_all=fillall |
1195 |
) |
1196 |
if fillall:
|
1197 |
self.assertEqual(pol0, constants.IPOLICY_DEFAULTS)
|
1198 |
else:
|
1199 |
self.assertEqual(pol0, exp_pol0)
|
1200 |
pol1 = cli.CreateIPolicyFromOpts( |
1201 |
ispecs_mem_size={"max": "12g"}, |
1202 |
ispecs_cpu_count={"min": 2, "std": 2}, |
1203 |
ispecs_disk_count={"min": 1, "max": 2, "std": 2}, |
1204 |
ispecs_disk_size={}, |
1205 |
ispecs_nic_count={}, |
1206 |
ipolicy_disk_templates=None,
|
1207 |
ipolicy_vcpu_ratio=3.1,
|
1208 |
ipolicy_spindle_ratio=None,
|
1209 |
fill_all=fillall |
1210 |
) |
1211 |
if fillall:
|
1212 |
self._RecursiveCheckMergedDicts(constants.IPOLICY_DEFAULTS,
|
1213 |
exp_pol1, pol1) |
1214 |
else:
|
1215 |
self.assertEqual(pol1, exp_pol1)
|
1216 |
pol2 = cli.CreateIPolicyFromOpts( |
1217 |
ispecs_mem_size={}, |
1218 |
ispecs_cpu_count={"std": 2}, |
1219 |
ispecs_disk_count={}, |
1220 |
ispecs_disk_size={"min": "0.5g"}, |
1221 |
ispecs_nic_count={"min": 2, "max": 3, "std": 3}, |
1222 |
ipolicy_disk_templates=["templates"],
|
1223 |
ipolicy_vcpu_ratio=None,
|
1224 |
ipolicy_spindle_ratio=1.3,
|
1225 |
fill_all=fillall |
1226 |
) |
1227 |
if fillall:
|
1228 |
self._RecursiveCheckMergedDicts(constants.IPOLICY_DEFAULTS,
|
1229 |
exp_pol2, pol2) |
1230 |
else:
|
1231 |
self.assertEqual(pol2, exp_pol2)
|
1232 |
|
1233 |
def testInvalidPolicies(self): |
1234 |
self.assertRaises(errors.TypeEnforcementError, cli.CreateIPolicyFromOpts,
|
1235 |
ispecs_mem_size={}, ispecs_cpu_count={}, |
1236 |
ispecs_disk_count={}, ispecs_disk_size={"std": 1}, |
1237 |
ispecs_nic_count={}, ipolicy_disk_templates=None,
|
1238 |
ipolicy_vcpu_ratio=None, ipolicy_spindle_ratio=None, |
1239 |
group_ipolicy=True)
|
1240 |
self.assertRaises(errors.OpPrereqError, cli.CreateIPolicyFromOpts,
|
1241 |
ispecs_mem_size={"wrong": "x"}, ispecs_cpu_count={}, |
1242 |
ispecs_disk_count={}, ispecs_disk_size={}, |
1243 |
ispecs_nic_count={}, ipolicy_disk_templates=None,
|
1244 |
ipolicy_vcpu_ratio=None, ipolicy_spindle_ratio=None) |
1245 |
self.assertRaises(errors.TypeEnforcementError, cli.CreateIPolicyFromOpts,
|
1246 |
ispecs_mem_size={}, ispecs_cpu_count={"min": "default"}, |
1247 |
ispecs_disk_count={}, ispecs_disk_size={}, |
1248 |
ispecs_nic_count={}, ipolicy_disk_templates=None,
|
1249 |
ipolicy_vcpu_ratio=None, ipolicy_spindle_ratio=None) |
1250 |
|
1251 |
def testAllowedValues(self): |
1252 |
allowedv = "blah"
|
1253 |
exp_pol1 = { |
1254 |
constants.ISPECS_MINMAX: { |
1255 |
constants.ISPECS_MIN: { |
1256 |
constants.ISPEC_CPU_COUNT: allowedv, |
1257 |
}, |
1258 |
constants.ISPECS_MAX: { |
1259 |
}, |
1260 |
}, |
1261 |
constants.ISPECS_STD: { |
1262 |
}, |
1263 |
} |
1264 |
pol1 = cli.CreateIPolicyFromOpts(ispecs_mem_size={}, |
1265 |
ispecs_cpu_count={"min": allowedv},
|
1266 |
ispecs_disk_count={}, |
1267 |
ispecs_disk_size={}, |
1268 |
ispecs_nic_count={}, |
1269 |
ipolicy_disk_templates=None,
|
1270 |
ipolicy_vcpu_ratio=None,
|
1271 |
ipolicy_spindle_ratio=None,
|
1272 |
allowed_values=[allowedv]) |
1273 |
self.assertEqual(pol1, exp_pol1)
|
1274 |
|
1275 |
|
1276 |
if __name__ == "__main__": |
1277 |
testutils.GanetiTestProgram() |