Add unit test for LUClusterRepairDiskSizes
authorThomas Thrainer <thomasth@google.com>
Tue, 30 Jul 2013 09:12:58 +0000 (11:12 +0200)
committerThomas Thrainer <thomasth@google.com>
Wed, 7 Aug 2013 15:52:25 +0000 (17:52 +0200)
Also add build method for easy building of disk objects to the test
framework.

Signed-off-by: Thomas Thrainer <thomasth@google.com>
Reviewed-by: Michele Tartara <mtartara@google.com>

test/py/cmdlib/cluster_unittest.py
test/py/cmdlib/testsupport/config_mock.py
test/py/cmdlib/testsupport/processor_mock.py

index 4901164..95b4c9f 100644 (file)
@@ -448,5 +448,99 @@ class TestLUClusterRename(CmdlibTestCase):
     self.ExecOpCode(op)
 
 
+class TestLUClusterRepairDiskSizes(CmdlibTestCase):
+  def testNoInstances(self):
+    op = opcodes.OpClusterRepairDiskSizes()
+
+    self.ExecOpCode(op)
+
+  def _SetUpInstanceSingleDisk(self, dev_type=constants.LD_LV):
+    pnode = self.cfg.GetMasterNodeInfo()
+    snode = self.cfg.AddNewNode()
+
+    inst = self.cfg.AddNewInstance()
+    disk = self.cfg.CreateDisk(dev_type=dev_type,
+                               primary_node=pnode,
+                               secondary_node=snode)
+    inst.disks.append(disk)
+
+    return (inst, disk)
+
+  def testSingleInstanceOnFailingNode(self):
+    (inst, _) = self._SetUpInstanceSingleDisk()
+    op = opcodes.OpClusterRepairDiskSizes(instances=[inst.name])
+
+    self.rpc.call_blockdev_getdimensions.return_value = \
+      RpcResultsBuilder(cfg=self.cfg) \
+        .CreateFailedNodeResult(self.cfg.GetMasterNode())
+
+    self.ExecOpCode(op)
+
+    self.mcpu.assertLogContainsRegex("Failure in blockdev_getdimensions")
+
+  def _ExecOpClusterRepairDiskSizes(self, node_data):
+    # not specifying instances repairs all
+    op = opcodes.OpClusterRepairDiskSizes()
+
+    self.rpc.call_blockdev_getdimensions.return_value = \
+      RpcResultsBuilder(cfg=self.cfg) \
+        .CreateSuccessfulNodeResult(self.cfg.GetMasterNode(), node_data)
+
+    return self.ExecOpCode(op)
+
+  def testInvalidResultData(self):
+    for data in [[], [None], ["invalid"], [("still", "invalid")]]:
+      self.ResetMocks()
+
+      self._SetUpInstanceSingleDisk()
+      self._ExecOpClusterRepairDiskSizes(data)
+
+      self.mcpu.assertLogContainsRegex("ignoring")
+
+  def testCorrectSize(self):
+    self._SetUpInstanceSingleDisk()
+    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
+    self.mcpu.assertLogIsEmpty()
+    self.assertEqual(0, len(changed))
+
+  def testWrongSize(self):
+    self._SetUpInstanceSingleDisk()
+    changed = self._ExecOpClusterRepairDiskSizes([(512 * 1024 * 1024, None)])
+    self.assertEqual(1, len(changed))
+
+  def testCorrectDRBD(self):
+    self._SetUpInstanceSingleDisk(dev_type=constants.LD_DRBD8)
+    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
+    self.mcpu.assertLogIsEmpty()
+    self.assertEqual(0, len(changed))
+
+  def testWrongDRBDChild(self):
+    (_, disk) = self._SetUpInstanceSingleDisk(dev_type=constants.LD_DRBD8)
+    disk.children[0].size = 512
+    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
+    self.assertEqual(1, len(changed))
+
+  def testExclusiveStorageInvalidResultData(self):
+    self._SetUpInstanceSingleDisk()
+    self.cfg.GetMasterNodeInfo().ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
+    self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
+
+    self.mcpu.assertLogContainsRegex(
+      "did not return valid spindles information")
+
+  def testExclusiveStorageCorrectSpindles(self):
+    (_, disk) = self._SetUpInstanceSingleDisk()
+    disk.spindles = 1
+    self.cfg.GetMasterNodeInfo().ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
+    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
+    self.assertEqual(0, len(changed))
+
+  def testExclusiveStorageWrongSpindles(self):
+    self._SetUpInstanceSingleDisk()
+    self.cfg.GetMasterNodeInfo().ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
+    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
+    self.assertEqual(1, len(changed))
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
index a77c8cc..7561cea 100644 (file)
@@ -46,6 +46,7 @@ class ConfigMock(config.ConfigWriter):
     self._cur_group_id = 1
     self._cur_node_id = 1
     self._cur_inst_id = 1
+    self._cur_disk_id = 1
 
     super(ConfigMock, self).__init__(cfg_file="/dev/null",
                                      _getents=_StubGetEntResolver())
@@ -53,6 +54,14 @@ class ConfigMock(config.ConfigWriter):
   def _GetUuid(self):
     return str(uuid_module.uuid4())
 
+  def _GetObjUuid(self, obj):
+    if obj is None:
+      return None
+    elif isinstance(obj, objects.ConfigObject):
+      return obj.uuid
+    else:
+      return obj
+
   def AddNewNodeGroup(self,
                       uuid=None,
                       name=None,
@@ -134,8 +143,7 @@ class ConfigMock(config.ConfigWriter):
       secondary_ip = "192.168.1.%d" % node_id
     if group is None:
       group = self._default_group.uuid
-    if isinstance(group, objects.NodeGroup):
-      group = group.uuid
+    group = self._GetObjUuid(group)
     if ndparams is None:
       ndparams = {}
 
@@ -191,8 +199,7 @@ class ConfigMock(config.ConfigWriter):
       name = "mock_inst_%d.example.com" % inst_id
     if primary_node is None:
       primary_node = self._master_node.uuid
-    if isinstance(primary_node, objects.Node):
-      primary_node = self._master_node.uuid
+    primary_node = self._GetObjUuid(primary_node)
     if hvparams is None:
       hvparams = {}
     if beparams is None:
@@ -221,6 +228,78 @@ class ConfigMock(config.ConfigWriter):
     self.AddInstance(inst, None)
     return inst
 
+  def CreateDisk(self,
+                 uuid=None,
+                 name=None,
+                 dev_type=constants.LD_LV,
+                 logical_id=None,
+                 physical_id=None,
+                 children=None,
+                 iv_name=None,
+                 size=1024,
+                 mode=constants.DISK_RDWR,
+                 params=None,
+                 spindles=None,
+                 primary_node=None,
+                 secondary_node=None):
+    """Create a new L{objecs.Disk} object
+
+    @rtype: L{objects.Disk}
+    @return: the newly create disk object
+
+    """
+    disk_id = self._cur_disk_id
+    self._cur_disk_id += 1
+
+    if uuid is None:
+      uuid = self._GetUuid()
+    if name is None:
+      name = "mock_disk_%d" % disk_id
+
+    if dev_type == constants.LD_DRBD8:
+      pnode_uuid = self._GetObjUuid(primary_node)
+      snode_uuid = self._GetObjUuid(secondary_node)
+      if logical_id is not None:
+        pnode_uuid = logical_id[0]
+        snode_uuid = logical_id[1]
+
+      if pnode_uuid is None or snode_uuid is None:
+        raise AssertionError("Trying to create DRBD disk without nodes!")
+
+      if logical_id is None:
+        logical_id = (pnode_uuid, snode_uuid,
+                      constants.FIRST_DRBD_PORT + disk_id,
+                      disk_id, disk_id, "mock_secret")
+      if children is None:
+        data_child = self.CreateDisk(dev_type=constants.LD_LV,
+                                     size=size)
+        meta_child = self.CreateDisk(dev_type=constants.LD_LV,
+                                     size=constants.DRBD_META_SIZE)
+        children = [data_child, meta_child]
+    elif dev_type == constants.LD_LV:
+      if logical_id is None:
+        logical_id = ("mockvg", "mock_disk_%d" % disk_id)
+    elif logical_id is None:
+      raise NotImplementedError
+    if children is None:
+      children = []
+    if iv_name is None:
+      iv_name = "mock_disk/%d" % disk_id
+    if params is None:
+      params = {}
+
+    return objects.Disk(uuid=uuid,
+                        name=name,
+                        dev_type=dev_type,
+                        logical_id=logical_id,
+                        physical_id=physical_id,
+                        children=children,
+                        iv_name=iv_name,
+                        size=size,
+                        mode=mode,
+                        params=params,
+                        spindles=spindles)
+
   def _OpenConfig(self, accept_foreign):
     self._config_data = objects.ConfigData(
       version=constants.CONFIG_VERSION,
index 9c95061..4a1c7ad 100644 (file)
@@ -152,3 +152,11 @@ class ProcessorMock(mcpu.Processor):
       "Could not find '%s' in LU log messages. Log is:\n%s" %
       (expected_regex, self.GetLogMessagesString())
     )
+
+  def assertLogIsEmpty(self):
+    """Asserts that the log does not contain any message.
+
+    """
+    if len(self.GetLogMessages()) > 0:
+      raise AssertionError("Log is not empty. Log is:\n%s" %
+                           self.GetLogMessagesString())