Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cli_unittest.py @ a4ebd726

History | View | Annotate | Download (14.2 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.errors import OpPrereqError, ParameterError
35

    
36

    
37
class TestParseTimespec(unittest.TestCase):
38
  """Testing case for ParseTimespec"""
39

    
40
  def testValidTimes(self):
41
    """Test valid timespecs"""
42
    test_data = [
43
      ('1s', 1),
44
      ('1', 1),
45
      ('1m', 60),
46
      ('1h', 60 * 60),
47
      ('1d', 60 * 60 * 24),
48
      ('1w', 60 * 60 * 24 * 7),
49
      ('4h', 4 * 60 * 60),
50
      ('61m', 61 * 60),
51
      ]
52
    for value, expected_result in test_data:
53
      self.failUnlessEqual(cli.ParseTimespec(value), expected_result)
54

    
55
  def testInvalidTime(self):
56
    """Test invalid timespecs"""
57
    test_data = [
58
      '1y',
59
      '',
60
      'aaa',
61
      's',
62
      ]
63
    for value in test_data:
64
      self.failUnlessRaises(OpPrereqError, cli.ParseTimespec, value)
65

    
66

    
67
class TestSplitKeyVal(unittest.TestCase):
68
  """Testing case for cli._SplitKeyVal"""
69
  DATA = "a=b,c,no_d,-e"
70
  RESULT = {"a": "b", "c": True, "d": False, "e": None}
71

    
72
  def testSplitKeyVal(self):
73
    """Test splitting"""
74
    self.failUnlessEqual(cli._SplitKeyVal("option", self.DATA), self.RESULT)
75

    
76
  def testDuplicateParam(self):
77
    """Test duplicate parameters"""
78
    for data in ("a=1,a=2", "a,no_a"):
79
      self.failUnlessRaises(ParameterError, cli._SplitKeyVal,
80
                            "option", data)
81

    
82
  def testEmptyData(self):
83
    """Test how we handle splitting an empty string"""
84
    self.failUnlessEqual(cli._SplitKeyVal("option", ""), {})
85

    
86
class TestIdentKeyVal(unittest.TestCase):
87
  """Testing case for cli.check_ident_key_val"""
88

    
89
  def testIdentKeyVal(self):
90
    """Test identkeyval"""
91
    def cikv(value):
92
      return cli.check_ident_key_val("option", "opt", value)
93

    
94
    self.assertEqual(cikv("foo:bar"), ("foo", {"bar": True}))
95
    self.assertEqual(cikv("foo:bar=baz"), ("foo", {"bar": "baz"}))
96
    self.assertEqual(cikv("bar:b=c,c=a"), ("bar", {"b": "c", "c": "a"}))
97
    self.assertEqual(cikv("no_bar"), ("bar", False))
98
    self.assertRaises(ParameterError, cikv, "no_bar:foo")
99
    self.assertRaises(ParameterError, cikv, "no_bar:foo=baz")
100
    self.assertEqual(cikv("-foo"), ("foo", None))
101
    self.assertRaises(ParameterError, cikv, "-foo:a=c")
102

    
103

    
104
class TestToStream(unittest.TestCase):
105
  """Test the ToStream functions"""
106

    
107
  def testBasic(self):
108
    for data in ["foo",
109
                 "foo %s",
110
                 "foo %(test)s",
111
                 "foo %s %s",
112
                 "",
113
                 ]:
114
      buf = StringIO()
115
      cli._ToStream(buf, data)
116
      self.failUnlessEqual(buf.getvalue(), data+'\n')
117

    
118
  def testParams(self):
119
      buf = StringIO()
120
      cli._ToStream(buf, "foo %s", 1)
121
      self.failUnlessEqual(buf.getvalue(), "foo 1\n")
122
      buf = StringIO()
123
      cli._ToStream(buf, "foo %s", (15,16))
124
      self.failUnlessEqual(buf.getvalue(), "foo (15, 16)\n")
125
      buf = StringIO()
126
      cli._ToStream(buf, "foo %s %s", "a", "b")
127
      self.failUnlessEqual(buf.getvalue(), "foo a b\n")
128

    
129

    
130
class TestGenerateTable(unittest.TestCase):
131
  HEADERS = dict([("f%s" % i, "Field%s" % i) for i in range(5)])
132

    
133
  FIELDS1 = ["f1", "f2"]
134
  DATA1 = [
135
    ["abc", 1234],
136
    ["foobar", 56],
137
    ["b", -14],
138
    ]
139

    
140
  def _test(self, headers, fields, separator, data,
141
            numfields, unitfields, units, expected):
142
    table = cli.GenerateTable(headers, fields, separator, data,
143
                              numfields=numfields, unitfields=unitfields,
144
                              units=units)
145
    self.assertEqual(table, expected)
146

    
147
  def testPlain(self):
148
    exp = [
149
      "Field1 Field2",
150
      "abc    1234",
151
      "foobar 56",
152
      "b      -14",
153
      ]
154
    self._test(self.HEADERS, self.FIELDS1, None, self.DATA1,
155
               None, None, "m", exp)
156

    
157
  def testNoFields(self):
158
    self._test(self.HEADERS, [], None, [[], []],
159
               None, None, "m", ["", "", ""])
160
    self._test(None, [], None, [[], []],
161
               None, None, "m", ["", ""])
162

    
163
  def testSeparator(self):
164
    for sep in ["#", ":", ",", "^", "!", "%", "|", "###", "%%", "!!!", "||"]:
165
      exp = [
166
        "Field1%sField2" % sep,
167
        "abc%s1234" % sep,
168
        "foobar%s56" % sep,
169
        "b%s-14" % sep,
170
        ]
171
      self._test(self.HEADERS, self.FIELDS1, sep, self.DATA1,
172
                 None, None, "m", exp)
173

    
174
  def testNoHeader(self):
175
    exp = [
176
      "abc    1234",
177
      "foobar 56",
178
      "b      -14",
179
      ]
180
    self._test(None, self.FIELDS1, None, self.DATA1,
181
               None, None, "m", exp)
182

    
183
  def testUnknownField(self):
184
    headers = {
185
      "f1": "Field1",
186
      }
187
    exp = [
188
      "Field1 UNKNOWN",
189
      "abc    1234",
190
      "foobar 56",
191
      "b      -14",
192
      ]
193
    self._test(headers, ["f1", "UNKNOWN"], None, self.DATA1,
194
               None, None, "m", exp)
195

    
196
  def testNumfields(self):
197
    fields = ["f1", "f2", "f3"]
198
    data = [
199
      ["abc", 1234, 0],
200
      ["foobar", 56, 3],
201
      ["b", -14, "-"],
202
      ]
203
    exp = [
204
      "Field1 Field2 Field3",
205
      "abc      1234      0",
206
      "foobar     56      3",
207
      "b         -14      -",
208
      ]
209
    self._test(self.HEADERS, fields, None, data,
210
               ["f2", "f3"], None, "m", exp)
211

    
212
  def testUnitfields(self):
213
    expnosep = [
214
      "Field1 Field2 Field3",
215
      "abc      1234     0M",
216
      "foobar     56     3M",
217
      "b         -14      -",
218
      ]
219

    
220
    expsep = [
221
      "Field1:Field2:Field3",
222
      "abc:1234:0M",
223
      "foobar:56:3M",
224
      "b:-14:-",
225
      ]
226

    
227
    for sep, expected in [(None, expnosep), (":", expsep)]:
228
      fields = ["f1", "f2", "f3"]
229
      data = [
230
        ["abc", 1234, 0],
231
        ["foobar", 56, 3],
232
        ["b", -14, "-"],
233
        ]
234
      self._test(self.HEADERS, fields, sep, data,
235
                 ["f2", "f3"], ["f3"], "h", expected)
236

    
237
  def testUnusual(self):
238
    data = [
239
      ["%", "xyz"],
240
      ["%%", "abc"],
241
      ]
242
    exp = [
243
      "Field1 Field2",
244
      "%      xyz",
245
      "%%     abc",
246
      ]
247
    self._test(self.HEADERS, ["f1", "f2"], None, data,
248
               None, None, "m", exp)
249

    
250

    
251
class _MockJobPollCb(cli.JobPollCbBase, cli.JobPollReportCbBase):
252
  def __init__(self, tc, job_id):
253
    self.tc = tc
254
    self.job_id = job_id
255
    self._wfjcr = []
256
    self._jobstatus = []
257
    self._expect_notchanged = False
258
    self._expect_log = []
259

    
260
  def CheckEmpty(self):
261
    self.tc.assertFalse(self._wfjcr)
262
    self.tc.assertFalse(self._jobstatus)
263
    self.tc.assertFalse(self._expect_notchanged)
264
    self.tc.assertFalse(self._expect_log)
265

    
266
  def AddWfjcResult(self, *args):
267
    self._wfjcr.append(args)
268

    
269
  def AddQueryJobsResult(self, *args):
270
    self._jobstatus.append(args)
271

    
272
  def WaitForJobChangeOnce(self, job_id, fields,
273
                           prev_job_info, prev_log_serial):
274
    self.tc.assertEqual(job_id, self.job_id)
275
    self.tc.assertEqualValues(fields, ["status"])
276
    self.tc.assertFalse(self._expect_notchanged)
277
    self.tc.assertFalse(self._expect_log)
278

    
279
    (exp_prev_job_info, exp_prev_log_serial, result) = self._wfjcr.pop(0)
280
    self.tc.assertEqualValues(prev_job_info, exp_prev_job_info)
281
    self.tc.assertEqual(prev_log_serial, exp_prev_log_serial)
282

    
283
    if result == constants.JOB_NOTCHANGED:
284
      self._expect_notchanged = True
285
    elif result:
286
      (_, logmsgs) = result
287
      if logmsgs:
288
        self._expect_log.extend(logmsgs)
289

    
290
    return result
291

    
292
  def QueryJobs(self, job_ids, fields):
293
    self.tc.assertEqual(job_ids, [self.job_id])
294
    self.tc.assertEqualValues(fields, ["status", "opstatus", "opresult"])
295
    self.tc.assertFalse(self._expect_notchanged)
296
    self.tc.assertFalse(self._expect_log)
297

    
298
    result = self._jobstatus.pop(0)
299
    self.tc.assertEqual(len(fields), len(result))
300
    return [result]
301

    
302
  def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg):
303
    self.tc.assertEqual(job_id, self.job_id)
304
    self.tc.assertEqualValues((serial, timestamp, log_type, log_msg),
305
                              self._expect_log.pop(0))
306

    
307
  def ReportNotChanged(self, job_id, status):
308
    self.tc.assertEqual(job_id, self.job_id)
309
    self.tc.assert_(self._expect_notchanged)
310
    self._expect_notchanged = False
311

    
312

    
313
class TestGenericPollJob(testutils.GanetiTestCase):
314
  def testSuccessWithLog(self):
315
    job_id = 29609
316
    cbs = _MockJobPollCb(self, job_id)
317

    
318
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
319

    
320
    cbs.AddWfjcResult(None, None,
321
                      ((constants.JOB_STATUS_QUEUED, ), None))
322

    
323
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
324
                      constants.JOB_NOTCHANGED)
325

    
326
    cbs.AddWfjcResult((constants.JOB_STATUS_QUEUED, ), None,
327
                      ((constants.JOB_STATUS_RUNNING, ),
328
                       [(1, utils.SplitTime(1273491611.0),
329
                         constants.ELOG_MESSAGE, "Step 1"),
330
                        (2, utils.SplitTime(1273491615.9),
331
                         constants.ELOG_MESSAGE, "Step 2"),
332
                        (3, utils.SplitTime(1273491625.02),
333
                         constants.ELOG_MESSAGE, "Step 3"),
334
                        (4, utils.SplitTime(1273491635.05),
335
                         constants.ELOG_MESSAGE, "Step 4"),
336
                        (37, utils.SplitTime(1273491645.0),
337
                         constants.ELOG_MESSAGE, "Step 5"),
338
                        (203, utils.SplitTime(127349155.0),
339
                         constants.ELOG_MESSAGE, "Step 6")]))
340

    
341
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 203,
342
                      ((constants.JOB_STATUS_RUNNING, ),
343
                       [(300, utils.SplitTime(1273491711.01),
344
                         constants.ELOG_MESSAGE, "Step X"),
345
                        (302, utils.SplitTime(1273491815.8),
346
                         constants.ELOG_MESSAGE, "Step Y"),
347
                        (303, utils.SplitTime(1273491925.32),
348
                         constants.ELOG_MESSAGE, "Step Z")]))
349

    
350
    cbs.AddWfjcResult((constants.JOB_STATUS_RUNNING, ), 303,
351
                      ((constants.JOB_STATUS_SUCCESS, ), None))
352

    
353
    cbs.AddQueryJobsResult(constants.JOB_STATUS_SUCCESS,
354
                           [constants.OP_STATUS_SUCCESS,
355
                            constants.OP_STATUS_SUCCESS],
356
                           ["Hello World", "Foo man bar"])
357

    
358
    self.assertEqual(["Hello World", "Foo man bar"],
359
                     cli.GenericPollJob(job_id, cbs, cbs))
360
    cbs.CheckEmpty()
361

    
362
  def testJobLost(self):
363
    job_id = 13746
364

    
365
    cbs = _MockJobPollCb(self, job_id)
366
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
367
    cbs.AddWfjcResult(None, None, None)
368
    self.assertRaises(errors.JobLost, cli.GenericPollJob, job_id, cbs, cbs)
369
    cbs.CheckEmpty()
370

    
371
  def testError(self):
372
    job_id = 31088
373

    
374
    cbs = _MockJobPollCb(self, job_id)
375
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
376
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
377
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
378
                           [constants.OP_STATUS_SUCCESS,
379
                            constants.OP_STATUS_ERROR],
380
                           ["Hello World", "Error code 123"])
381
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
382
    cbs.CheckEmpty()
383

    
384
  def testError2(self):
385
    job_id = 22235
386

    
387
    cbs = _MockJobPollCb(self, job_id)
388
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
389
    encexc = errors.EncodeException(errors.LockError("problem"))
390
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
391
                           [constants.OP_STATUS_ERROR], [encexc])
392
    self.assertRaises(errors.LockError, cli.GenericPollJob, job_id, cbs, cbs)
393
    cbs.CheckEmpty()
394

    
395
  def testWeirdError(self):
396
    job_id = 28847
397

    
398
    cbs = _MockJobPollCb(self, job_id)
399
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_ERROR, ), None))
400
    cbs.AddQueryJobsResult(constants.JOB_STATUS_ERROR,
401
                           [constants.OP_STATUS_RUNNING,
402
                            constants.OP_STATUS_RUNNING],
403
                           [None, None])
404
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
405
    cbs.CheckEmpty()
406

    
407
  def testCancel(self):
408
    job_id = 4275
409

    
410
    cbs = _MockJobPollCb(self, job_id)
411
    cbs.AddWfjcResult(None, None, constants.JOB_NOTCHANGED)
412
    cbs.AddWfjcResult(None, None, ((constants.JOB_STATUS_CANCELING, ), None))
413
    cbs.AddQueryJobsResult(constants.JOB_STATUS_CANCELING,
414
                           [constants.OP_STATUS_CANCELING,
415
                            constants.OP_STATUS_CANCELING],
416
                           [None, None])
417
    self.assertRaises(errors.OpExecError, cli.GenericPollJob, job_id, cbs, cbs)
418
    cbs.CheckEmpty()
419

    
420

    
421
class TestFormatLogMessage(unittest.TestCase):
422
  def test(self):
423
    self.assertEqual(cli.FormatLogMessage(constants.ELOG_MESSAGE,
424
                                          "Hello World"),
425
                     "Hello World")
426
    self.assertRaises(TypeError, cli.FormatLogMessage,
427
                      constants.ELOG_MESSAGE, [1, 2, 3])
428

    
429
    self.assert_(cli.FormatLogMessage("some other type", (1, 2, 3)))
430

    
431

    
432
class TestParseFields(unittest.TestCase):
433
  def test(self):
434
    self.assertEqual(cli.ParseFields(None, []), [])
435
    self.assertEqual(cli.ParseFields("name,foo,hello", []),
436
                     ["name", "foo", "hello"])
437
    self.assertEqual(cli.ParseFields(None, ["def", "ault", "fields", "here"]),
438
                     ["def", "ault", "fields", "here"])
439
    self.assertEqual(cli.ParseFields("name,foo", ["def", "ault"]),
440
                     ["name", "foo"])
441
    self.assertEqual(cli.ParseFields("+name,foo", ["def", "ault"]),
442
                     ["def", "ault", "name", "foo"])
443

    
444

    
445
if __name__ == '__main__':
446
  testutils.GanetiTestProgram()