Revision 08cef8fc

b/Makefile.am
1335 1335
	test/py/cmdlib/testsupport/config_mock.py \
1336 1336
	test/py/cmdlib/testsupport/iallocator_mock.py \
1337 1337
	test/py/cmdlib/testsupport/lock_manager_mock.py \
1338
	test/py/cmdlib/testsupport/netutils_mock.py \
1338 1339
	test/py/cmdlib/testsupport/processor_mock.py \
1339
	test/py/cmdlib/testsupport/rpc_runner_mock.py
1340
	test/py/cmdlib/testsupport/rpc_runner_mock.py \
1341
	test/py/cmdlib/testsupport/ssh_mock.py \
1342
	test/py/cmdlib/testsupport/util.py
1340 1343

  
1341 1344
haskell_tests = test/hs/htest
1342 1345

  
b/test/py/cmdlib/cluster_unittest.py
402 402
    self.ExecOpCode(op)
403 403

  
404 404

  
405
class TestLUClusterRename(CmdlibTestCase):
406
  NEW_NAME = "new-name.example.com"
407
  NEW_IP = "1.2.3.4"
408

  
409
  def testNoChanges(self):
410
    op = opcodes.OpClusterRename(name=self.cfg.GetClusterName())
411

  
412
    self.ExecOpCodeExpectOpPrereqError(op, "name nor the IP address")
413

  
414
  def testReachableIp(self):
415
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
416

  
417
    self.netutils_mod.GetHostname.return_value = \
418
      HostnameMock(self.NEW_NAME, self.NEW_IP)
419
    self.netutils_mod.TcpPing.return_value = True
420

  
421
    self.ExecOpCodeExpectOpPrereqError(op, "is reachable on the network")
422

  
423
  def testValidRename(self):
424
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
425

  
426
    self.netutils_mod.GetHostname.return_value = \
427
      HostnameMock(self.NEW_NAME, self.NEW_IP)
428

  
429
    self.ExecOpCode(op)
430

  
431
    self.assertEqual(1, self.ssh_mod.WriteKnownHostsFile.call_count)
432
    self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
433
      self.cfg.GetMasterNode(),
434
      self.cfg.GetMasterNetworkParameters(),
435
      False)
436
    self.rpc.call_node_activate_master_ip.assert_called_once_with(
437
      self.cfg.GetMasterNode(),
438
      self.cfg.GetMasterNetworkParameters(),
439
      False)
440

  
441
  def testRenameOfflineMaster(self):
442
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
443

  
444
    self.cfg.GetMasterNodeInfo().offline = True
445
    self.netutils_mod.GetHostname.return_value = \
446
      HostnameMock(self.NEW_NAME, self.NEW_IP)
447

  
448
    self.ExecOpCode(op)
449

  
450

  
405 451
if __name__ == "__main__":
406 452
  testutils.GanetiTestProgram()
b/test/py/cmdlib/testsupport/__init__.py
27 27
from cmdlib.testsupport.config_mock import ConfigMock
28 28
from cmdlib.testsupport.iallocator_mock import patchIAllocator
29 29
from cmdlib.testsupport.lock_manager_mock import LockManagerMock
30
from cmdlib.testsupport.netutils_mock import patchNetutils, HostnameMock
30 31
from cmdlib.testsupport.processor_mock import ProcessorMock
31 32
from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock, \
32 33
  RpcResultsBuilder
34
from cmdlib.testsupport.ssh_mock import patchSsh
33 35

  
34 36
__all__ = ["CmdlibTestCase",
35 37
           "ConfigMock",
36
           "patchIAllocator",
37 38
           "CreateRpcRunnerMock",
39
           "HostnameMock",
40
           "patchIAllocator",
41
           "patchNetutils",
42
           "patchSsh",
38 43
           "LockManagerMock",
39 44
           "ProcessorMock",
40 45
           "RpcResultsBuilder",
b/test/py/cmdlib/testsupport/cmdlib_testcase.py
29 29
from cmdlib.testsupport.config_mock import ConfigMock
30 30
from cmdlib.testsupport.iallocator_mock import patchIAllocator
31 31
from cmdlib.testsupport.lock_manager_mock import LockManagerMock
32
from cmdlib.testsupport.netutils_mock import patchNetutils, \
33
  SetupDefaultNetutilsMock
32 34
from cmdlib.testsupport.processor_mock import ProcessorMock
33 35
from cmdlib.testsupport.rpc_runner_mock import CreateRpcRunnerMock
36
from cmdlib.testsupport.ssh_mock import patchSsh
34 37

  
35 38
from ganeti import errors
36 39
from ganeti import opcodes
......
60 63
    * C{rpc}: @see L{CreateRpcRunnerMock}
61 64
    * C{iallocator_cls}: @see L{patchIAllocator}
62 65
    * C{mcpu}: @see L{ProcessorMock}
66
    * C{netutils_mod}: @see L{patchNetutils}
67
    * C{ssh_mod}: @see L{patchSsh}
63 68

  
64 69
  """
65 70

  
......
68 73
  def setUp(self):
69 74
    super(CmdlibTestCase, self).setUp()
70 75
    self._iallocator_patcher = None
76
    self._netutils_patcher = None
77
    self._ssh_patcher = None
71 78

  
72 79
    try:
73 80
      runtime.InitArchInfo()
......
81 88
    if self._iallocator_patcher is not None:
82 89
      self._iallocator_patcher.stop()
83 90
      self._iallocator_patcher = None
91
    if self._netutils_patcher is not None:
92
      self._netutils_patcher.stop()
93
      self._netutils_patcher = None
94
    if self._ssh_patcher is not None:
95
      self._ssh_patcher.stop()
96
      self._ssh_patcher = None
84 97

  
85 98
  def tearDown(self):
86 99
    super(CmdlibTestCase, self).tearDown()
......
105 118
    self.cfg = ConfigMock()
106 119
    self.glm = LockManagerMock()
107 120
    self.rpc = CreateRpcRunnerMock()
121
    ctx = GanetiContextMock(self.cfg, self.glm, self.rpc)
122
    self.mcpu = ProcessorMock(ctx)
108 123

  
109 124
    self._StopPatchers()
110 125
    try:
111 126
      self._iallocator_patcher = patchIAllocator(self._GetTestModule())
112 127
      self.iallocator_cls = self._iallocator_patcher.start()
113
    except ImportError:
128
    except (ImportError, AttributeError):
114 129
      # this test module does not use iallocator, no patching performed
115 130
      self._iallocator_patcher = None
116 131

  
117
    ctx = GanetiContextMock(self.cfg, self.glm, self.rpc)
118
    self.mcpu = ProcessorMock(ctx)
132
    try:
133
      self._netutils_patcher = patchNetutils(self._GetTestModule())
134
      self.netutils_mod = self._netutils_patcher.start()
135
      SetupDefaultNetutilsMock(self.netutils_mod, self.cfg)
136
    except (ImportError, AttributeError):
137
      # this test module does not use netutils, no patching performed
138
      self._netutils_patcher = None
139

  
140
    try:
141
      self._ssh_patcher = patchSsh(self._GetTestModule())
142
      self.ssh_mod = self._ssh_patcher.start()
143
    except (ImportError, AttributeError):
144
      # this test module does not use ssh, no patching performed
145
      self._ssh_patcher = None
119 146

  
120 147
  def ExecOpCode(self, opcode):
121 148
    """Executes the given opcode.
b/test/py/cmdlib/testsupport/iallocator_mock.py
22 22
"""Support for mocking the IAllocator interface"""
23 23

  
24 24

  
25
import mock
25
from cmdlib.testsupport.util import patchModule
26 26

  
27 27

  
28 28
# pylint: disable=C0103
......
36 36
        "ganeti.cmdlib" prefix is optional.
37 37

  
38 38
  """
39
  if not module_under_test.startswith("ganeti.cmdlib"):
40
    module_under_test = "ganeti.cmdlib." + module_under_test
41
  return mock.patch("%s.iallocator.IAllocator" % module_under_test)
39
  return patchModule(module_under_test, "iallocator.IAllocator")
b/test/py/cmdlib/testsupport/netutils_mock.py
1
#
2
#
3

  
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Support for mocking the netutils module"""
23

  
24
import mock
25

  
26

  
27
from ganeti import compat
28
from ganeti import errors
29
from ganeti import netutils
30
from cmdlib.testsupport.util import patchModule
31

  
32

  
33
# pylint: disable=C0103
34
def patchNetutils(module_under_test):
35
  """Patches the L{ganeti.netutils} module for tests.
36

  
37
  This function is meant to be used as a decorator for test methods.
38

  
39
  @type module_under_test: string
40
  @param module_under_test: the module within cmdlib which is tested. The
41
        "ganeti.cmdlib" prefix is optional.
42

  
43
  """
44
  return patchModule(module_under_test, "netutils")
45

  
46

  
47
class HostnameMock(object):
48
  """Simple mocked version of L{netutils.Hostname}.
49

  
50
  """
51
  def __init__(self, name, ip):
52
    self.name = name
53
    self.ip = ip
54

  
55

  
56
def _IsOverwrittenReturnValue(value):
57
  return value is not None and value != mock.DEFAULT and \
58
      not isinstance(value, mock.Mock)
59

  
60

  
61
# pylint: disable=W0613
62
def _GetHostnameMock(cfg, mock_fct, name=None, family=None):
63
  if _IsOverwrittenReturnValue(mock_fct.return_value):
64
    return mock.DEFAULT
65

  
66
  if name is None:
67
    name = cfg.GetMasterNodeName()
68

  
69
  if name == cfg.GetClusterName():
70
    cluster = cfg.GetClusterInfo()
71
    return HostnameMock(cluster.cluster_name, cluster.master_ip)
72

  
73
  node = cfg.GetNodeInfoByName(name)
74
  if node is None:
75

  
76
    raise errors.OpPrereqError(
77
      "Mock error: The given name '%s' is not in the config" % name,
78
      errors.ECODE_RESOLVER)
79

  
80
  return HostnameMock(node.name, node.primary_ip)
81

  
82

  
83
# pylint: disable=W0613
84
def _TcpPingMock(cfg, mock_fct, target, port, timeout=None,
85
                 live_port_needed=None, source=None):
86
  if _IsOverwrittenReturnValue(mock_fct.return_value):
87
    return mock.DEFAULT
88

  
89
  if target == cfg.GetClusterName():
90
    return True
91
  if cfg.GetNodeInfoByName(target) is not None:
92
    return True
93
  if target in [node.primary_ip for node in cfg.GetAllNodesInfo().values()]:
94
    return True
95
  if target in [node.secondary_ip for node in cfg.GetAllNodesInfo().values()]:
96
    return True
97
  return False
98

  
99

  
100
def SetupDefaultNetutilsMock(netutils_mod, cfg):
101
  """Configures the given netutils_mod mock to work with the given config.
102

  
103
  All relevant functions in netutils_mod are stubbed in such a way that they
104
  are consistent with the configuration.
105

  
106
  @param netutils_mod: the mock module to configure
107
  @type cfg: cmdlib.testsupport.ConfigMock
108
  @param cfg: the configuration to query for netutils request
109

  
110
  """
111
  netutils_mod.GetHostname.side_effect = \
112
    compat.partial(_GetHostnameMock, cfg, netutils_mod.GetHostname)
113
  netutils_mod.TcpPing.side_effect = \
114
    compat.partial(_TcpPingMock, cfg, netutils_mod.TcpPing)
115
  netutils_mod.GetDaemonPort.side_effect = netutils.GetDaemonPort
116
  netutils_mod.FormatAddress.side_effect = netutils.FormatAddress
b/test/py/cmdlib/testsupport/ssh_mock.py
1
#
2
#
3

  
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Support for mocking the ssh module"""
23

  
24

  
25
from cmdlib.testsupport.util import patchModule
26

  
27

  
28
# pylint: disable=C0103
29
def patchSsh(module_under_test):
30
  """Patches the L{ganeti.ssh} module for tests.
31

  
32
  This function is meant to be used as a decorator for test methods.
33

  
34
  @type module_under_test: string
35
  @param module_under_test: the module within cmdlib which is tested. The
36
        "ganeti.cmdlib" prefix is optional.
37

  
38
  """
39
  return patchModule(module_under_test, "ssh")
b/test/py/cmdlib/testsupport/util.py
1
#
2
#
3

  
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Utility functions or the cmdlib test framework"""
23

  
24

  
25
import mock
26

  
27

  
28
# pylint: disable=C0103
29
def patchModule(module_under_test, mock_module):
30
  """Computes the module prefix required to mock parts of the Ganeti code.
31

  
32
  @type module_under_test: string
33
  @param module_under_test: the module within cmdlib which is tested. The
34
        "ganeti.cmdlib" prefix is optional.
35
  @type mock_module
36
  @param mock_module: the module which should be mocked.
37

  
38
  """
39
  if not module_under_test.startswith("ganeti.cmdlib"):
40
    module_under_test = "ganeti.cmdlib." + module_under_test
41
  return mock.patch("%s.%s" % (module_under_test, mock_module))

Also available in: Unified diff