root / test / ganeti.cli_unittest.py @ a6070ef7
History | View | Annotate | Download (25.1 kB)
1 |
#!/usr/bin/python
|
---|---|
2 |
#
|
3 |
|
4 |
# Copyright (C) 2008 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 |
from cStringIO import StringIO |
26 |
|
27 |
import ganeti |
28 |
import testutils |
29 |
|
30 |
from ganeti import constants |
31 |
from ganeti import cli |
32 |
from ganeti import errors |
33 |
from ganeti import utils |
34 |
from ganeti import objects |
35 |
from ganeti.errors import OpPrereqError, ParameterError |
36 |
|
37 |
|
38 |
class TestParseTimespec(unittest.TestCase): |
39 |
"""Testing case for ParseTimespec"""
|
40 |
|
41 |
def testValidTimes(self): |
42 |
"""Test valid timespecs"""
|
43 |
test_data = [ |
44 |
('1s', 1), |
45 |
('1', 1), |
46 |
('1m', 60), |
47 |
('1h', 60 * 60), |
48 |
('1d', 60 * 60 * 24), |
49 |
('1w', 60 * 60 * 24 * 7), |
50 |
('4h', 4 * 60 * 60), |
51 |
('61m', 61 * 60), |
52 |
] |
53 |
for value, expected_result in test_data: |
54 |
self.failUnlessEqual(cli.ParseTimespec(value), expected_result)
|
55 |
|
56 |
def testInvalidTime(self): |
57 |
"""Test invalid timespecs"""
|
58 |
test_data = [ |
59 |
'1y',
|
60 |
'',
|
61 |
'aaa',
|
62 |
's',
|
63 |
] |
64 |
for value in test_data: |
65 |
self.failUnlessRaises(OpPrereqError, cli.ParseTimespec, value)
|
66 |
|
67 |
|
68 |
class TestSplitKeyVal(unittest.TestCase): |
69 |
"""Testing case for cli._SplitKeyVal"""
|
70 |
DATA = "a=b,c,no_d,-e"
|
71 |
RESULT = {"a": "b", "c": True, "d": False, "e": None} |
72 |
|
73 |
def testSplitKeyVal(self): |
74 |
"""Test splitting"""
|
75 |
self.failUnlessEqual(cli._SplitKeyVal("option", self.DATA), self.RESULT) |
76 |
|
77 |
def testDuplicateParam(self): |
78 |
"""Test duplicate parameters"""
|
79 |
for data in ("a=1,a=2", "a,no_a"): |
80 |
self.failUnlessRaises(ParameterError, cli._SplitKeyVal,
|
81 |
"option", data)
|
82 |
|
83 |
def testEmptyData(self): |
84 |
"""Test how we handle splitting an empty string"""
|
85 |
self.failUnlessEqual(cli._SplitKeyVal("option", ""), {}) |
86 |
|
87 |
class TestIdentKeyVal(unittest.TestCase): |
88 |
"""Testing case for cli.check_ident_key_val"""
|
89 |
|
90 |
def testIdentKeyVal(self): |
91 |
"""Test identkeyval"""
|
92 |
def cikv(value): |
93 |
return cli.check_ident_key_val("option", "opt", value) |
94 |
|
95 |
self.assertEqual(cikv("foo:bar"), ("foo", {"bar": True})) |
96 |
self.assertEqual(cikv("foo:bar=baz"), ("foo", {"bar": "baz"})) |
97 |
self.assertEqual(cikv("bar:b=c,c=a"), ("bar", {"b": "c", "c": "a"})) |
98 |
self.assertEqual(cikv("no_bar"), ("bar", False)) |
99 |
self.assertRaises(ParameterError, cikv, "no_bar:foo") |
100 |
self.assertRaises(ParameterError, cikv, "no_bar:foo=baz") |
101 |
self.assertEqual(cikv("-foo"), ("foo", None)) |
102 |
self.assertRaises(ParameterError, cikv, "-foo:a=c") |
103 |
|
104 |
|
105 |
class TestToStream(unittest.TestCase): |
106 |
"""Test the ToStream functions"""
|
107 |
|
108 |
def testBasic(self): |
109 |
for data in ["foo", |
110 |
"foo %s",
|
111 |
"foo %(test)s",
|
112 |
"foo %s %s",
|
113 |
"",
|
114 |
]: |
115 |
buf = StringIO() |
116 |
cli._ToStream(buf, data) |
117 |
self.failUnlessEqual(buf.getvalue(), data+'\n') |
118 |
|
119 |
def testParams(self): |
120 |
buf = StringIO() |
121 |
cli._ToStream(buf, "foo %s", 1) |
122 |
self.failUnlessEqual(buf.getvalue(), "foo 1\n") |
123 |
buf = StringIO() |
124 |
cli._ToStream(buf, "foo %s", (15,16)) |
125 |
self.failUnlessEqual(buf.getvalue(), "foo (15, 16)\n") |
126 |
buf = StringIO() |
127 |
cli._ToStream(buf, "foo %s %s", "a", "b") |
128 |
self.failUnlessEqual(buf.getvalue(), "foo a b\n") |
129 |
|
130 |
|
131 |
class TestGenerateTable(unittest.TestCase): |
132 |
HEADERS = dict([("f%s" % i, "Field%s" % i) for i in range(5)]) |
133 |
|
134 |
FIELDS1 = ["f1", "f2"] |
135 |
DATA1 = [ |
136 |
["abc", 1234], |
137 |
["foobar", 56], |
138 |
["b", -14], |
139 |
] |
140 |
|
141 |
def _test(self, headers, fields, separator, data, |
142 |
numfields, unitfields, units, expected): |
143 |
table = cli.GenerateTable(headers, fields, separator, data, |
144 |
numfields=numfields, unitfields=unitfields, |
145 |
units=units) |
146 |
self.assertEqual(table, expected)
|
147 |
|
148 |
def testPlain(self): |
149 |
exp = [ |
150 |
"Field1 Field2",
|
151 |
"abc 1234",
|
152 |
"foobar 56",
|
153 |
"b -14",
|
154 |
] |
155 |
self._test(self.HEADERS, self.FIELDS1, None, self.DATA1, |
156 |
None, None, "m", exp) |
157 |
|
158 |
def testNoFields(self): |
159 |
self._test(self.HEADERS, [], None, [[], []], |
160 |
None, None, "m", ["", "", ""]) |
161 |
self._test(None, [], None, [[], []], |
162 |
None, None, "m", ["", ""]) |
163 |
|
164 |
def testSeparator(self): |
165 |
for sep in ["#", ":", ",", "^", "!", "%", "|", "###", "%%", "!!!", "||"]: |
166 |
exp = [ |
167 |
"Field1%sField2" % sep,
|
168 |
"abc%s1234" % sep,
|
169 |
"foobar%s56" % sep,
|
170 |
"b%s-14" % sep,
|
171 |
] |
172 |
self._test(self.HEADERS, self.FIELDS1, sep, self.DATA1, |
173 |
None, None, "m", exp) |
174 |
|
175 |
def testNoHeader(self): |
176 |
exp = [ |
177 |
"abc 1234",
|
178 |
"foobar 56",
|
179 |
"b -14",
|
180 |
] |
181 |
self._test(None, self.FIELDS1, None, self.DATA1, |
182 |
None, None, "m", exp) |
183 |
|
184 |
def testUnknownField(self): |
185 |
headers = { |
186 |
"f1": "Field1", |
187 |
} |
188 |
exp = [ |
189 |
"Field1 UNKNOWN",
|
190 |
"abc 1234",
|
191 |
"foobar 56",
|
192 |
"b -14",
|
193 |
] |
194 |
self._test(headers, ["f1", "UNKNOWN"], None, self.DATA1, |
195 |
None, None, "m", exp) |
196 |
|
197 |
def testNumfields(self): |
198 |
fields = ["f1", "f2", "f3"] |
199 |
data = [ |
200 |
["abc", 1234, 0], |
201 |
["foobar", 56, 3], |
202 |
["b", -14, "-"], |
203 |
] |
204 |
exp = [ |
205 |
"Field1 Field2 Field3",
|
206 |
"abc 1234 0",
|
207 |
"foobar 56 3",
|
208 |
"b -14 -",
|
209 |
] |
210 |
self._test(self.HEADERS, fields, None, data, |
211 |
["f2", "f3"], None, "m", exp) |
212 |
|
213 |
def testUnitfields(self): |
214 |
expnosep = [ |
215 |
"Field1 Field2 Field3",
|
216 |
"abc 1234 0M",
|
217 |
"foobar 56 3M",
|
218 |
"b -14 -",
|
219 |
] |
220 |
|
221 |
expsep = [ |
222 |
"Field1:Field2:Field3",
|
223 |
"abc:1234:0M",
|
224 |
"foobar:56:3M",
|
225 |
"b:-14:-",
|
226 |
] |
227 |
|
228 |
for sep, expected in [(None, expnosep), (":", expsep)]: |
229 |
fields = ["f1", "f2", "f3"] |
230 |
data = [ |
231 |
["abc", 1234, 0], |
232 |
["foobar", 56, 3], |
233 |
["b", -14, "-"], |
234 |
] |
235 |
self._test(self.HEADERS, fields, sep, data, |
236 |
["f2", "f3"], ["f3"], "h", expected) |
237 |
|
238 |
def testUnusual(self): |
239 |
data = [ |
240 |
["%", "xyz"], |
241 |
["%%", "abc"], |
242 |
] |
243 |
exp = [ |
244 |
"Field1 Field2",
|
245 |
"% xyz",
|
246 |
"%% abc",
|
247 |
] |
248 |
self._test(self.HEADERS, ["f1", "f2"], None, data, |
249 |
None, None, "m", exp) |
250 |
|
251 |
|
252 |
class TestFormatQueryResult(unittest.TestCase): |
253 |
def test(self): |
254 |
fields = [ |
255 |
objects.QueryFieldDefinition(name="name", title="Name", |
256 |
kind=constants.QFT_TEXT), |
257 |
objects.QueryFieldDefinition(name="size", title="Size", |
258 |
kind=constants.QFT_NUMBER), |
259 |
objects.QueryFieldDefinition(name="act", title="Active", |
260 |
kind=constants.QFT_BOOL), |
261 |
objects.QueryFieldDefinition(name="mem", title="Memory", |
262 |
kind=constants.QFT_UNIT), |
263 |
objects.QueryFieldDefinition(name="other", title="SomeList", |
264 |
kind=constants.QFT_OTHER), |
265 |
] |
266 |
|
267 |
response = objects.QueryResponse(fields=fields, data=[ |
268 |
[(constants.QRFS_NORMAL, "nodeA"), (constants.QRFS_NORMAL, 128), |
269 |
(constants.QRFS_NORMAL, False), (constants.QRFS_NORMAL, 1468006), |
270 |
(constants.QRFS_NORMAL, [])], |
271 |
[(constants.QRFS_NORMAL, "other"), (constants.QRFS_NORMAL, 512), |
272 |
(constants.QRFS_NORMAL, True), (constants.QRFS_NORMAL, 16), |
273 |
(constants.QRFS_NORMAL, [1, 2, 3])], |
274 |
[(constants.QRFS_NORMAL, "xyz"), (constants.QRFS_NORMAL, 1024), |
275 |
(constants.QRFS_NORMAL, True), (constants.QRFS_NORMAL, 4096), |
276 |
(constants.QRFS_NORMAL, [{}, {}])], |
277 |
]) |
278 |
|
279 |
self.assertEqual(cli.FormatQueryResult(response, unit="h", header=True), |
280 |
(cli.QR_NORMAL, [ |
281 |
"Name Size Active Memory SomeList",
|
282 |
"nodeA 128 N 1.4T []",
|
283 |
"other 512 Y 16M [1, 2, 3]",
|
284 |
"xyz 1024 Y 4.0G [{}, {}]",
|
285 |
])) |
286 |
|
287 |
def testTimestampAndUnit(self): |
288 |
fields = [ |
289 |
objects.QueryFieldDefinition(name="name", title="Name", |
290 |
kind=constants.QFT_TEXT), |
291 |
objects.QueryFieldDefinition(name="size", title="Size", |
292 |
kind=constants.QFT_UNIT), |
293 |
objects.QueryFieldDefinition(name="mtime", title="ModTime", |
294 |
kind=constants.QFT_TIMESTAMP), |
295 |
] |
296 |
|
297 |
response = objects.QueryResponse(fields=fields, data=[ |
298 |
[(constants.QRFS_NORMAL, "a"), (constants.QRFS_NORMAL, 1024), |
299 |
(constants.QRFS_NORMAL, 0)],
|
300 |
[(constants.QRFS_NORMAL, "b"), (constants.QRFS_NORMAL, 144996), |
301 |
(constants.QRFS_NORMAL, 1291746295)],
|
302 |
]) |
303 |
|
304 |
self.assertEqual(cli.FormatQueryResult(response, unit="m", header=True), |
305 |
(cli.QR_NORMAL, [ |
306 |
"Name Size ModTime",
|
307 |
"a 1024 %s" % utils.FormatTime(0), |
308 |
"b 144996 %s" % utils.FormatTime(1291746295), |
309 |
])) |
310 |
|
311 |
def testOverride(self): |
312 |
fields = [ |
313 |
objects.QueryFieldDefinition(name="name", title="Name", |
314 |
kind=constants.QFT_TEXT), |
315 |
objects.QueryFieldDefinition(name="cust", title="Custom", |
316 |
kind=constants.QFT_OTHER), |
317 |
objects.QueryFieldDefinition(name="xt", title="XTime", |
318 |
kind=constants.QFT_TIMESTAMP), |
319 |
] |
320 |
|
321 |
response = objects.QueryResponse(fields=fields, data=[ |
322 |
[(constants.QRFS_NORMAL, "x"), (constants.QRFS_NORMAL, ["a", "b", "c"]), |
323 |
(constants.QRFS_NORMAL, 1234)],
|
324 |
[(constants.QRFS_NORMAL, "y"), (constants.QRFS_NORMAL, range(10)), |
325 |
(constants.QRFS_NORMAL, 1291746295)],
|
326 |
]) |
327 |
|
328 |
override = { |
329 |
"cust": (utils.CommaJoin, False), |
330 |
"xt": (hex, True), |
331 |
} |
332 |
|
333 |
self.assertEqual(cli.FormatQueryResult(response, unit="h", header=True, |
334 |
format_override=override), |
335 |
(cli.QR_NORMAL, [ |
336 |
"Name Custom XTime",
|
337 |
"x a, b, c 0x4d2",
|
338 |
"y 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 0x4cfe7bf7",
|
339 |
])) |
340 |
|
341 |
def testSeparator(self): |
342 |
fields = [ |
343 |
objects.QueryFieldDefinition(name="name", title="Name", |
344 |
kind=constants.QFT_TEXT), |
345 |
objects.QueryFieldDefinition(name="count", title="Count", |
346 |
kind=constants.QFT_NUMBER), |
347 |
objects.QueryFieldDefinition(name="desc", title="Description", |
348 |
kind=constants.QFT_TEXT), |
349 |
] |
350 |
|
351 |
response = objects.QueryResponse(fields=fields, data=[ |
352 |
[(constants.QRFS_NORMAL, "instance1.example.com"),
|
353 |
(constants.QRFS_NORMAL, 21125), (constants.QRFS_NORMAL, "Hello World!")], |
354 |
[(constants.QRFS_NORMAL, "mail.other.net"),
|
355 |
(constants.QRFS_NORMAL, -9000), (constants.QRFS_NORMAL, "a,b,c")], |
356 |
]) |
357 |
|
358 |
for sep in [":", "|", "#", "|||", "###", "@@@", "@#@"]: |
359 |
for header in [None, "Name%sCount%sDescription" % (sep, sep)]: |
360 |
exp = [] |
361 |
if header:
|
362 |
exp.append(header) |
363 |
exp.extend([ |
364 |
"instance1.example.com%s21125%sHello World!" % (sep, sep),
|
365 |
"mail.other.net%s-9000%sa,b,c" % (sep, sep),
|
366 |
]) |
367 |
|
368 |
self.assertEqual(cli.FormatQueryResult(response, separator=sep,
|
369 |
header=bool(header)),
|
370 |
(cli.QR_NORMAL, exp)) |
371 |
|
372 |
def testStatusWithUnknown(self): |
373 |
fields = [ |
374 |
objects.QueryFieldDefinition(name="id", title="ID", |
375 |
kind=constants.QFT_NUMBER), |
376 |
objects.QueryFieldDefinition(name="unk", title="unk", |
377 |
kind=constants.QFT_UNKNOWN), |
378 |
objects.QueryFieldDefinition(name="unavail", title="Unavail", |
379 |
kind=constants.QFT_BOOL), |
380 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
381 |
kind=constants.QFT_TEXT), |
382 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
383 |
kind=constants.QFT_TEXT), |
384 |
] |
385 |
|
386 |
response = objects.QueryResponse(fields=fields, data=[ |
387 |
[(constants.QRFS_NORMAL, 1), (constants.QRFS_UNKNOWN, None), |
388 |
(constants.QRFS_NORMAL, False), (constants.QRFS_NORMAL, ""), |
389 |
(constants.QRFS_OFFLINE, None)],
|
390 |
[(constants.QRFS_NORMAL, 2), (constants.QRFS_UNKNOWN, None), |
391 |
(constants.QRFS_NODATA, None), (constants.QRFS_NORMAL, "x"), |
392 |
(constants.QRFS_OFFLINE, None)],
|
393 |
[(constants.QRFS_NORMAL, 3), (constants.QRFS_UNKNOWN, None), |
394 |
(constants.QRFS_NORMAL, False), (constants.QRFS_UNAVAIL, None), |
395 |
(constants.QRFS_OFFLINE, None)],
|
396 |
]) |
397 |
|
398 |
self.assertEqual(cli.FormatQueryResult(response, header=True, |
399 |
separator="|"),
|
400 |
(cli.QR_UNKNOWN, [ |
401 |
"ID|unk|Unavail|NoData|OffLine",
|
402 |
"1|(unknown)|N||(offline)",
|
403 |
"2|(unknown)|(nodata)|x|(offline)",
|
404 |
"3|(unknown)|N|(unavail)|(offline)",
|
405 |
])) |
406 |
|
407 |
def testNoData(self): |
408 |
fields = [ |
409 |
objects.QueryFieldDefinition(name="id", title="ID", |
410 |
kind=constants.QFT_NUMBER), |
411 |
objects.QueryFieldDefinition(name="name", title="Name", |
412 |
kind=constants.QFT_TEXT), |
413 |
] |
414 |
|
415 |
response = objects.QueryResponse(fields=fields, data=[]) |
416 |
|
417 |
self.assertEqual(cli.FormatQueryResult(response, header=True), |
418 |
(cli.QR_NORMAL, ["ID Name"]))
|
419 |
|
420 |
def testNoDataWithUnknown(self): |
421 |
fields = [ |
422 |
objects.QueryFieldDefinition(name="id", title="ID", |
423 |
kind=constants.QFT_NUMBER), |
424 |
objects.QueryFieldDefinition(name="unk", title="unk", |
425 |
kind=constants.QFT_UNKNOWN), |
426 |
] |
427 |
|
428 |
response = objects.QueryResponse(fields=fields, data=[]) |
429 |
|
430 |
self.assertEqual(cli.FormatQueryResult(response, header=False), |
431 |
(cli.QR_UNKNOWN, [])) |
432 |
|
433 |
def testStatus(self): |
434 |
fields = [ |
435 |
objects.QueryFieldDefinition(name="id", title="ID", |
436 |
kind=constants.QFT_NUMBER), |
437 |
objects.QueryFieldDefinition(name="unavail", title="Unavail", |
438 |
kind=constants.QFT_BOOL), |
439 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
440 |
kind=constants.QFT_TEXT), |
441 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
442 |
kind=constants.QFT_TEXT), |
443 |
] |
444 |
|
445 |
response = objects.QueryResponse(fields=fields, data=[ |
446 |
[(constants.QRFS_NORMAL, 1), (constants.QRFS_NORMAL, False), |
447 |
(constants.QRFS_NORMAL, ""), (constants.QRFS_OFFLINE, None)], |
448 |
[(constants.QRFS_NORMAL, 2), (constants.QRFS_NODATA, None), |
449 |
(constants.QRFS_NORMAL, "x"), (constants.QRFS_NORMAL, "abc")], |
450 |
[(constants.QRFS_NORMAL, 3), (constants.QRFS_NORMAL, False), |
451 |
(constants.QRFS_UNAVAIL, None), (constants.QRFS_OFFLINE, None)], |
452 |
]) |
453 |
|
454 |
self.assertEqual(cli.FormatQueryResult(response, header=False, |
455 |
separator="|"),
|
456 |
(cli.QR_INCOMPLETE, [ |
457 |
"1|N||(offline)",
|
458 |
"2|(nodata)|x|abc",
|
459 |
"3|N|(unavail)|(offline)",
|
460 |
])) |
461 |
|
462 |
def testInvalidFieldType(self): |
463 |
fields = [ |
464 |
objects.QueryFieldDefinition(name="x", title="x", |
465 |
kind="#some#other#type"),
|
466 |
] |
467 |
|
468 |
response = objects.QueryResponse(fields=fields, data=[]) |
469 |
|
470 |
self.assertRaises(NotImplementedError, cli.FormatQueryResult, response) |
471 |
|
472 |
def testInvalidFieldStatus(self): |
473 |
fields = [ |
474 |
objects.QueryFieldDefinition(name="x", title="x", |
475 |
kind=constants.QFT_TEXT), |
476 |
] |
477 |
|
478 |
response = objects.QueryResponse(fields=fields, data=[[(-1, None)]]) |
479 |
self.assertRaises(NotImplementedError, cli.FormatQueryResult, response) |
480 |
|
481 |
response = objects.QueryResponse(fields=fields, data=[[(-1, "x")]]) |
482 |
self.assertRaises(AssertionError, cli.FormatQueryResult, response) |
483 |
|
484 |
def testEmptyFieldTitle(self): |
485 |
fields = [ |
486 |
objects.QueryFieldDefinition(name="x", title="", |
487 |
kind=constants.QFT_TEXT), |
488 |
] |
489 |
|
490 |
response = objects.QueryResponse(fields=fields, data=[]) |
491 |
self.assertRaises(AssertionError, cli.FormatQueryResult, response) |
492 |
|
493 |
|
494 |
class _MockJobPollCb(cli.JobPollCbBase, cli.JobPollReportCbBase): |
495 |
def __init__(self, tc, job_id): |
496 |
self.tc = tc
|
497 |
self.job_id = job_id
|
498 |
self._wfjcr = []
|
499 |
self._jobstatus = []
|
500 |
self._expect_notchanged = False |
501 |
self._expect_log = []
|
502 |
|
503 |
def CheckEmpty(self): |
504 |
self.tc.assertFalse(self._wfjcr) |
505 |
self.tc.assertFalse(self._jobstatus) |
506 |
self.tc.assertFalse(self._expect_notchanged) |
507 |
self.tc.assertFalse(self._expect_log) |
508 |
|
509 |
def AddWfjcResult(self, *args): |
510 |
self._wfjcr.append(args)
|
511 |
|
512 |
def AddQueryJobsResult(self, *args): |
513 |
self._jobstatus.append(args)
|
514 |
|
515 |
def WaitForJobChangeOnce(self, job_id, fields, |
516 |
prev_job_info, prev_log_serial): |
517 |
self.tc.assertEqual(job_id, self.job_id) |
518 |
self.tc.assertEqualValues(fields, ["status"]) |
519 |
self.tc.assertFalse(self._expect_notchanged) |
520 |
self.tc.assertFalse(self._expect_log) |
521 |
|
522 |
(exp_prev_job_info, exp_prev_log_serial, result) = self._wfjcr.pop(0) |
523 |
self.tc.assertEqualValues(prev_job_info, exp_prev_job_info)
|
524 |
self.tc.assertEqual(prev_log_serial, exp_prev_log_serial)
|
525 |
|
526 |
if result == constants.JOB_NOTCHANGED:
|
527 |
self._expect_notchanged = True |
528 |
elif result:
|
529 |
(_, logmsgs) = result |
530 |
if logmsgs:
|
531 |
self._expect_log.extend(logmsgs)
|
532 |
|
533 |
return result
|
534 |
|
535 |
def QueryJobs(self, job_ids, fields): |
536 |
self.tc.assertEqual(job_ids, [self.job_id]) |
537 |
self.tc.assertEqualValues(fields, ["status", "opstatus", "opresult"]) |
538 |
self.tc.assertFalse(self._expect_notchanged) |
539 |
self.tc.assertFalse(self._expect_log) |
540 |
|
541 |
result = self._jobstatus.pop(0) |
542 |
self.tc.assertEqual(len(fields), len(result)) |
543 |
return [result]
|
544 |
|
545 |
def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg): |
546 |
self.tc.assertEqual(job_id, self.job_id) |
547 |
self.tc.assertEqualValues((serial, timestamp, log_type, log_msg),
|
548 |
self._expect_log.pop(0)) |
549 |
|
550 |
def ReportNotChanged(self, job_id, status): |
551 |
self.tc.assertEqual(job_id, self.job_id) |
552 |
self.tc.assert_(self._expect_notchanged) |
553 |
self._expect_notchanged = False |
554 |
|
555 |
|
556 |
class TestGenericPollJob(testutils.GanetiTestCase): |
557 |
def testSuccessWithLog(self): |
558 |
job_id = 29609
|
559 |
cbs = _MockJobPollCb(self, job_id)
|
560 |
|
561 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
562 |
|
563 |
cbs.AddWfjcResult(None, None, |
564 |
((constants.JOB_STATUS_QUEUED, ), None))
|
565 |
|
566 |
cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
|
567 |
constants.JOB_NOTCHANGED) |
568 |
|
569 |
cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
|
570 |
((constants.JOB_STATUS_RUNNING, ), |
571 |
[(1, utils.SplitTime(1273491611.0), |
572 |
constants.ELOG_MESSAGE, "Step 1"),
|
573 |
(2, utils.SplitTime(1273491615.9), |
574 |
constants.ELOG_MESSAGE, "Step 2"),
|
575 |
(3, utils.SplitTime(1273491625.02), |
576 |
constants.ELOG_MESSAGE, "Step 3"),
|
577 |
(4, utils.SplitTime(1273491635.05), |
578 |
constants.ELOG_MESSAGE, "Step 4"),
|
579 |
(37, utils.SplitTime(1273491645.0), |
580 |
constants.ELOG_MESSAGE, "Step 5"),
|
581 |
(203, utils.SplitTime(127349155.0), |
582 |
constants.ELOG_MESSAGE, "Step 6")]))
|
583 |
|
584 |
cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 203,
|
585 |
((constants.JOB_STATUS_RUNNING, ), |
586 |
[(300, utils.SplitTime(1273491711.01), |
587 |
constants.ELOG_MESSAGE, "Step X"),
|
588 |
(302, utils.SplitTime(1273491815.8), |
589 |
constants.ELOG_MESSAGE, "Step Y"),
|
590 |
(303, utils.SplitTime(1273491925.32), |
591 |
constants.ELOG_MESSAGE, "Step Z")]))
|
592 |
|
593 |
cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 303,
|
594 |
((constants.JOB_STATUS_SUCCESS, ), None))
|
595 |
|
596 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_SUCCESS, |
597 |
[constants.OP_STATUS_SUCCESS, |
598 |
constants.OP_STATUS_SUCCESS], |
599 |
["Hello World", "Foo man bar"]) |
600 |
|
601 |
self.assertEqual(["Hello World", "Foo man bar"], |
602 |
cli.GenericPollJob(job_id, cbs, cbs)) |
603 |
cbs.CheckEmpty() |
604 |
|
605 |
def testJobLost(self): |
606 |
job_id = 13746
|
607 |
|
608 |
cbs = _MockJobPollCb(self, job_id)
|
609 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
610 |
cbs.AddWfjcResult(None, None, None) |
611 |
self.assertRaises(errors.JobLost, cli.GenericPollJob, job_id, cbs, cbs)
|
612 |
cbs.CheckEmpty() |
613 |
|
614 |
def testError(self): |
615 |
job_id = 31088
|
616 |
|
617 |
cbs = _MockJobPollCb(self, job_id)
|
618 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
619 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
620 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
621 |
[constants.OP_STATUS_SUCCESS, |
622 |
constants.OP_STATUS_ERROR], |
623 |
["Hello World", "Error code 123"]) |
624 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
625 |
cbs.CheckEmpty() |
626 |
|
627 |
def testError2(self): |
628 |
job_id = 22235
|
629 |
|
630 |
cbs = _MockJobPollCb(self, job_id)
|
631 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
632 |
encexc = errors.EncodeException(errors.LockError("problem"))
|
633 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
634 |
[constants.OP_STATUS_ERROR], [encexc]) |
635 |
self.assertRaises(errors.LockError, cli.GenericPollJob, job_id, cbs, cbs)
|
636 |
cbs.CheckEmpty() |
637 |
|
638 |
def testWeirdError(self): |
639 |
job_id = 28847
|
640 |
|
641 |
cbs = _MockJobPollCb(self, job_id)
|
642 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None)) |
643 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR, |
644 |
[constants.OP_STATUS_RUNNING, |
645 |
constants.OP_STATUS_RUNNING], |
646 |
[None, None]) |
647 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
648 |
cbs.CheckEmpty() |
649 |
|
650 |
def testCancel(self): |
651 |
job_id = 4275
|
652 |
|
653 |
cbs = _MockJobPollCb(self, job_id)
|
654 |
cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED) |
655 |
cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_CANCELING, ), None)) |
656 |
cbs.AddQueryJobsResult(constants.JOB_STATUS_CANCELING, |
657 |
[constants.OP_STATUS_CANCELING, |
658 |
constants.OP_STATUS_CANCELING], |
659 |
[None, None]) |
660 |
self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
|
661 |
cbs.CheckEmpty() |
662 |
|
663 |
|
664 |
class TestFormatLogMessage(unittest.TestCase): |
665 |
def test(self): |
666 |
self.assertEqual(cli.FormatLogMessage(constants.ELOG_MESSAGE,
|
667 |
"Hello World"),
|
668 |
"Hello World")
|
669 |
self.assertRaises(TypeError, cli.FormatLogMessage, |
670 |
constants.ELOG_MESSAGE, [1, 2, 3]) |
671 |
|
672 |
self.assert_(cli.FormatLogMessage("some other type", (1, 2, 3))) |
673 |
|
674 |
|
675 |
class TestParseFields(unittest.TestCase): |
676 |
def test(self): |
677 |
self.assertEqual(cli.ParseFields(None, []), []) |
678 |
self.assertEqual(cli.ParseFields("name,foo,hello", []), |
679 |
["name", "foo", "hello"]) |
680 |
self.assertEqual(cli.ParseFields(None, ["def", "ault", "fields", "here"]), |
681 |
["def", "ault", "fields", "here"]) |
682 |
self.assertEqual(cli.ParseFields("name,foo", ["def", "ault"]), |
683 |
["name", "foo"]) |
684 |
self.assertEqual(cli.ParseFields("+name,foo", ["def", "ault"]), |
685 |
["def", "ault", "name", "foo"]) |
686 |
|
687 |
|
688 |
class TestConstants(unittest.TestCase): |
689 |
def testPriority(self): |
690 |
self.assertEqual(set(cli._PRIONAME_TO_VALUE.values()), |
691 |
set(constants.OP_PRIO_SUBMIT_VALID))
|
692 |
self.assertEqual(list(value for _, value in cli._PRIORITY_NAMES), |
693 |
sorted(constants.OP_PRIO_SUBMIT_VALID, reverse=True)) |
694 |
|
695 |
|
696 |
class TestParseNicOption(unittest.TestCase): |
697 |
def test(self): |
698 |
self.assertEqual(cli.ParseNicOption([("0", { "link": "eth0", })]), |
699 |
[{ "link": "eth0", }]) |
700 |
self.assertEqual(cli.ParseNicOption([("5", { "ip": "192.0.2.7", })]), |
701 |
[{}, {}, {}, {}, {}, { "ip": "192.0.2.7", }]) |
702 |
|
703 |
def testErrors(self): |
704 |
for i in [None, "", "abc", "zero", "Hello World", "\0", []]: |
705 |
self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
|
706 |
[(i, { "link": "eth0", })]) |
707 |
self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
|
708 |
[("0", i)])
|
709 |
|
710 |
self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
|
711 |
[(0, { True: False, })]) |
712 |
|
713 |
self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
|
714 |
[(3, { "mode": [], })]) |
715 |
|
716 |
|
717 |
if __name__ == '__main__': |
718 |
testutils.GanetiTestProgram() |