4 # Copyright (C) 2010, 2011, 2012 Google Inc.
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.
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.
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
22 """Script for testing ganeti.backend"""
28 from ganeti import utils
29 from ganeti import opcodes
30 from ganeti import opcodes_base
32 from ganeti import constants
33 from ganeti import errors
34 from ganeti import compat
39 class TestOpcodes(unittest.TestCase):
41 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, None)
42 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, "")
43 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, {})
44 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, {"OP_ID": ""})
46 for cls in opcodes.OP_MAPPING.values():
47 self.assert_(cls.OP_ID.startswith("OP_"))
48 self.assert_(len(cls.OP_ID) > 3)
49 self.assertEqual(cls.OP_ID, cls.OP_ID.upper())
50 self.assertEqual(cls.OP_ID, opcodes_base._NameToId(cls.__name__))
52 compat.any(cls.OP_ID.startswith(prefix)
53 for prefix in opcodes_base.SUMMARY_PREFIX.keys()))
54 self.assertTrue(callable(cls.OP_RESULT),
55 msg=("%s should have a result check" % cls.OP_ID))
57 self.assertRaises(TypeError, cls, unsupported_parameter="some value")
63 # Variables supported by all opcodes
64 {"dry_run": False, "debug_level": 0, },
67 dict([(name, []) for name in cls.GetAllSlots()])
73 self.assertEqual(op.OP_ID, cls.OP_ID)
74 self._checkSummary(op)
77 state = op.__getstate__()
78 self.assert_(isinstance(state, dict))
80 restored = opcodes.OpCode.LoadOpCode(state)
81 self.assert_(isinstance(restored, cls))
82 self._checkSummary(restored)
84 for name in ["x_y_z", "hello_world"]:
85 assert name not in cls.GetAllSlots()
86 for value in [None, True, False, [], "Hello World"]:
87 self.assertRaises(AttributeError, setattr, op, name, value)
89 def _checkSummary(self, op):
90 summary = op.Summary()
92 if hasattr(op, "OP_DSC_FIELD"):
93 self.assert_(("OP_%s" % summary).startswith("%s(" % op.OP_ID))
94 self.assert_(summary.endswith(")"))
96 self.assertEqual("OP_%s" % summary, op.OP_ID)
98 def testSummary(self):
99 class OpTest(opcodes.OpCode):
100 OP_DSC_FIELD = "data"
102 ("data", ht.NoDefault, ht.TString, None),
105 self.assertEqual(OpTest(data="").Summary(), "TEST()")
106 self.assertEqual(OpTest(data="Hello World").Summary(),
108 self.assertEqual(OpTest(data="node1.example.com").Summary(),
109 "TEST(node1.example.com)")
111 def testSummaryFormatter(self):
112 class OpTest(opcodes.OpCode):
113 OP_DSC_FIELD = "data"
114 OP_DSC_FORMATTER = lambda _, v: "a"
116 ("data", ht.NoDefault, ht.TString, None),
118 self.assertEqual(OpTest(data="").Summary(), "TEST(a)")
119 self.assertEqual(OpTest(data="b").Summary(), "TEST(a)")
121 def testTinySummary(self):
123 utils.FindDuplicates(opcodes_base.SUMMARY_PREFIX.values()))
124 self.assertTrue(compat.all(prefix.endswith("_") and supplement.endswith("_")
125 for (prefix, supplement) in
126 opcodes_base.SUMMARY_PREFIX.items()))
128 self.assertEqual(opcodes.OpClusterPostInit().TinySummary(), "C_POST_INIT")
129 self.assertEqual(opcodes.OpNodeRemove().TinySummary(), "N_REMOVE")
130 self.assertEqual(opcodes.OpInstanceMigrate().TinySummary(), "I_MIGRATE")
131 self.assertEqual(opcodes.OpGroupQuery().TinySummary(), "G_QUERY")
132 self.assertEqual(opcodes.OpTestJqueue().TinySummary(), "TEST_JQUEUE")
134 def testListSummary(self):
135 class OpTest(opcodes.OpCode):
136 OP_DSC_FIELD = "data"
138 ("data", ht.NoDefault, ht.TList, None),
141 self.assertEqual(OpTest(data=["a", "b", "c"]).Summary(),
143 self.assertEqual(OpTest(data=["a", None, "c"]).Summary(),
145 self.assertEqual(OpTest(data=[1, 2, 3, 4]).Summary(), "TEST(1,2,3,4)")
148 self.assertFalse(utils.FindDuplicates(cls.OP_ID
149 for cls in opcodes._GetOpList()))
150 self.assertEqual(len(opcodes._GetOpList()), len(opcodes.OP_MAPPING))
152 def testParams(self):
153 supported_by_all = set(["debug_level", "dry_run", "priority"])
155 self.assertTrue(opcodes_base.BaseOpCode not in opcodes.OP_MAPPING.values())
156 self.assertTrue(opcodes.OpCode not in opcodes.OP_MAPPING.values())
158 for cls in opcodes.OP_MAPPING.values() + [opcodes.OpCode]:
159 all_slots = cls.GetAllSlots()
161 self.assertEqual(len(set(all_slots) & supported_by_all), 3,
162 msg=("Opcode %s doesn't support all base"
163 " parameters (%r)" % (cls.OP_ID, supported_by_all)))
165 # All opcodes must have OP_PARAMS
166 self.assert_(hasattr(cls, "OP_PARAMS"),
167 msg="%s doesn't have OP_PARAMS" % cls.OP_ID)
169 param_names = [name for (name, _, _, _) in cls.GetAllParams()]
171 self.assertEqual(all_slots, param_names)
173 # Without inheritance
174 self.assertEqual(cls.__slots__,
175 [name for (name, _, _, _) in cls.OP_PARAMS])
177 # This won't work if parameters are converted to a dictionary
178 duplicates = utils.FindDuplicates(param_names)
179 self.assertFalse(duplicates,
180 msg=("Found duplicate parameters %r in %s" %
181 (duplicates, cls.OP_ID)))
183 # Check parameter definitions
184 for attr_name, aval, test, doc in cls.GetAllParams():
185 self.assert_(attr_name)
186 self.assertTrue(callable(test),
187 msg=("Invalid type check for %s.%s" %
188 (cls.OP_ID, attr_name)))
189 self.assertTrue(doc is None or isinstance(doc, basestring))
192 default_value = aval()
193 self.assertFalse(callable(default_value),
194 msg=("Default value of %s.%s returned by function"
195 " is callable" % (cls.OP_ID, attr_name)))
199 if aval is not ht.NoDefault and aval is not None:
200 self.assertTrue(test(default_value),
201 msg=("Default value of %s.%s does not verify" %
202 (cls.OP_ID, attr_name)))
204 # If any parameter has documentation, all others need to have it as well
205 has_doc = [doc is not None for (_, _, _, doc) in cls.OP_PARAMS]
206 self.assertTrue(not compat.any(has_doc) or compat.all(has_doc),
207 msg="%s does not document all parameters" % cls)
209 def testValidateNoModification(self):
210 class OpTest(opcodes.OpCode):
212 ("nodef", None, ht.TString, None),
213 ("wdef", "default", ht.TMaybeString, None),
214 ("number", 0, ht.TInt, None),
215 ("notype", None, ht.TAny, None),
218 # Missing required parameter "nodef"
220 before = op.__getstate__()
221 self.assertRaises(errors.OpPrereqError, op.Validate, False)
222 self.assertFalse(hasattr(op, "nodef"))
223 self.assertFalse(hasattr(op, "wdef"))
224 self.assertFalse(hasattr(op, "number"))
225 self.assertFalse(hasattr(op, "notype"))
226 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
228 # Required parameter "nodef" is provided
229 op = OpTest(nodef="foo")
230 before = op.__getstate__()
232 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
233 self.assertEqual(op.nodef, "foo")
234 self.assertFalse(hasattr(op, "wdef"))
235 self.assertFalse(hasattr(op, "number"))
236 self.assertFalse(hasattr(op, "notype"))
238 # Missing required parameter "nodef"
239 op = OpTest(wdef="hello", number=999)
240 before = op.__getstate__()
241 self.assertRaises(errors.OpPrereqError, op.Validate, False)
242 self.assertFalse(hasattr(op, "nodef"))
243 self.assertFalse(hasattr(op, "notype"))
244 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
246 # Wrong type for "nodef"
247 op = OpTest(nodef=987)
248 before = op.__getstate__()
249 self.assertRaises(errors.OpPrereqError, op.Validate, False)
250 self.assertEqual(op.nodef, 987)
251 self.assertFalse(hasattr(op, "notype"))
252 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
254 # Testing different types for "notype"
255 op = OpTest(nodef="foo", notype=[1, 2, 3])
256 before = op.__getstate__()
258 self.assertEqual(op.nodef, "foo")
259 self.assertEqual(op.notype, [1, 2, 3])
260 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
262 op = OpTest(nodef="foo", notype="Hello World")
263 before = op.__getstate__()
265 self.assertEqual(op.nodef, "foo")
266 self.assertEqual(op.notype, "Hello World")
267 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
269 def testValidateSetDefaults(self):
270 class OpTest(opcodes.OpCode):
272 ("value1", "default", ht.TMaybeString, None),
273 ("value2", "result", ht.TMaybeString, None),
277 before = op.__getstate__()
279 self.assertNotEqual(op.__getstate__(), before,
280 msg="Opcode was not modified")
281 self.assertEqual(op.value1, "default")
282 self.assertEqual(op.value2, "result")
283 self.assert_(op.dry_run is None)
284 self.assert_(op.debug_level is None)
285 self.assertEqual(op.priority, constants.OP_PRIO_DEFAULT)
287 op = OpTest(value1="hello", value2="world", debug_level=123)
288 before = op.__getstate__()
290 self.assertNotEqual(op.__getstate__(), before,
291 msg="Opcode was not modified")
292 self.assertEqual(op.value1, "hello")
293 self.assertEqual(op.value2, "world")
294 self.assertEqual(op.debug_level, 123)
296 def testOpInstanceMultiAlloc(self):
297 inst = dict([(name, []) for name in opcodes.OpInstanceCreate.GetAllSlots()])
298 inst_op = opcodes.OpInstanceCreate(**inst)
299 inst_state = inst_op.__getstate__()
301 multialloc = opcodes.OpInstanceMultiAlloc(instances=[inst_op])
302 state = multialloc.__getstate__()
303 self.assertEquals(state["instances"], [inst_state])
304 loaded_multialloc = opcodes.OpCode.LoadOpCode(state)
305 (loaded_inst,) = loaded_multialloc.instances
306 self.assertNotEquals(loaded_inst, inst_op)
307 self.assertEquals(loaded_inst.__getstate__(), inst_state)
310 class TestOpcodeDepends(unittest.TestCase):
312 check_relative = opcodes_base.BuildJobDepCheck(True)
313 check_norelative = opcodes_base.TNoRelativeJobDependencies
315 for fn in [check_relative, check_norelative]:
316 self.assertTrue(fn(None))
317 self.assertTrue(fn([]))
318 self.assertTrue(fn([(1, [])]))
319 self.assertTrue(fn([(719833, [])]))
320 self.assertTrue(fn([("24879", [])]))
321 self.assertTrue(fn([(2028, [constants.JOB_STATUS_ERROR])]))
323 (2028, [constants.JOB_STATUS_ERROR]),
325 (5063, [constants.JOB_STATUS_SUCCESS, constants.JOB_STATUS_ERROR]),
328 self.assertFalse(fn(1))
329 self.assertFalse(fn([(9, )]))
330 self.assertFalse(fn([(15194, constants.JOB_STATUS_ERROR)]))
334 [(-27740, [constants.JOB_STATUS_CANCELED, constants.JOB_STATUS_ERROR]),
335 (-1, [constants.JOB_STATUS_ERROR]),
338 self.assertTrue(check_relative(i))
339 self.assertFalse(check_norelative(i))
342 class TestResultChecks(unittest.TestCase):
343 def testJobIdList(self):
344 for i in [[], [(False, "error")], [(False, "")],
345 [(True, 123), (True, "999")]]:
346 self.assertTrue(ht.TJobIdList(i))
348 for i in ["", [("x", 1)], [[], []], [[False, "", None], [True, 123]]]:
349 self.assertFalse(ht.TJobIdList(i))
351 def testJobIdListOnly(self):
352 self.assertTrue(ht.TJobIdListOnly({
353 constants.JOB_IDS_KEY: [],
355 self.assertTrue(ht.TJobIdListOnly({
356 constants.JOB_IDS_KEY: [(True, "9282")],
359 self.assertFalse(ht.TJobIdListOnly({
362 self.assertFalse(ht.TJobIdListOnly({
363 constants.JOB_IDS_KEY: [],
366 self.assertFalse(ht.TJobIdListOnly({
367 constants.JOB_IDS_KEY: [("foo", "bar")],
369 self.assertFalse(ht.TJobIdListOnly({
370 constants.JOB_IDS_KEY: [("one", "two", "three")],
374 class TestOpInstanceSetParams(unittest.TestCase):
375 def _GenericTests(self, fn):
376 self.assertTrue(fn([]))
377 self.assertTrue(fn([(constants.DDM_ADD, {})]))
378 self.assertTrue(fn([(constants.DDM_REMOVE, {})]))
379 for i in [0, 1, 2, 3, 9, 10, 1024]:
380 self.assertTrue(fn([(i, {})]))
382 self.assertFalse(fn(None))
383 self.assertFalse(fn({}))
384 self.assertFalse(fn(""))
385 self.assertFalse(fn(0))
386 self.assertFalse(fn([(-100, {})]))
387 self.assertFalse(fn([(constants.DDM_ADD, 2, 3)]))
388 self.assertFalse(fn([[constants.DDM_ADD]]))
390 def testNicModifications(self):
391 fn = ht.TSetParamsMods(ht.TINicParams)
392 self._GenericTests(fn)
394 for param in constants.INIC_PARAMS:
395 self.assertTrue(fn([[constants.DDM_ADD, {param: None}]]))
396 self.assertTrue(fn([[constants.DDM_ADD, {param: param}]]))
398 def testDiskModifications(self):
399 fn = ht.TSetParamsMods(ht.TIDiskParams)
400 self._GenericTests(fn)
402 for param in constants.IDISK_PARAMS:
403 self.assertTrue(fn([[constants.DDM_ADD, {param: 0}]]))
404 self.assertTrue(fn([[constants.DDM_ADD, {param: param}]]))
407 if __name__ == "__main__":
408 testutils.GanetiTestProgram()