This patch enables patching the rpc module to create a mocked version which can be used to mock a rpc.DnsOnlyRunner(). This is needed for unit testing LUNodeAdd, as it need to run RPCs against nodes not yet present in the configuration.
Parts of this patch were written by Thomas Thrainer. Signed-off-by: Thomas Thrainer <[email protected]> Signed-off-by: Sebastian Gebhard <[email protected]> --- test/py/cmdlib/testsupport/cmdlib_testcase.py | 28 ++++++++++++++++++++++++++- test/py/cmdlib/testsupport/netutils_mock.py | 2 +- test/py/cmdlib/testsupport/rpc_runner_mock.py | 27 ++++++++++++++++++++++++++ test/py/cmdlib/testsupport/util.py | 4 ++-- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/test/py/cmdlib/testsupport/cmdlib_testcase.py b/test/py/cmdlib/testsupport/cmdlib_testcase.py index 811d455..52fcc06 100644 --- a/test/py/cmdlib/testsupport/cmdlib_testcase.py +++ b/test/py/cmdlib/testsupport/cmdlib_testcase.py @@ -34,11 +34,12 @@ from cmdlib.testsupport.netutils_mock import patchNetutils, \ SetupDefaultNetutilsMock from cmdlib.testsupport.processor_mock import ProcessorMock from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock, \ - RpcResultsBuilder + RpcResultsBuilder, patchRpc, SetupDefaultRpcModuleMock from cmdlib.testsupport.ssh_mock import patchSsh from ganeti.cmdlib.base import LogicalUnit from ganeti import errors +from ganeti import locking from ganeti import objects from ganeti import opcodes from ganeti import runtime @@ -57,6 +58,19 @@ class GanetiContextMock(object): def __init__(self, test_case): self._test_case = test_case + def AddNode(self, node, ec_id): + self._test_case.cfg.AddNode(node, ec_id) + self._test_case.glm.add(locking.LEVEL_NODE, node.uuid) + self._test_case.glm.add(locking.LEVEL_NODE_RES, node.uuid) + + def ReaddNode(self, node): + pass + + def RemoveNode(self, node): + self._test_case.cfg.RemoveNode(node.uuid) + self._test_case.glm.remove(locking.LEVEL_NODE, node.uuid) + self._test_case.glm.remove(locking.LEVEL_NODE_RES, node.uuid) + class MockLU(LogicalUnit): def BuildHooksNodes(self): @@ -109,6 +123,7 @@ class CmdlibTestCase(testutils.GanetiTestCase): self._iallocator_patcher = None self._netutils_patcher = None self._ssh_patcher = None + self._rpc_patcher = None try: runtime.InitArchInfo() @@ -128,6 +143,9 @@ class CmdlibTestCase(testutils.GanetiTestCase): if self._ssh_patcher is not None: self._ssh_patcher.stop() self._ssh_patcher = None + if self._rpc_patcher is not None: + self._rpc_patcher.stop() + self._rpc_patcher = None def tearDown(self): super(CmdlibTestCase, self).tearDown() @@ -178,6 +196,14 @@ class CmdlibTestCase(testutils.GanetiTestCase): # this test module does not use ssh, no patching performed self._ssh_patcher = None + try: + self._rpc_patcher = patchRpc(self._GetTestModule()) + self.rpc_mod = self._rpc_patcher.start() + SetupDefaultRpcModuleMock(self.rpc_mod) + except (ImportError, AttributeError): + # this test module does not use rpc, no patching performed + self._rpc_patcher = None + def GetMockLU(self): """Creates a mock L{LogialUnit} with access to the mocked config etc. diff --git a/test/py/cmdlib/testsupport/netutils_mock.py b/test/py/cmdlib/testsupport/netutils_mock.py index b8ee351..798051a 100644 --- a/test/py/cmdlib/testsupport/netutils_mock.py +++ b/test/py/cmdlib/testsupport/netutils_mock.py @@ -72,7 +72,7 @@ def _GetHostnameMock(cfg, mock_fct, name=None, family=None): if node is not None: return HostnameMock(node.name, node.primary_ip) - return HostnameMock(name, "203.0.113.1") + return HostnameMock(name, "192.0.2.253") # pylint: disable=W0613 diff --git a/test/py/cmdlib/testsupport/rpc_runner_mock.py b/test/py/cmdlib/testsupport/rpc_runner_mock.py index 93845fb..8238566 100644 --- a/test/py/cmdlib/testsupport/rpc_runner_mock.py +++ b/test/py/cmdlib/testsupport/rpc_runner_mock.py @@ -27,6 +27,8 @@ import mock from ganeti import objects from ganeti import rpc +from cmdlib.testsupport.util import patchModule + def CreateRpcRunnerMock(): """Creates a new L{mock.MagicMock} tailored for L{rpc.RpcRunner} @@ -179,3 +181,28 @@ class RpcResultsBuilder(object): @rtype: dict """ return dict((result.node, result) for result in self._results) + + +# pylint: disable=C0103 +def patchRpc(module_under_test): + """Patches the L{ganeti.rpc} module for tests. + + This function is meant to be used as a decorator for test methods. + + @type module_under_test: string + @param module_under_test: the module within cmdlib which is tested. The + "ganeti.cmdlib" prefix is optional. + + """ + return patchModule(module_under_test, "rpc", wraps=rpc) + + +def SetupDefaultRpcModuleMock(rpc_mod): + """Configures the given rpc_mod. + + All relevant functions in rpc_mod are stubbed in a sensible way. + + @param rpc_mod: the mock module to configure + + """ + rpc_mod.DnsOnlyRunner.return_value = CreateRpcRunnerMock() diff --git a/test/py/cmdlib/testsupport/util.py b/test/py/cmdlib/testsupport/util.py index e2354ce..61305c9 100644 --- a/test/py/cmdlib/testsupport/util.py +++ b/test/py/cmdlib/testsupport/util.py @@ -26,7 +26,7 @@ import mock # pylint: disable=C0103 -def patchModule(module_under_test, mock_module): +def patchModule(module_under_test, mock_module, **kwargs): """Computes the module prefix required to mock parts of the Ganeti code. @type module_under_test: string @@ -38,4 +38,4 @@ def patchModule(module_under_test, mock_module): """ if not module_under_test.startswith("ganeti.cmdlib"): module_under_test = "ganeti.cmdlib." + module_under_test - return mock.patch("%s.%s" % (module_under_test, mock_module)) + return mock.patch("%s.%s" % (module_under_test, mock_module), **kwargs) -- 1.8.1.2
