Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cli_unittest.py @ f0b1bafe

History | View | Annotate | Download (25.5 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2008, 2011 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.RS_NORMAL, "nodeA"), (constants.RS_NORMAL, 128),
269
       (constants.RS_NORMAL, False), (constants.RS_NORMAL, 1468006),
270
       (constants.RS_NORMAL, [])],
271
      [(constants.RS_NORMAL, "other"), (constants.RS_NORMAL, 512),
272
       (constants.RS_NORMAL, True), (constants.RS_NORMAL, 16),
273
       (constants.RS_NORMAL, [1, 2, 3])],
274
      [(constants.RS_NORMAL, "xyz"), (constants.RS_NORMAL, 1024),
275
       (constants.RS_NORMAL, True), (constants.RS_NORMAL, 4096),
276
       (constants.RS_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.RS_NORMAL, "a"), (constants.RS_NORMAL, 1024),
299
       (constants.RS_NORMAL, 0)],
300
      [(constants.RS_NORMAL, "b"), (constants.RS_NORMAL, 144996),
301
       (constants.RS_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.RS_NORMAL, "x"), (constants.RS_NORMAL, ["a", "b", "c"]),
323
       (constants.RS_NORMAL, 1234)],
324
      [(constants.RS_NORMAL, "y"), (constants.RS_NORMAL, range(10)),
325
       (constants.RS_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.RS_NORMAL, "instance1.example.com"),
353
       (constants.RS_NORMAL, 21125), (constants.RS_NORMAL, "Hello World!")],
354
      [(constants.RS_NORMAL, "mail.other.net"),
355
       (constants.RS_NORMAL, -9000), (constants.RS_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.RS_NORMAL, 1), (constants.RS_UNKNOWN, None),
388
       (constants.RS_NORMAL, False), (constants.RS_NORMAL, ""),
389
       (constants.RS_OFFLINE, None)],
390
      [(constants.RS_NORMAL, 2), (constants.RS_UNKNOWN, None),
391
       (constants.RS_NODATA, None), (constants.RS_NORMAL, "x"),
392
       (constants.RS_OFFLINE, None)],
393
      [(constants.RS_NORMAL, 3), (constants.RS_UNKNOWN, None),
394
       (constants.RS_NORMAL, False), (constants.RS_UNAVAIL, None),
395
       (constants.RS_OFFLINE, None)],
396
      ])
397

    
398
    self.assertEqual(cli.FormatQueryResult(response, header=True,
399
                                           separator="|", verbose=True),
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
    self.assertEqual(cli.FormatQueryResult(response, header=True,
407
                                           separator="|", verbose=False),
408
      (cli.QR_UNKNOWN, [
409
      "ID|unk|Unavail|NoData|OffLine",
410
      "1|??|N||*",
411
      "2|??|?|x|*",
412
      "3|??|N|-|*",
413
      ]))
414

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

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

    
425
    self.assertEqual(cli.FormatQueryResult(response, header=True),
426
                     (cli.QR_NORMAL, ["ID Name"]))
427

    
428
  def testNoDataWithUnknown(self):
429
    fields = [
430
      objects.QueryFieldDefinition(name="id", title="ID",
431
                                   kind=constants.QFT_NUMBER),
432
      objects.QueryFieldDefinition(name="unk", title="unk",
433
                                   kind=constants.QFT_UNKNOWN),
434
      ]
435

    
436
    response = objects.QueryResponse(fields=fields, data=[])
437

    
438
    self.assertEqual(cli.FormatQueryResult(response, header=False),
439
                     (cli.QR_UNKNOWN, []))
440

    
441
  def testStatus(self):
442
    fields = [
443
      objects.QueryFieldDefinition(name="id", title="ID",
444
                                   kind=constants.QFT_NUMBER),
445
      objects.QueryFieldDefinition(name="unavail", title="Unavail",
446
                                   kind=constants.QFT_BOOL),
447
      objects.QueryFieldDefinition(name="nodata", title="NoData",
448
                                   kind=constants.QFT_TEXT),
449
      objects.QueryFieldDefinition(name="offline", title="OffLine",
450
                                   kind=constants.QFT_TEXT),
451
      ]
452

    
453
    response = objects.QueryResponse(fields=fields, data=[
454
      [(constants.RS_NORMAL, 1), (constants.RS_NORMAL, False),
455
       (constants.RS_NORMAL, ""), (constants.RS_OFFLINE, None)],
456
      [(constants.RS_NORMAL, 2), (constants.RS_NODATA, None),
457
       (constants.RS_NORMAL, "x"), (constants.RS_NORMAL, "abc")],
458
      [(constants.RS_NORMAL, 3), (constants.RS_NORMAL, False),
459
       (constants.RS_UNAVAIL, None), (constants.RS_OFFLINE, None)],
460
      ])
461

    
462
    self.assertEqual(cli.FormatQueryResult(response, header=False,
463
                                           separator="|", verbose=True),
464
      (cli.QR_INCOMPLETE, [
465
      "1|N||(offline)",
466
      "2|(nodata)|x|abc",
467
      "3|N|(unavail)|(offline)",
468
      ]))
469
    self.assertEqual(cli.FormatQueryResult(response, header=False,
470
                                           separator="|", verbose=False),
471
      (cli.QR_INCOMPLETE, [
472
      "1|N||*",
473
      "2|?|x|abc",
474
      "3|N|-|*",
475
      ]))
476

    
477
  def testInvalidFieldType(self):
478
    fields = [
479
      objects.QueryFieldDefinition(name="x", title="x",
480
                                   kind="#some#other#type"),
481
      ]
482

    
483
    response = objects.QueryResponse(fields=fields, data=[])
484

    
485
    self.assertRaises(NotImplementedError, cli.FormatQueryResult, response)
486

    
487
  def testInvalidFieldStatus(self):
488
    fields = [
489
      objects.QueryFieldDefinition(name="x", title="x",
490
                                   kind=constants.QFT_TEXT),
491
      ]
492

    
493
    response = objects.QueryResponse(fields=fields, data=[[(-1, None)]])
494
    self.assertRaises(NotImplementedError, cli.FormatQueryResult, response)
495

    
496
    response = objects.QueryResponse(fields=fields, data=[[(-1, "x")]])
497
    self.assertRaises(AssertionError, cli.FormatQueryResult, response)
498

    
499
  def testEmptyFieldTitle(self):
500
    fields = [
501
      objects.QueryFieldDefinition(name="x", title="",
502
                                   kind=constants.QFT_TEXT),
503
      ]
504

    
505
    response = objects.QueryResponse(fields=fields, data=[])
506
    self.assertRaises(AssertionError, cli.FormatQueryResult, response)
507

    
508

    
509
class _MockJobPollCb(cli.JobPollCbBase, cli.JobPollReportCbBase):
510
  def __init__(self, tc, job_id):
511
    self.tc = tc
512
    self.job_id = job_id
513
    self._wfjcr = []
514
    self._jobstatus = []
515
    self._expect_notchanged = False
516
    self._expect_log = []
517

    
518
  def CheckEmpty(self):
519
    self.tc.assertFalse(self._wfjcr)
520
    self.tc.assertFalse(self._jobstatus)
521
    self.tc.assertFalse(self._expect_notchanged)
522
    self.tc.assertFalse(self._expect_log)
523

    
524
  def AddWfjcResult(self, *args):
525
    self._wfjcr.append(args)
526

    
527
  def AddQueryJobsResult(self, *args):
528
    self._jobstatus.append(args)
529

    
530
  def WaitForJobChangeOnce(self, job_id, fields,
531
                           prev_job_info, prev_log_serial):
532
    self.tc.assertEqual(job_id, self.job_id)
533
    self.tc.assertEqualValues(fields, ["status"])
534
    self.tc.assertFalse(self._expect_notchanged)
535
    self.tc.assertFalse(self._expect_log)
536

    
537
    (exp_prev_job_info, exp_prev_log_serial, result) = self._wfjcr.pop(0)
538
    self.tc.assertEqualValues(prev_job_info, exp_prev_job_info)
539
    self.tc.assertEqual(prev_log_serial, exp_prev_log_serial)
540

    
541
    if result == constants.JOB_NOTCHANGED:
542
      self._expect_notchanged = True
543
    elif result:
544
      (_, logmsgs) = result
545
      if logmsgs:
546
        self._expect_log.extend(logmsgs)
547

    
548
    return result
549

    
550
  def QueryJobs(self, job_ids, fields):
551
    self.tc.assertEqual(job_ids, [self.job_id])
552
    self.tc.assertEqualValues(fields, ["status", "opstatus", "opresult"])
553
    self.tc.assertFalse(self._expect_notchanged)
554
    self.tc.assertFalse(self._expect_log)
555

    
556
    result = self._jobstatus.pop(0)
557
    self.tc.assertEqual(len(fields), len(result))
558
    return [result]
559

    
560
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
561
    self.tc.assertEqual(job_id, self.job_id)
562
    self.tc.assertEqualValues((serial, timestamp, log_type, log_msg),
563
                              self._expect_log.pop(0))
564

    
565
  def ReportNotChanged(self, job_id, status):
566
    self.tc.assertEqual(job_id, self.job_id)
567
    self.tc.assert_(self._expect_notchanged)
568
    self._expect_notchanged = False
569

    
570

    
571
class TestGenericPollJob(testutils.GanetiTestCase):
572
  def testSuccessWithLog(self):
573
    job_id = 29609
574
    cbs = _MockJobPollCb(self, job_id)
575

    
576
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
577

    
578
    cbs.AddWfjcResult(None, None,
579
                      ((constants.JOB_STATUS_QUEUED, ), None))
580

    
581
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
582
                      constants.JOB_NOTCHANGED)
583

    
584
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
585
                      ((constants.JOB_STATUS_RUNNING, ),
586
                       [(1, utils.SplitTime(1273491611.0),
587
                         constants.ELOG_MESSAGE, "Step 1"),
588
                        (2, utils.SplitTime(1273491615.9),
589
                         constants.ELOG_MESSAGE, "Step 2"),
590
                        (3, utils.SplitTime(1273491625.02),
591
                         constants.ELOG_MESSAGE, "Step 3"),
592
                        (4, utils.SplitTime(1273491635.05),
593
                         constants.ELOG_MESSAGE, "Step 4"),
594
                        (37, utils.SplitTime(1273491645.0),
595
                         constants.ELOG_MESSAGE, "Step 5"),
596
                        (203, utils.SplitTime(127349155.0),
597
                         constants.ELOG_MESSAGE, "Step 6")]))
598

    
599
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 203,
600
                      ((constants.JOB_STATUS_RUNNING, ),
601
                       [(300, utils.SplitTime(1273491711.01),
602
                         constants.ELOG_MESSAGE, "Step X"),
603
                        (302, utils.SplitTime(1273491815.8),
604
                         constants.ELOG_MESSAGE, "Step Y"),
605
                        (303, utils.SplitTime(1273491925.32),
606
                         constants.ELOG_MESSAGE, "Step Z")]))
607

    
608
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 303,
609
                      ((constants.JOB_STATUS_SUCCESS, ), None))
610

    
611
    cbs.AddQueryJobsResult(constants.JOB_STATUS_SUCCESS,
612
                           [constants.OP_STATUS_SUCCESS,
613
                            constants.OP_STATUS_SUCCESS],
614
                           ["Hello World", "Foo man bar"])
615

    
616
    self.assertEqual(["Hello World", "Foo man bar"],
617
                     cli.GenericPollJob(job_id, cbs, cbs))
618
    cbs.CheckEmpty()
619

    
620
  def testJobLost(self):
621
    job_id = 13746
622

    
623
    cbs = _MockJobPollCb(self, job_id)
624
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
625
    cbs.AddWfjcResult(None, None, None)
626
    self.assertRaises(errors.JobLost, cli.GenericPollJob, job_id, cbs, cbs)
627
    cbs.CheckEmpty()
628

    
629
  def testError(self):
630
    job_id = 31088
631

    
632
    cbs = _MockJobPollCb(self, job_id)
633
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
634
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
635
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
636
                           [constants.OP_STATUS_SUCCESS,
637
                            constants.OP_STATUS_ERROR],
638
                           ["Hello World", "Error code 123"])
639
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
640
    cbs.CheckEmpty()
641

    
642
  def testError2(self):
643
    job_id = 22235
644

    
645
    cbs = _MockJobPollCb(self, job_id)
646
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
647
    encexc = errors.EncodeException(errors.LockError("problem"))
648
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
649
                           [constants.OP_STATUS_ERROR], [encexc])
650
    self.assertRaises(errors.LockError, cli.GenericPollJob, job_id, cbs, cbs)
651
    cbs.CheckEmpty()
652

    
653
  def testWeirdError(self):
654
    job_id = 28847
655

    
656
    cbs = _MockJobPollCb(self, job_id)
657
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
658
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
659
                           [constants.OP_STATUS_RUNNING,
660
                            constants.OP_STATUS_RUNNING],
661
                           [None, None])
662
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
663
    cbs.CheckEmpty()
664

    
665
  def testCancel(self):
666
    job_id = 4275
667

    
668
    cbs = _MockJobPollCb(self, job_id)
669
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
670
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_CANCELING, ), None))
671
    cbs.AddQueryJobsResult(constants.JOB_STATUS_CANCELING,
672
                           [constants.OP_STATUS_CANCELING,
673
                            constants.OP_STATUS_CANCELING],
674
                           [None, None])
675
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
676
    cbs.CheckEmpty()
677

    
678

    
679
class TestFormatLogMessage(unittest.TestCase):
680
  def test(self):
681
    self.assertEqual(cli.FormatLogMessage(constants.ELOG_MESSAGE,
682
                                          "Hello World"),
683
                     "Hello World")
684
    self.assertRaises(TypeError, cli.FormatLogMessage,
685
                      constants.ELOG_MESSAGE, [1, 2, 3])
686

    
687
    self.assert_(cli.FormatLogMessage("some other type", (1, 2, 3)))
688

    
689

    
690
class TestParseFields(unittest.TestCase):
691
  def test(self):
692
    self.assertEqual(cli.ParseFields(None, []), [])
693
    self.assertEqual(cli.ParseFields("name,foo,hello", []),
694
                     ["name", "foo", "hello"])
695
    self.assertEqual(cli.ParseFields(None, ["def", "ault", "fields", "here"]),
696
                     ["def", "ault", "fields", "here"])
697
    self.assertEqual(cli.ParseFields("name,foo", ["def", "ault"]),
698
                     ["name", "foo"])
699
    self.assertEqual(cli.ParseFields("+name,foo", ["def", "ault"]),
700
                     ["def", "ault", "name", "foo"])
701

    
702

    
703
class TestConstants(unittest.TestCase):
704
  def testPriority(self):
705
    self.assertEqual(set(cli._PRIONAME_TO_VALUE.values()),
706
                     set(constants.OP_PRIO_SUBMIT_VALID))
707
    self.assertEqual(list(value for _, value in cli._PRIORITY_NAMES),
708
                     sorted(constants.OP_PRIO_SUBMIT_VALID, reverse=True))
709

    
710

    
711
class TestParseNicOption(unittest.TestCase):
712
  def test(self):
713
    self.assertEqual(cli.ParseNicOption([("0", { "link": "eth0", })]),
714
                     [{ "link": "eth0", }])
715
    self.assertEqual(cli.ParseNicOption([("5", { "ip": "192.0.2.7", })]),
716
                     [{}, {}, {}, {}, {}, { "ip": "192.0.2.7", }])
717

    
718
  def testErrors(self):
719
    for i in [None, "", "abc", "zero", "Hello World", "\0", []]:
720
      self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
721
                        [(i, { "link": "eth0", })])
722
      self.assertRaises(errors.OpPrereqError, cli.ParseNicOption,
723
                        [("0", i)])
724

    
725
    self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
726
                      [(0, { True: False, })])
727

    
728
    self.assertRaises(errors.TypeEnforcementError, cli.ParseNicOption,
729
                      [(3, { "mode": [], })])
730

    
731

    
732
if __name__ == '__main__':
733
  testutils.GanetiTestProgram()