Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cli_unittest.py @ 2466c0fd

History | View | Annotate | Download (24.6 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
      ]
383

    
384
    response = objects.QueryResponse(fields=fields, data=[
385
      [(constants.QRFS_NORMAL, 1), (constants.QRFS_UNKNOWN, None),
386
       (constants.QRFS_NORMAL, False), (constants.QRFS_NORMAL, "")],
387
      [(constants.QRFS_NORMAL, 2), (constants.QRFS_UNKNOWN, None),
388
       (constants.QRFS_NODATA, None), (constants.QRFS_NORMAL, "x")],
389
      [(constants.QRFS_NORMAL, 3), (constants.QRFS_UNKNOWN, None),
390
       (constants.QRFS_NORMAL, False), (constants.QRFS_UNAVAIL, None)],
391
      ])
392

    
393
    self.assertEqual(cli.FormatQueryResult(response, header=True,
394
                                           separator="|"),
395
      (cli.QR_UNKNOWN, [
396
      "ID|unk|Unavail|NoData",
397
      "1|(unknown)|N|",
398
      "2|(unknown)|(nodata)|x",
399
      "3|(unknown)|N|(unavail)",
400
      ]))
401

    
402
  def testNoData(self):
403
    fields = [
404
      objects.QueryFieldDefinition(name="id", title="ID",
405
                                   kind=constants.QFT_NUMBER),
406
      objects.QueryFieldDefinition(name="name", title="Name",
407
                                   kind=constants.QFT_TEXT),
408
      ]
409

    
410
    response = objects.QueryResponse(fields=fields, data=[])
411

    
412
    self.assertEqual(cli.FormatQueryResult(response, header=True),
413
                     (cli.QR_NORMAL, ["ID Name"]))
414

    
415
  def testNoDataWithUnknown(self):
416
    fields = [
417
      objects.QueryFieldDefinition(name="id", title="ID",
418
                                   kind=constants.QFT_NUMBER),
419
      objects.QueryFieldDefinition(name="unk", title="unk",
420
                                   kind=constants.QFT_UNKNOWN),
421
      ]
422

    
423
    response = objects.QueryResponse(fields=fields, data=[])
424

    
425
    self.assertEqual(cli.FormatQueryResult(response, header=False),
426
                     (cli.QR_UNKNOWN, []))
427

    
428
  def testStatus(self):
429
    fields = [
430
      objects.QueryFieldDefinition(name="id", title="ID",
431
                                   kind=constants.QFT_NUMBER),
432
      objects.QueryFieldDefinition(name="unavail", title="Unavail",
433
                                   kind=constants.QFT_BOOL),
434
      objects.QueryFieldDefinition(name="nodata", title="NoData",
435
                                   kind=constants.QFT_TEXT),
436
      ]
437

    
438
    response = objects.QueryResponse(fields=fields, data=[
439
      [(constants.QRFS_NORMAL, 1), (constants.QRFS_NORMAL, False),
440
       (constants.QRFS_NORMAL, "")],
441
      [(constants.QRFS_NORMAL, 2), (constants.QRFS_NODATA, None),
442
       (constants.QRFS_NORMAL, "x")],
443
      [(constants.QRFS_NORMAL, 3), (constants.QRFS_NORMAL, False),
444
       (constants.QRFS_UNAVAIL, None)],
445
      ])
446

    
447
    self.assertEqual(cli.FormatQueryResult(response, header=False,
448
                                           separator="|"),
449
      (cli.QR_INCOMPLETE, [
450
      "1|N|",
451
      "2|(nodata)|x",
452
      "3|N|(unavail)",
453
      ]))
454

    
455
  def testInvalidFieldType(self):
456
    fields = [
457
      objects.QueryFieldDefinition(name="x", title="x",
458
                                   kind="#some#other#type"),
459
      ]
460

    
461
    response = objects.QueryResponse(fields=fields, data=[])
462

    
463
    self.assertRaises(NotImplementedError, cli.FormatQueryResult, response)
464

    
465
  def testInvalidFieldStatus(self):
466
    fields = [
467
      objects.QueryFieldDefinition(name="x", title="x",
468
                                   kind=constants.QFT_TEXT),
469
      ]
470

    
471
    response = objects.QueryResponse(fields=fields, data=[[(-1, None)]])
472
    self.assertRaises(NotImplementedError, cli.FormatQueryResult, response)
473

    
474
    response = objects.QueryResponse(fields=fields, data=[[(-1, "x")]])
475
    self.assertRaises(AssertionError, cli.FormatQueryResult, response)
476

    
477
  def testEmptyFieldTitle(self):
478
    fields = [
479
      objects.QueryFieldDefinition(name="x", title="",
480
                                   kind=constants.QFT_TEXT),
481
      ]
482

    
483
    response = objects.QueryResponse(fields=fields, data=[])
484
    self.assertRaises(AssertionError, cli.FormatQueryResult, response)
485

    
486

    
487
class _MockJobPollCb(cli.JobPollCbBase, cli.JobPollReportCbBase):
488
  def __init__(self, tc, job_id):
489
    self.tc = tc
490
    self.job_id = job_id
491
    self._wfjcr = []
492
    self._jobstatus = []
493
    self._expect_notchanged = False
494
    self._expect_log = []
495

    
496
  def CheckEmpty(self):
497
    self.tc.assertFalse(self._wfjcr)
498
    self.tc.assertFalse(self._jobstatus)
499
    self.tc.assertFalse(self._expect_notchanged)
500
    self.tc.assertFalse(self._expect_log)
501

    
502
  def AddWfjcResult(self, *args):
503
    self._wfjcr.append(args)
504

    
505
  def AddQueryJobsResult(self, *args):
506
    self._jobstatus.append(args)
507

    
508
  def WaitForJobChangeOnce(self, job_id, fields,
509
                           prev_job_info, prev_log_serial):
510
    self.tc.assertEqual(job_id, self.job_id)
511
    self.tc.assertEqualValues(fields, ["status"])
512
    self.tc.assertFalse(self._expect_notchanged)
513
    self.tc.assertFalse(self._expect_log)
514

    
515
    (exp_prev_job_info, exp_prev_log_serial, result) = self._wfjcr.pop(0)
516
    self.tc.assertEqualValues(prev_job_info, exp_prev_job_info)
517
    self.tc.assertEqual(prev_log_serial, exp_prev_log_serial)
518

    
519
    if result == constants.JOB_NOTCHANGED:
520
      self._expect_notchanged = True
521
    elif result:
522
      (_, logmsgs) = result
523
      if logmsgs:
524
        self._expect_log.extend(logmsgs)
525

    
526
    return result
527

    
528
  def QueryJobs(self, job_ids, fields):
529
    self.tc.assertEqual(job_ids, [self.job_id])
530
    self.tc.assertEqualValues(fields, ["status", "opstatus", "opresult"])
531
    self.tc.assertFalse(self._expect_notchanged)
532
    self.tc.assertFalse(self._expect_log)
533

    
534
    result = self._jobstatus.pop(0)
535
    self.tc.assertEqual(len(fields), len(result))
536
    return [result]
537

    
538
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
539
    self.tc.assertEqual(job_id, self.job_id)
540
    self.tc.assertEqualValues((serial, timestamp, log_type, log_msg),
541
                              self._expect_log.pop(0))
542

    
543
  def ReportNotChanged(self, job_id, status):
544
    self.tc.assertEqual(job_id, self.job_id)
545
    self.tc.assert_(self._expect_notchanged)
546
    self._expect_notchanged = False
547

    
548

    
549
class TestGenericPollJob(testutils.GanetiTestCase):
550
  def testSuccessWithLog(self):
551
    job_id = 29609
552
    cbs = _MockJobPollCb(self, job_id)
553

    
554
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
555

    
556
    cbs.AddWfjcResult(None, None,
557
                      ((constants.JOB_STATUS_QUEUED, ), None))
558

    
559
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
560
                      constants.JOB_NOTCHANGED)
561

    
562
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
563
                      ((constants.JOB_STATUS_RUNNING, ),
564
                       [(1, utils.SplitTime(1273491611.0),
565
                         constants.ELOG_MESSAGE, "Step 1"),
566
                        (2, utils.SplitTime(1273491615.9),
567
                         constants.ELOG_MESSAGE, "Step 2"),
568
                        (3, utils.SplitTime(1273491625.02),
569
                         constants.ELOG_MESSAGE, "Step 3"),
570
                        (4, utils.SplitTime(1273491635.05),
571
                         constants.ELOG_MESSAGE, "Step 4"),
572
                        (37, utils.SplitTime(1273491645.0),
573
                         constants.ELOG_MESSAGE, "Step 5"),
574
                        (203, utils.SplitTime(127349155.0),
575
                         constants.ELOG_MESSAGE, "Step 6")]))
576

    
577
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 203,
578
                      ((constants.JOB_STATUS_RUNNING, ),
579
                       [(300, utils.SplitTime(1273491711.01),
580
                         constants.ELOG_MESSAGE, "Step X"),
581
                        (302, utils.SplitTime(1273491815.8),
582
                         constants.ELOG_MESSAGE, "Step Y"),
583
                        (303, utils.SplitTime(1273491925.32),
584
                         constants.ELOG_MESSAGE, "Step Z")]))
585

    
586
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 303,
587
                      ((constants.JOB_STATUS_SUCCESS, ), None))
588

    
589
    cbs.AddQueryJobsResult(constants.JOB_STATUS_SUCCESS,
590
                           [constants.OP_STATUS_SUCCESS,
591
                            constants.OP_STATUS_SUCCESS],
592
                           ["Hello World", "Foo man bar"])
593

    
594
    self.assertEqual(["Hello World", "Foo man bar"],
595
                     cli.GenericPollJob(job_id, cbs, cbs))
596
    cbs.CheckEmpty()
597

    
598
  def testJobLost(self):
599
    job_id = 13746
600

    
601
    cbs = _MockJobPollCb(self, job_id)
602
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
603
    cbs.AddWfjcResult(None, None, None)
604
    self.assertRaises(errors.JobLost, cli.GenericPollJob, job_id, cbs, cbs)
605
    cbs.CheckEmpty()
606

    
607
  def testError(self):
608
    job_id = 31088
609

    
610
    cbs = _MockJobPollCb(self, job_id)
611
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
612
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
613
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
614
                           [constants.OP_STATUS_SUCCESS,
615
                            constants.OP_STATUS_ERROR],
616
                           ["Hello World", "Error code 123"])
617
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
618
    cbs.CheckEmpty()
619

    
620
  def testError2(self):
621
    job_id = 22235
622

    
623
    cbs = _MockJobPollCb(self, job_id)
624
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
625
    encexc = errors.EncodeException(errors.LockError("problem"))
626
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
627
                           [constants.OP_STATUS_ERROR], [encexc])
628
    self.assertRaises(errors.LockError, cli.GenericPollJob, job_id, cbs, cbs)
629
    cbs.CheckEmpty()
630

    
631
  def testWeirdError(self):
632
    job_id = 28847
633

    
634
    cbs = _MockJobPollCb(self, job_id)
635
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
636
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
637
                           [constants.OP_STATUS_RUNNING,
638
                            constants.OP_STATUS_RUNNING],
639
                           [None, None])
640
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
641
    cbs.CheckEmpty()
642

    
643
  def testCancel(self):
644
    job_id = 4275
645

    
646
    cbs = _MockJobPollCb(self, job_id)
647
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
648
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_CANCELING, ), None))
649
    cbs.AddQueryJobsResult(constants.JOB_STATUS_CANCELING,
650
                           [constants.OP_STATUS_CANCELING,
651
                            constants.OP_STATUS_CANCELING],
652
                           [None, None])
653
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
654
    cbs.CheckEmpty()
655

    
656

    
657
class TestFormatLogMessage(unittest.TestCase):
658
  def test(self):
659
    self.assertEqual(cli.FormatLogMessage(constants.ELOG_MESSAGE,
660
                                          "Hello World"),
661
                     "Hello World")
662
    self.assertRaises(TypeError, cli.FormatLogMessage,
663
                      constants.ELOG_MESSAGE, [1, 2, 3])
664

    
665
    self.assert_(cli.FormatLogMessage("some other type", (1, 2, 3)))
666

    
667

    
668
class TestParseFields(unittest.TestCase):
669
  def test(self):
670
    self.assertEqual(cli.ParseFields(None, []), [])
671
    self.assertEqual(cli.ParseFields("name,foo,hello", []),
672
                     ["name", "foo", "hello"])
673
    self.assertEqual(cli.ParseFields(None, ["def", "ault", "fields", "here"]),
674
                     ["def", "ault", "fields", "here"])
675
    self.assertEqual(cli.ParseFields("name,foo", ["def", "ault"]),
676
                     ["name", "foo"])
677
    self.assertEqual(cli.ParseFields("+name,foo", ["def", "ault"]),
678
                     ["def", "ault", "name", "foo"])
679

    
680

    
681
class TestConstants(unittest.TestCase):
682
  def testPriority(self):
683
    self.assertEqual(set(cli._PRIONAME_TO_VALUE.values()),
684
                     set(constants.OP_PRIO_SUBMIT_VALID))
685
    self.assertEqual(list(value for _, value in cli._PRIORITY_NAMES),
686
                     sorted(constants.OP_PRIO_SUBMIT_VALID, reverse=True))
687

    
688

    
689
class TestParseNicOption(unittest.TestCase):
690
  def test(self):
691
    self.assertEqual(cli.ParseNicOption([("0", { "link": "eth0", })]),
692
                     [{ "link": "eth0", }])
693
    self.assertEqual(cli.ParseNicOption([("5", { "ip": "192.0.2.7", })]),
694
                     [{}, {}, {}, {}, {}, { "ip": "192.0.2.7", }])
695

    
696
  def testErrors(self):
697
    for i in [None, "", "abc", "zero", "Hello World", "\0", []]:
698
      self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
699
                        [(i, { "link": "eth0", })])
700
      self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
701
                        [("0", i)])
702

    
703
    self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
704
                      [(0, { True: False, })])
705

    
706
    self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
707
                      [(3, { "mode": [], })])
708

    
709

    
710
if __name__ == '__main__':
711
  testutils.GanetiTestProgram()