4 # Copyright (C) 2010, 2011 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
31 from ganeti import constants
32 from ganeti import errors
33 from ganeti import compat
38 class TestOpcodes(unittest.TestCase):
40 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, None)
41 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, "")
42 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, {})
43 self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, {"OP_ID": ""})
45 for cls in opcodes.OP_MAPPING.values():
46 self.assert_(cls.OP_ID.startswith("OP_"))
47 self.assert_(len(cls.OP_ID) > 3)
48 self.assertEqual(cls.OP_ID, cls.OP_ID.upper())
49 self.assertEqual(cls.OP_ID, opcodes._NameToId(cls.__name__))
50 self.assertFalse(compat.any(cls.OP_ID.startswith(prefix)
51 for prefix in opcodes._SUMMARY_PREFIX.keys()))
52 self.assertTrue(cls.OP_RESULT is None or callable(cls.OP_RESULT))
54 self.assertRaises(TypeError, cls, unsupported_parameter="some value")
60 # Variables supported by all opcodes
61 {"dry_run": False, "debug_level": 0, },
64 dict([(name, False) for name in cls._all_slots()])
70 self.assertEqual(op.OP_ID, cls.OP_ID)
71 self._checkSummary(op)
74 state = op.__getstate__()
75 self.assert_(isinstance(state, dict))
77 restored = opcodes.OpCode.LoadOpCode(state)
78 self.assert_(isinstance(restored, cls))
79 self._checkSummary(restored)
81 for name in ["x_y_z", "hello_world"]:
82 assert name not in cls._all_slots()
83 for value in [None, True, False, [], "Hello World"]:
84 self.assertRaises(AttributeError, setattr, op, name, value)
86 def _checkSummary(self, op):
87 summary = op.Summary()
89 if hasattr(op, "OP_DSC_FIELD"):
90 self.assert_(("OP_%s" % summary).startswith("%s(" % op.OP_ID))
91 self.assert_(summary.endswith(")"))
93 self.assertEqual("OP_%s" % summary, op.OP_ID)
95 def testSummary(self):
96 class OpTest(opcodes.OpCode):
99 ("data", ht.NoDefault, ht.TString, None),
102 self.assertEqual(OpTest(data="").Summary(), "TEST()")
103 self.assertEqual(OpTest(data="Hello World").Summary(),
105 self.assertEqual(OpTest(data="node1.example.com").Summary(),
106 "TEST(node1.example.com)")
108 def testTinySummary(self):
109 self.assertFalse(utils.FindDuplicates(opcodes._SUMMARY_PREFIX.values()))
110 self.assertTrue(compat.all(prefix.endswith("_") and supplement.endswith("_")
111 for (prefix, supplement) in
112 opcodes._SUMMARY_PREFIX.items()))
114 self.assertEqual(opcodes.OpClusterPostInit().TinySummary(), "C_POST_INIT")
115 self.assertEqual(opcodes.OpNodeRemove().TinySummary(), "N_REMOVE")
116 self.assertEqual(opcodes.OpInstanceMigrate().TinySummary(), "I_MIGRATE")
117 self.assertEqual(opcodes.OpGroupQuery().TinySummary(), "G_QUERY")
118 self.assertEqual(opcodes.OpTestJqueue().TinySummary(), "TEST_JQUEUE")
120 def testListSummary(self):
121 class OpTest(opcodes.OpCode):
122 OP_DSC_FIELD = "data"
124 ("data", ht.NoDefault, ht.TList, None),
127 self.assertEqual(OpTest(data=["a", "b", "c"]).Summary(),
129 self.assertEqual(OpTest(data=["a", None, "c"]).Summary(),
131 self.assertEqual(OpTest(data=[1, 2, 3, 4]).Summary(), "TEST(1,2,3,4)")
134 self.assertFalse(utils.FindDuplicates(cls.OP_ID
135 for cls in opcodes._GetOpList()))
136 self.assertEqual(len(opcodes._GetOpList()), len(opcodes.OP_MAPPING))
138 def testParams(self):
139 supported_by_all = set(["debug_level", "dry_run", "priority"])
141 self.assertTrue(opcodes.BaseOpCode not in opcodes.OP_MAPPING.values())
142 self.assertTrue(opcodes.OpCode not in opcodes.OP_MAPPING.values())
144 for cls in opcodes.OP_MAPPING.values() + [opcodes.OpCode]:
145 all_slots = cls._all_slots()
147 self.assertEqual(len(set(all_slots) & supported_by_all), 3,
148 msg=("Opcode %s doesn't support all base"
149 " parameters (%r)" % (cls.OP_ID, supported_by_all)))
151 # All opcodes must have OP_PARAMS
152 self.assert_(hasattr(cls, "OP_PARAMS"),
153 msg="%s doesn't have OP_PARAMS" % cls.OP_ID)
155 param_names = [name for (name, _, _, _) in cls.GetAllParams()]
157 self.assertEqual(all_slots, param_names)
159 # Without inheritance
160 self.assertEqual(cls.__slots__,
161 [name for (name, _, _, _) in cls.OP_PARAMS])
163 # This won't work if parameters are converted to a dictionary
164 duplicates = utils.FindDuplicates(param_names)
165 self.assertFalse(duplicates,
166 msg=("Found duplicate parameters %r in %s" %
167 (duplicates, cls.OP_ID)))
169 # Check parameter definitions
170 for attr_name, aval, test, doc in cls.GetAllParams():
171 self.assert_(attr_name)
172 self.assert_(test is None or test is ht.NoType or callable(test),
173 msg=("Invalid type check for %s.%s" %
174 (cls.OP_ID, attr_name)))
175 self.assertTrue(doc is None or isinstance(doc, basestring))
178 self.assertFalse(callable(aval()),
179 msg="Default value returned by function is callable")
181 # If any parameter has documentation, all others need to have it as well
182 has_doc = [doc is not None for (_, _, _, doc) in cls.OP_PARAMS]
183 self.assertTrue(not compat.any(has_doc) or compat.all(has_doc),
184 msg="%s does not document all parameters" % cls)
186 def testValidateNoModification(self):
187 class OpTest(opcodes.OpCode):
189 ("nodef", ht.NoDefault, ht.TMaybeString, None),
190 ("wdef", "default", ht.TMaybeString, None),
191 ("number", 0, ht.TInt, None),
192 ("notype", None, ht.NoType, None),
195 # Missing required parameter "nodef"
197 before = op.__getstate__()
198 self.assertRaises(errors.OpPrereqError, op.Validate, False)
199 self.assertFalse(hasattr(op, "nodef"))
200 self.assertFalse(hasattr(op, "wdef"))
201 self.assertFalse(hasattr(op, "number"))
202 self.assertFalse(hasattr(op, "notype"))
203 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
205 # Required parameter "nodef" is provided
206 op = OpTest(nodef="foo")
207 before = op.__getstate__()
209 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
210 self.assertEqual(op.nodef, "foo")
211 self.assertFalse(hasattr(op, "wdef"))
212 self.assertFalse(hasattr(op, "number"))
213 self.assertFalse(hasattr(op, "notype"))
215 # Missing required parameter "nodef"
216 op = OpTest(wdef="hello", number=999)
217 before = op.__getstate__()
218 self.assertRaises(errors.OpPrereqError, op.Validate, False)
219 self.assertFalse(hasattr(op, "nodef"))
220 self.assertFalse(hasattr(op, "notype"))
221 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
223 # Wrong type for "nodef"
224 op = OpTest(nodef=987)
225 before = op.__getstate__()
226 self.assertRaises(errors.OpPrereqError, op.Validate, False)
227 self.assertEqual(op.nodef, 987)
228 self.assertFalse(hasattr(op, "notype"))
229 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
231 # Testing different types for "notype"
232 op = OpTest(nodef="foo", notype=[1, 2, 3])
233 before = op.__getstate__()
235 self.assertEqual(op.nodef, "foo")
236 self.assertEqual(op.notype, [1, 2, 3])
237 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
239 op = OpTest(nodef="foo", notype="Hello World")
240 before = op.__getstate__()
242 self.assertEqual(op.nodef, "foo")
243 self.assertEqual(op.notype, "Hello World")
244 self.assertEqual(op.__getstate__(), before, msg="Opcode was modified")
246 def testValidateSetDefaults(self):
247 class OpTest(opcodes.OpCode):
249 # Static default value
250 ("value1", "default", ht.TMaybeString, None),
252 # Default value callback
253 ("value2", lambda: "result", ht.TMaybeString, None),
257 before = op.__getstate__()
259 self.assertNotEqual(op.__getstate__(), before,
260 msg="Opcode was not modified")
261 self.assertEqual(op.value1, "default")
262 self.assertEqual(op.value2, "result")
263 self.assert_(op.dry_run is None)
264 self.assert_(op.debug_level is None)
265 self.assertEqual(op.priority, constants.OP_PRIO_DEFAULT)
267 op = OpTest(value1="hello", value2="world", debug_level=123)
268 before = op.__getstate__()
270 self.assertNotEqual(op.__getstate__(), before,
271 msg="Opcode was not modified")
272 self.assertEqual(op.value1, "hello")
273 self.assertEqual(op.value2, "world")
274 self.assertEqual(op.debug_level, 123)
277 class TestOpcodeDepends(unittest.TestCase):
279 check_relative = opcodes._BuildJobDepCheck(True)
280 check_norelative = opcodes.TNoRelativeJobDependencies
282 for fn in [check_relative, check_norelative]:
283 self.assertTrue(fn(None))
284 self.assertTrue(fn([]))
285 self.assertTrue(fn([(1, [])]))
286 self.assertTrue(fn([(719833, [])]))
287 self.assertTrue(fn([("24879", [])]))
288 self.assertTrue(fn([(2028, [constants.JOB_STATUS_ERROR])]))
290 (2028, [constants.JOB_STATUS_ERROR]),
292 (5063, [constants.JOB_STATUS_SUCCESS, constants.JOB_STATUS_ERROR]),
295 self.assertFalse(fn(1))
296 self.assertFalse(fn([(9, )]))
297 self.assertFalse(fn([(15194, constants.JOB_STATUS_ERROR)]))
301 [(-27740, [constants.JOB_STATUS_CANCELED, constants.JOB_STATUS_ERROR]),
302 (-1, [constants.JOB_STATUS_ERROR]),
305 self.assertTrue(check_relative(i))
306 self.assertFalse(check_norelative(i))
309 class TestResultChecks(unittest.TestCase):
310 def testJobIdList(self):
311 for i in [[], [(False, "error")], [(False, "")],
312 [(True, 123), (True, "999")]]:
313 self.assertTrue(opcodes.TJobIdList(i))
315 for i in ["", [("x", 1)], [[], []], [[False, "", None], [True, 123]]]:
316 self.assertFalse(opcodes.TJobIdList(i))
318 def testJobIdListOnly(self):
319 self.assertTrue(opcodes.TJobIdListOnly({
320 constants.JOB_IDS_KEY: [],
322 self.assertTrue(opcodes.TJobIdListOnly({
323 constants.JOB_IDS_KEY: [(True, "9282")],
326 self.assertFalse(opcodes.TJobIdListOnly({
329 self.assertFalse(opcodes.TJobIdListOnly({
330 constants.JOB_IDS_KEY: [],
333 self.assertFalse(opcodes.TJobIdListOnly({
334 constants.JOB_IDS_KEY: [("foo", "bar")],
336 self.assertFalse(opcodes.TJobIdListOnly({
337 constants.JOB_IDS_KEY: [("one", "two", "three")],
341 if __name__ == "__main__":
342 testutils.GanetiTestProgram()