Commit 08cef8fc authored by Thomas Thrainer's avatar Thomas Thrainer
Browse files

Add unit test for LUClusterRename



Also mock the netutils and ssh module in order to test all code paths.
Signed-off-by: default avatarThomas Thrainer <thomasth@google.com>
Reviewed-by: default avatarMichele Tartara <mtartara@google.com>
parent 6bb43023
......@@ -1335,8 +1335,11 @@ python_test_support = \
test/py/cmdlib/testsupport/config_mock.py \
test/py/cmdlib/testsupport/iallocator_mock.py \
test/py/cmdlib/testsupport/lock_manager_mock.py \
test/py/cmdlib/testsupport/netutils_mock.py \
test/py/cmdlib/testsupport/processor_mock.py \
test/py/cmdlib/testsupport/rpc_runner_mock.py
test/py/cmdlib/testsupport/rpc_runner_mock.py \
test/py/cmdlib/testsupport/ssh_mock.py \
test/py/cmdlib/testsupport/util.py
haskell_tests = test/hs/htest
......
......@@ -402,5 +402,51 @@ class TestLUClusterRedistConf(CmdlibTestCase):
self.ExecOpCode(op)
class TestLUClusterRename(CmdlibTestCase):
NEW_NAME = "new-name.example.com"
NEW_IP = "1.2.3.4"
def testNoChanges(self):
op = opcodes.OpClusterRename(name=self.cfg.GetClusterName())
self.ExecOpCodeExpectOpPrereqError(op, "name nor the IP address")
def testReachableIp(self):
op = opcodes.OpClusterRename(name=self.NEW_NAME)
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.NEW_NAME, self.NEW_IP)
self.netutils_mod.TcpPing.return_value = True
self.ExecOpCodeExpectOpPrereqError(op, "is reachable on the network")
def testValidRename(self):
op = opcodes.OpClusterRename(name=self.NEW_NAME)
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.NEW_NAME, self.NEW_IP)
self.ExecOpCode(op)
self.assertEqual(1, self.ssh_mod.WriteKnownHostsFile.call_count)
self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
self.cfg.GetMasterNode(),
self.cfg.GetMasterNetworkParameters(),
False)
self.rpc.call_node_activate_master_ip.assert_called_once_with(
self.cfg.GetMasterNode(),
self.cfg.GetMasterNetworkParameters(),
False)
def testRenameOfflineMaster(self):
op = opcodes.OpClusterRename(name=self.NEW_NAME)
self.cfg.GetMasterNodeInfo().offline = True
self.netutils_mod.GetHostname.return_value = \
HostnameMock(self.NEW_NAME, self.NEW_IP)
self.ExecOpCode(op)
if __name__ == "__main__":
testutils.GanetiTestProgram()
......@@ -27,14 +27,19 @@ from cmdlib.testsupport.cmdlib_testcase import CmdlibTestCase
from cmdlib.testsupport.config_mock import ConfigMock
from cmdlib.testsupport.iallocator_mock import patchIAllocator
from cmdlib.testsupport.lock_manager_mock import LockManagerMock
from cmdlib.testsupport.netutils_mock import patchNetutils, HostnameMock
from cmdlib.testsupport.processor_mock import ProcessorMock
from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock, \
RpcResultsBuilder
from cmdlib.testsupport.ssh_mock import patchSsh
__all__ = ["CmdlibTestCase",
"ConfigMock",
"patchIAllocator",
"CreateRpcRunnerMock",
"HostnameMock",
"patchIAllocator",
"patchNetutils",
"patchSsh",
"LockManagerMock",
"ProcessorMock",
"RpcResultsBuilder",
......
......@@ -29,8 +29,11 @@ import traceback
from cmdlib.testsupport.config_mock import ConfigMock
from cmdlib.testsupport.iallocator_mock import patchIAllocator
from cmdlib.testsupport.lock_manager_mock import LockManagerMock
from cmdlib.testsupport.netutils_mock import patchNetutils, \
SetupDefaultNetutilsMock
from cmdlib.testsupport.processor_mock import ProcessorMock
from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock
from cmdlib.testsupport.ssh_mock import patchSsh
from ganeti import errors
from ganeti import opcodes
......@@ -60,6 +63,8 @@ class CmdlibTestCase(testutils.GanetiTestCase):
* C{rpc}: @see L{CreateRpcRunnerMock}
* C{iallocator_cls}: @see L{patchIAllocator}
* C{mcpu}: @see L{ProcessorMock}
* C{netutils_mod}: @see L{patchNetutils}
* C{ssh_mod}: @see L{patchSsh}
"""
......@@ -68,6 +73,8 @@ class CmdlibTestCase(testutils.GanetiTestCase):
def setUp(self):
super(CmdlibTestCase, self).setUp()
self._iallocator_patcher = None
self._netutils_patcher = None
self._ssh_patcher = None
try:
runtime.InitArchInfo()
......@@ -81,6 +88,12 @@ class CmdlibTestCase(testutils.GanetiTestCase):
if self._iallocator_patcher is not None:
self._iallocator_patcher.stop()
self._iallocator_patcher = None
if self._netutils_patcher is not None:
self._netutils_patcher.stop()
self._netutils_patcher = None
if self._ssh_patcher is not None:
self._ssh_patcher.stop()
self._ssh_patcher = None
def tearDown(self):
super(CmdlibTestCase, self).tearDown()
......@@ -105,17 +118,31 @@ class CmdlibTestCase(testutils.GanetiTestCase):
self.cfg = ConfigMock()
self.glm = LockManagerMock()
self.rpc = CreateRpcRunnerMock()
ctx = GanetiContextMock(self.cfg, self.glm, self.rpc)
self.mcpu = ProcessorMock(ctx)
self._StopPatchers()
try:
self._iallocator_patcher = patchIAllocator(self._GetTestModule())
self.iallocator_cls = self._iallocator_patcher.start()
except ImportError:
except (ImportError, AttributeError):
# this test module does not use iallocator, no patching performed
self._iallocator_patcher = None
ctx = GanetiContextMock(self.cfg, self.glm, self.rpc)
self.mcpu = ProcessorMock(ctx)
try:
self._netutils_patcher = patchNetutils(self._GetTestModule())
self.netutils_mod = self._netutils_patcher.start()
SetupDefaultNetutilsMock(self.netutils_mod, self.cfg)
except (ImportError, AttributeError):
# this test module does not use netutils, no patching performed
self._netutils_patcher = None
try:
self._ssh_patcher = patchSsh(self._GetTestModule())
self.ssh_mod = self._ssh_patcher.start()
except (ImportError, AttributeError):
# this test module does not use ssh, no patching performed
self._ssh_patcher = None
def ExecOpCode(self, opcode):
"""Executes the given opcode.
......
......@@ -22,7 +22,7 @@
"""Support for mocking the IAllocator interface"""
import mock
from cmdlib.testsupport.util import patchModule
# pylint: disable=C0103
......@@ -36,6 +36,4 @@ def patchIAllocator(module_under_test):
"ganeti.cmdlib" prefix is optional.
"""
if not module_under_test.startswith("ganeti.cmdlib"):
module_under_test = "ganeti.cmdlib." + module_under_test
return mock.patch("%s.iallocator.IAllocator" % module_under_test)
return patchModule(module_under_test, "iallocator.IAllocator")
#
#
# Copyright (C) 2013 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Support for mocking the netutils module"""
import mock
from ganeti import compat
from ganeti import errors
from ganeti import netutils
from cmdlib.testsupport.util import patchModule
# pylint: disable=C0103
def patchNetutils(module_under_test):
"""Patches the L{ganeti.netutils} 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, "netutils")
class HostnameMock(object):
"""Simple mocked version of L{netutils.Hostname}.
"""
def __init__(self, name, ip):
self.name = name
self.ip = ip
def _IsOverwrittenReturnValue(value):
return value is not None and value != mock.DEFAULT and \
not isinstance(value, mock.Mock)
# pylint: disable=W0613
def _GetHostnameMock(cfg, mock_fct, name=None, family=None):
if _IsOverwrittenReturnValue(mock_fct.return_value):
return mock.DEFAULT
if name is None:
name = cfg.GetMasterNodeName()
if name == cfg.GetClusterName():
cluster = cfg.GetClusterInfo()
return HostnameMock(cluster.cluster_name, cluster.master_ip)
node = cfg.GetNodeInfoByName(name)
if node is None:
raise errors.OpPrereqError(
"Mock error: The given name '%s' is not in the config" % name,
errors.ECODE_RESOLVER)
return HostnameMock(node.name, node.primary_ip)
# pylint: disable=W0613
def _TcpPingMock(cfg, mock_fct, target, port, timeout=None,
live_port_needed=None, source=None):
if _IsOverwrittenReturnValue(mock_fct.return_value):
return mock.DEFAULT
if target == cfg.GetClusterName():
return True
if cfg.GetNodeInfoByName(target) is not None:
return True
if target in [node.primary_ip for node in cfg.GetAllNodesInfo().values()]:
return True
if target in [node.secondary_ip for node in cfg.GetAllNodesInfo().values()]:
return True
return False
def SetupDefaultNetutilsMock(netutils_mod, cfg):
"""Configures the given netutils_mod mock to work with the given config.
All relevant functions in netutils_mod are stubbed in such a way that they
are consistent with the configuration.
@param netutils_mod: the mock module to configure
@type cfg: cmdlib.testsupport.ConfigMock
@param cfg: the configuration to query for netutils request
"""
netutils_mod.GetHostname.side_effect = \
compat.partial(_GetHostnameMock, cfg, netutils_mod.GetHostname)
netutils_mod.TcpPing.side_effect = \
compat.partial(_TcpPingMock, cfg, netutils_mod.TcpPing)
netutils_mod.GetDaemonPort.side_effect = netutils.GetDaemonPort
netutils_mod.FormatAddress.side_effect = netutils.FormatAddress
#
#
# Copyright (C) 2013 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Support for mocking the ssh module"""
from cmdlib.testsupport.util import patchModule
# pylint: disable=C0103
def patchSsh(module_under_test):
"""Patches the L{ganeti.ssh} 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, "ssh")
#
#
# Copyright (C) 2013 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Utility functions or the cmdlib test framework"""
import mock
# pylint: disable=C0103
def patchModule(module_under_test, mock_module):
"""Computes the module prefix required to mock parts of the Ganeti code.
@type module_under_test: string
@param module_under_test: the module within cmdlib which is tested. The
"ganeti.cmdlib" prefix is optional.
@type mock_module
@param mock_module: the module which should be mocked.
"""
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))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment