On Mon, Aug 26, 2013 at 8:35 AM, Sebastian Gebhard <[email protected]>wrote:
> 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. > > Signed-off-by: Sebastian Gebhard <[email protected]> > --- > Makefile.am | 1 + > test/py/cmdlib/testsupport/cmdlib_testcase.py | 28 > ++++++++++++++++++++++++++- > test/py/cmdlib/testsupport/rpc_runner_mock.py | 26 > +++++++++++++++++++++++++ > test/py/cmdlib/testsupport/util.py | 4 ++-- > 4 files changed, 56 insertions(+), 3 deletions(-) > > diff --git a/Makefile.am b/Makefile.am > index e99707e..55c833b 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -1280,6 +1280,7 @@ python_tests = \ > test/py/cmdlib/group_unittest.py \ > test/py/cmdlib/instance_unittest.py \ > test/py/cmdlib/instance_storage_unittest.py \ > + test/py/cmdlib/node_unittest.py \ > test/py/cmdlib/test_unittest.py \ > test/py/cfgupgrade_unittest.py \ > test/py/docs_unittest.py \ > diff --git a/test/py/cmdlib/testsupport/cmdlib_testcase.py > b/test/py/cmdlib/testsupport/cmdlib_testcase.py > index 811d455..6901d05 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, patchRpcModule, 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 = patchRpcModule(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/rpc_runner_mock.py > b/test/py/cmdlib/testsupport/rpc_runner_mock.py > index 93845fb..484f178 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,27 @@ class RpcResultsBuilder(object): > @rtype: dict > """ > return dict((result.node, result) for result in self._results) > + > + > +def patchRpcModule(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() > \ No newline at end of file > Newline missing. Did 'make pylint', 'make pylint-qa' and 'make pylint-test' run through? > 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 > > The rest looks good to me, but I can't quite LGTM it, as parts of it are written by me ;-). Cheers, Thomas -- Thomas Thrainer | Software Engineer | [email protected] | Google Germany GmbH Dienerstr. 12 80331 München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores
