X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ff0d18e6077bd235ef20d9f4599479a071dedd77..48aaca91efa214b37dba94f28582be73f3c90dbd:/test/ganeti.opcodes_unittest.py diff --git a/test/ganeti.opcodes_unittest.py b/test/ganeti.opcodes_unittest.py index 6c2fdb0..a5e36d2 100755 --- a/test/ganeti.opcodes_unittest.py +++ b/test/ganeti.opcodes_unittest.py @@ -30,10 +30,21 @@ from ganeti import opcodes from ganeti import ht from ganeti import constants from ganeti import errors +from ganeti import compat import testutils +#: Unless an opcode is included in the following list it must have a result +#: check of some sort +MISSING_RESULT_CHECK = frozenset([ + opcodes.OpTestAllocator, + opcodes.OpTestDelay, + opcodes.OpTestDummy, + opcodes.OpTestJqueue, + ]) + + class TestOpcodes(unittest.TestCase): def test(self): self.assertRaises(ValueError, opcodes.OpCode.LoadOpCode, None) @@ -46,6 +57,15 @@ class TestOpcodes(unittest.TestCase): self.assert_(len(cls.OP_ID) > 3) self.assertEqual(cls.OP_ID, cls.OP_ID.upper()) self.assertEqual(cls.OP_ID, opcodes._NameToId(cls.__name__)) + self.assertFalse(compat.any(cls.OP_ID.startswith(prefix) + for prefix in opcodes._SUMMARY_PREFIX.keys())) + if cls in MISSING_RESULT_CHECK: + self.assertTrue(cls.OP_RESULT is None, + msg=("%s is listed to not have a result check" % + cls.OP_ID)) + else: + self.assertTrue(callable(cls.OP_RESULT), + msg=("%s should have a result check" % cls.OP_ID)) self.assertRaises(TypeError, cls, unsupported_parameter="some value") @@ -57,7 +77,7 @@ class TestOpcodes(unittest.TestCase): {"dry_run": False, "debug_level": 0, }, # All variables - dict([(name, False) for name in cls._all_slots()]) + dict([(name, []) for name in cls.GetAllSlots()]) ] for i in args: @@ -75,7 +95,7 @@ class TestOpcodes(unittest.TestCase): self._checkSummary(restored) for name in ["x_y_z", "hello_world"]: - assert name not in cls._all_slots() + assert name not in cls.GetAllSlots() for value in [None, True, False, [], "Hello World"]: self.assertRaises(AttributeError, setattr, op, name, value) @@ -92,7 +112,7 @@ class TestOpcodes(unittest.TestCase): class OpTest(opcodes.OpCode): OP_DSC_FIELD = "data" OP_PARAMS = [ - ("data", ht.NoDefault, ht.TString), + ("data", ht.NoDefault, ht.TString, None), ] self.assertEqual(OpTest(data="").Summary(), "TEST()") @@ -101,11 +121,23 @@ class TestOpcodes(unittest.TestCase): self.assertEqual(OpTest(data="node1.example.com").Summary(), "TEST(node1.example.com)") + def testTinySummary(self): + self.assertFalse(utils.FindDuplicates(opcodes._SUMMARY_PREFIX.values())) + self.assertTrue(compat.all(prefix.endswith("_") and supplement.endswith("_") + for (prefix, supplement) in + opcodes._SUMMARY_PREFIX.items())) + + self.assertEqual(opcodes.OpClusterPostInit().TinySummary(), "C_POST_INIT") + self.assertEqual(opcodes.OpNodeRemove().TinySummary(), "N_REMOVE") + self.assertEqual(opcodes.OpInstanceMigrate().TinySummary(), "I_MIGRATE") + self.assertEqual(opcodes.OpGroupQuery().TinySummary(), "G_QUERY") + self.assertEqual(opcodes.OpTestJqueue().TinySummary(), "TEST_JQUEUE") + def testListSummary(self): class OpTest(opcodes.OpCode): OP_DSC_FIELD = "data" OP_PARAMS = [ - ("data", ht.NoDefault, ht.TList), + ("data", ht.NoDefault, ht.TList, None), ] self.assertEqual(OpTest(data=["a", "b", "c"]).Summary(), @@ -126,7 +158,7 @@ class TestOpcodes(unittest.TestCase): self.assertTrue(opcodes.OpCode not in opcodes.OP_MAPPING.values()) for cls in opcodes.OP_MAPPING.values() + [opcodes.OpCode]: - all_slots = cls._all_slots() + all_slots = cls.GetAllSlots() self.assertEqual(len(set(all_slots) & supported_by_all), 3, msg=("Opcode %s doesn't support all base" @@ -136,12 +168,13 @@ class TestOpcodes(unittest.TestCase): self.assert_(hasattr(cls, "OP_PARAMS"), msg="%s doesn't have OP_PARAMS" % cls.OP_ID) - param_names = [name for (name, _, _) in cls.GetAllParams()] + param_names = [name for (name, _, _, _) in cls.GetAllParams()] self.assertEqual(all_slots, param_names) # Without inheritance - self.assertEqual(cls.__slots__, [name for (name, _, _) in cls.OP_PARAMS]) + self.assertEqual(cls.__slots__, + [name for (name, _, _, _) in cls.OP_PARAMS]) # This won't work if parameters are converted to a dictionary duplicates = utils.FindDuplicates(param_names) @@ -150,23 +183,37 @@ class TestOpcodes(unittest.TestCase): (duplicates, cls.OP_ID))) # Check parameter definitions - for attr_name, aval, test in cls.GetAllParams(): + for attr_name, aval, test, doc in cls.GetAllParams(): self.assert_(attr_name) self.assert_(test is None or test is ht.NoType or callable(test), msg=("Invalid type check for %s.%s" % (cls.OP_ID, attr_name))) + self.assertTrue(doc is None or isinstance(doc, basestring)) if callable(aval): - self.assertFalse(callable(aval()), + default_value = aval() + self.assertFalse(callable(default_value), msg="Default value returned by function is callable") + else: + default_value = aval + + if aval is not ht.NoDefault and test is not ht.NoType: + self.assertTrue(test(default_value), + msg=("Default value of '%s.%s' does not verify" % + (cls.OP_ID, attr_name))) + + # If any parameter has documentation, all others need to have it as well + has_doc = [doc is not None for (_, _, _, doc) in cls.OP_PARAMS] + self.assertTrue(not compat.any(has_doc) or compat.all(has_doc), + msg="%s does not document all parameters" % cls) def testValidateNoModification(self): class OpTest(opcodes.OpCode): OP_PARAMS = [ - ("nodef", ht.NoDefault, ht.TMaybeString), - ("wdef", "default", ht.TMaybeString), - ("number", 0, ht.TInt), - ("notype", None, ht.NoType), + ("nodef", ht.NoDefault, ht.TMaybeString, None), + ("wdef", "default", ht.TMaybeString, None), + ("number", 0, ht.TInt, None), + ("notype", None, ht.NoType, None), ] # Missing required parameter "nodef" @@ -224,10 +271,10 @@ class TestOpcodes(unittest.TestCase): class OpTest(opcodes.OpCode): OP_PARAMS = [ # Static default value - ("value1", "default", ht.TMaybeString), + ("value1", "default", ht.TMaybeString, None), # Default value callback - ("value2", lambda: "result", ht.TMaybeString), + ("value2", lambda: "result", ht.TMaybeString, None), ] op = OpTest() @@ -251,5 +298,142 @@ class TestOpcodes(unittest.TestCase): self.assertEqual(op.debug_level, 123) + def testOpInstanceMultiAlloc(self): + inst = dict([(name, []) for name in opcodes.OpInstanceCreate.GetAllSlots()]) + inst_op = opcodes.OpInstanceCreate(**inst) + inst_state = inst_op.__getstate__() + + multialloc = opcodes.OpInstanceMultiAlloc(instances=[inst_op]) + state = multialloc.__getstate__() + self.assertEquals(state["instances"], [inst_state]) + loaded_multialloc = opcodes.OpCode.LoadOpCode(state) + (loaded_inst,) = loaded_multialloc.instances + self.assertNotEquals(loaded_inst, inst_op) + self.assertEquals(loaded_inst.__getstate__(), inst_state) + + +class TestOpcodeDepends(unittest.TestCase): + def test(self): + check_relative = opcodes._BuildJobDepCheck(True) + check_norelative = opcodes.TNoRelativeJobDependencies + + for fn in [check_relative, check_norelative]: + self.assertTrue(fn(None)) + self.assertTrue(fn([])) + self.assertTrue(fn([(1, [])])) + self.assertTrue(fn([(719833, [])])) + self.assertTrue(fn([("24879", [])])) + self.assertTrue(fn([(2028, [constants.JOB_STATUS_ERROR])])) + self.assertTrue(fn([ + (2028, [constants.JOB_STATUS_ERROR]), + (18750, []), + (5063, [constants.JOB_STATUS_SUCCESS, constants.JOB_STATUS_ERROR]), + ])) + + self.assertFalse(fn(1)) + self.assertFalse(fn([(9, )])) + self.assertFalse(fn([(15194, constants.JOB_STATUS_ERROR)])) + + for i in [ + [(-1, [])], + [(-27740, [constants.JOB_STATUS_CANCELED, constants.JOB_STATUS_ERROR]), + (-1, [constants.JOB_STATUS_ERROR]), + (9921, [])], + ]: + self.assertTrue(check_relative(i)) + self.assertFalse(check_norelative(i)) + + +class TestResultChecks(unittest.TestCase): + def testJobIdList(self): + for i in [[], [(False, "error")], [(False, "")], + [(True, 123), (True, "999")]]: + self.assertTrue(opcodes.TJobIdList(i)) + + for i in ["", [("x", 1)], [[], []], [[False, "", None], [True, 123]]]: + self.assertFalse(opcodes.TJobIdList(i)) + + def testJobIdListOnly(self): + self.assertTrue(opcodes.TJobIdListOnly({ + constants.JOB_IDS_KEY: [], + })) + self.assertTrue(opcodes.TJobIdListOnly({ + constants.JOB_IDS_KEY: [(True, "9282")], + })) + + self.assertFalse(opcodes.TJobIdListOnly({ + "x": None, + })) + self.assertFalse(opcodes.TJobIdListOnly({ + constants.JOB_IDS_KEY: [], + "x": None, + })) + self.assertFalse(opcodes.TJobIdListOnly({ + constants.JOB_IDS_KEY: [("foo", "bar")], + })) + self.assertFalse(opcodes.TJobIdListOnly({ + constants.JOB_IDS_KEY: [("one", "two", "three")], + })) + + +class TestClusterOsList(unittest.TestCase): + def test(self): + good = [ + None, + [], + [(constants.DDM_ADD, "dos"), + (constants.DDM_REMOVE, "linux")], + ] + + for i in good: + self.assertTrue(opcodes._TestClusterOsList(i)) + + wrong = ["", 0, "xy", ["Hello World"], object(), + [("foo", "bar")], + [("", "")], + [[constants.DDM_ADD]], + [(constants.DDM_ADD, "")], + [(constants.DDM_REMOVE, "")], + [(constants.DDM_ADD, None)], + [(constants.DDM_REMOVE, None)], + ] + + for i in wrong: + self.assertFalse(opcodes._TestClusterOsList(i)) + + +class TestOpInstanceSetParams(unittest.TestCase): + def _GenericTests(self, fn): + self.assertTrue(fn([])) + self.assertTrue(fn([(constants.DDM_ADD, {})])) + self.assertTrue(fn([(constants.DDM_REMOVE, {})])) + for i in [0, 1, 2, 3, 9, 10, 1024]: + self.assertTrue(fn([(i, {})])) + + self.assertFalse(fn(None)) + self.assertFalse(fn({})) + self.assertFalse(fn("")) + self.assertFalse(fn(0)) + self.assertFalse(fn([(-100, {})])) + self.assertFalse(fn([(constants.DDM_ADD, 2, 3)])) + self.assertFalse(fn([[constants.DDM_ADD]])) + + def testNicModifications(self): + fn = opcodes.OpInstanceSetParams.TestNicModifications + self._GenericTests(fn) + + for param in constants.INIC_PARAMS: + self.assertTrue(fn([[constants.DDM_ADD, {param: None}]])) + self.assertTrue(fn([[constants.DDM_ADD, {param: param}]])) + + def testDiskModifications(self): + fn = opcodes.OpInstanceSetParams.TestDiskModifications + self._GenericTests(fn) + + for param in constants.IDISK_PARAMS: + self.assertTrue(fn([[constants.DDM_ADD, {param: 0}]])) + self.assertTrue(fn([[constants.DDM_ADD, {param: param}]])) + + if __name__ == "__main__": testutils.GanetiTestProgram()