Statistics
| Branch: | Tag: | Revision:

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()