From: Michael Hanselmann Date: Thu, 24 Jan 2013 14:08:50 +0000 (+0100) Subject: Establish base for testing Xen hypervisor abstraction X-Git-Tag: v2.8.0beta1~479 X-Git-Url: https://code.grnet.gr/git/ganeti-local/commitdiff_plain/74a50c4689c8f1f160f5f0a6fb6b4275ed922996?ds=sidebyside Establish base for testing Xen hypervisor abstraction There are two separate Xen hypervisors (HVM and PVM), as well as two different Xen commands (xl and xm). This already provides four different combinations and future changes might bring even more. For this reason the test classes for the Xen hypervisor are not defined manually, but rather generated at module load time. Doing so makes it possible to keep using the standard unit test infrastructure provided by the “unittest” module. Using “super”, which we try to avoid in other places, is necessary to call functions provided by other classes. Signed-off-by: Michael Hanselmann Reviewed-by: Helga Velroyen --- diff --git a/test/py/ganeti.hypervisor.hv_xen_unittest.py b/test/py/ganeti.hypervisor.hv_xen_unittest.py index fd05933..d226d10 100755 --- a/test/py/ganeti.hypervisor.hv_xen_unittest.py +++ b/test/py/ganeti.hypervisor.hv_xen_unittest.py @@ -25,6 +25,7 @@ import string # pylint: disable=W0402 import unittest import tempfile import shutil +import random from ganeti import constants from ganeti import objects @@ -38,6 +39,10 @@ from ganeti.hypervisor import hv_xen import testutils +# Map from hypervisor class to hypervisor name +HVCLASS_TO_HVNAME = utils.InvertDict(hypervisor._HYPERVISOR_MAP) + + class TestConsole(unittest.TestCase): def test(self): for cls in [hv_xen.XenPvmHypervisor, hv_xen.XenHvmHypervisor]: @@ -324,5 +329,78 @@ class TestXenHypervisorWriteConfigFile(unittest.TestCase): self.fail("Exception was not raised") +class _TestXenHypervisor(object): + TARGET = NotImplemented + CMD = NotImplemented + HVNAME = NotImplemented + + def setUp(self): + super(_TestXenHypervisor, self).setUp() + + self.tmpdir = tempfile.mkdtemp() + + self.vncpw = "".join(random.sample(string.ascii_letters, 10)) + + self.vncpw_path = utils.PathJoin(self.tmpdir, "vncpw") + utils.WriteFile(self.vncpw_path, data=self.vncpw) + + def tearDown(self): + super(_TestXenHypervisor, self).tearDown() + + shutil.rmtree(self.tmpdir) + + def _GetHv(self, run_cmd=NotImplemented): + return self.TARGET(_cfgdir=self.tmpdir, _run_cmd_fn=run_cmd, _cmd=self.CMD) + + def _SuccessCommand(self, stdout, cmd): + self.assertEqual(cmd[0], self.CMD) + + return utils.RunResult(constants.EXIT_SUCCESS, None, stdout, "", None, + NotImplemented, NotImplemented) + + def _FailingCommand(self, cmd): + self.assertEqual(cmd[0], self.CMD) + + return utils.RunResult(constants.EXIT_FAILURE, None, + "", "This command failed", None, + NotImplemented, NotImplemented) + + +def _MakeTestClass(cls, cmd): + """Makes a class for testing. + + The returned class has structure as shown in the following pseudo code: + + class Test{cls.__name__}{cmd}(_TestXenHypervisor, unittest.TestCase): + TARGET = {cls} + CMD = {cmd} + HVNAME = {Hypervisor name retrieved using class} + + @type cls: class + @param cls: Hypervisor class to be tested + @type cmd: string + @param cmd: Hypervisor command + @rtype: tuple + @return: Class name and class object (not instance) + + """ + name = "Test%sCmd%s" % (cls.__name__, cmd.title()) + bases = (_TestXenHypervisor, unittest.TestCase) + hvname = HVCLASS_TO_HVNAME[cls] + + return (name, type(name, bases, dict(TARGET=cls, CMD=cmd, HVNAME=hvname))) + + +# Create test classes programmatically instead of manually to reduce the risk +# of forgetting some combinations +for cls in [hv_xen.XenPvmHypervisor, hv_xen.XenHvmHypervisor]: + for cmd in constants.KNOWN_XEN_COMMANDS: + (name, testcls) = _MakeTestClass(cls, cmd) + + assert name not in locals() + + locals()[name] = testcls + + if __name__ == "__main__": testutils.GanetiTestProgram()