From 129cce6944f31613f9befcd2ffaf5da14d706187 Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Wed, 3 Oct 2012 20:27:45 +0200
Subject: [PATCH] Add unit tests for cmdlib._WipeDisks

This is in preparation for adding disk wipe on growing disks.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Bernardo Dal Seno <bdalseno@google.com>
---
 test/ganeti.cmdlib_unittest.py | 161 ++++++++++++++++++++++++++++++++-
 1 file changed, 160 insertions(+), 1 deletion(-)

diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py
index 8dff7401a..58ba4a5ca 100755
--- a/test/ganeti.cmdlib_unittest.py
+++ b/test/ganeti.cmdlib_unittest.py
@@ -385,11 +385,13 @@ class TestClusterVerifyFiles(unittest.TestCase):
 
 
 class _FakeLU:
-  def __init__(self, cfg=NotImplemented, proc=NotImplemented):
+  def __init__(self, cfg=NotImplemented, proc=NotImplemented,
+               rpc=NotImplemented):
     self.warning_log = []
     self.info_log = []
     self.cfg = cfg
     self.proc = proc
+    self.rpc = rpc
 
   def LogWarning(self, text, *args):
     self.warning_log.append((text, args))
@@ -1238,5 +1240,162 @@ class TestGenerateDiskTemplate(unittest.TestCase):
       ])
 
 
+class _ConfigForDiskWipe:
+  def SetDiskID(self, device, node):
+    assert isinstance(device, objects.Disk)
+    assert node == "node1.example.com"
+
+
+class _RpcForDiskWipe:
+  def __init__(self, pause_cb, wipe_cb):
+    self._pause_cb = pause_cb
+    self._wipe_cb = wipe_cb
+
+  def call_blockdev_pause_resume_sync(self, node, disks, pause):
+    assert node == "node1.example.com"
+    return rpc.RpcResult(data=self._pause_cb(disks, pause))
+
+  def call_blockdev_wipe(self, node, bdev, offset, size):
+    assert node == "node1.example.com"
+    return rpc.RpcResult(data=self._wipe_cb(bdev, offset, size))
+
+
+class _DiskPauseTracker:
+  def __init__(self):
+    self.history = []
+
+  def __call__(self, (disks, instance), pause):
+    assert instance.disks == disks
+
+    self.history.extend((i.logical_id, i.size, pause)
+                        for i in disks)
+
+    return (True, [True] * len(disks))
+
+
+class TestWipeDisks(unittest.TestCase):
+  def testPauseFailure(self):
+    def _FailPause((disks, _), pause):
+      self.assertEqual(len(disks), 3)
+      self.assertTrue(pause)
+      return (False, "error")
+
+    lu = _FakeLU(rpc=_RpcForDiskWipe(_FailPause, NotImplemented),
+                 cfg=_ConfigForDiskWipe())
+
+    disks = [
+      objects.Disk(dev_type=constants.LD_LV),
+      objects.Disk(dev_type=constants.LD_LV),
+      objects.Disk(dev_type=constants.LD_LV),
+      ]
+
+    instance = objects.Instance(name="inst21201",
+                                primary_node="node1.example.com",
+                                disk_template=constants.DT_PLAIN,
+                                disks=disks)
+
+    self.assertRaises(errors.OpExecError, cmdlib._WipeDisks, lu, instance)
+
+  def testFailingWipe(self):
+    pt = _DiskPauseTracker()
+
+    def _WipeCb((disk, _), offset, size):
+      assert disk.logical_id == "disk0"
+      return (False, None)
+
+    lu = _FakeLU(rpc=_RpcForDiskWipe(pt, _WipeCb),
+                 cfg=_ConfigForDiskWipe())
+
+    disks = [
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
+                   size=100 * 1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
+                   size=500 * 1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=256),
+      ]
+
+    instance = objects.Instance(name="inst562",
+                                primary_node="node1.example.com",
+                                disk_template=constants.DT_PLAIN,
+                                disks=disks)
+
+    try:
+      cmdlib._WipeDisks(lu, instance)
+    except errors.OpExecError, err:
+      self.assertTrue(str(err), "Could not wipe disk 0 at offset 0 ")
+    else:
+      self.fail("Did not raise exception")
+
+    self.assertEqual(pt.history, [
+      ("disk0", 100 * 1024, True),
+      ("disk1", 500 * 1024, True),
+      ("disk2", 256, True),
+      ("disk0", 100 * 1024, False),
+      ("disk1", 500 * 1024, False),
+      ("disk2", 256, False),
+      ])
+
+  def testNormalWipe(self):
+    pt = _DiskPauseTracker()
+
+    progress = {}
+
+    def _WipeCb((disk, _), offset, size):
+      assert isinstance(offset, (long, int))
+      assert isinstance(size, (long, int))
+
+      max_chunk_size = (disk.size / 100.0 * constants.MIN_WIPE_CHUNK_PERCENT)
+
+      self.assertTrue(offset >= 0)
+      self.assertTrue((offset + size) <= disk.size)
+
+      self.assertTrue(size > 0)
+      self.assertTrue(size <= constants.MAX_WIPE_CHUNK)
+      self.assertTrue(size <= max_chunk_size)
+
+      self.assertTrue(offset == 0 or disk.logical_id in progress)
+
+      # Keep track of progress
+      cur_progress = progress.setdefault(disk.logical_id, 0)
+      self.assertEqual(cur_progress, offset)
+
+      progress[disk.logical_id] += size
+
+      return (True, None)
+
+    lu = _FakeLU(rpc=_RpcForDiskWipe(pt, _WipeCb),
+                 cfg=_ConfigForDiskWipe())
+
+    disks = [
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk0", size=1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
+                   size=500 * 1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=128),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk3",
+                   size=constants.MAX_WIPE_CHUNK),
+      ]
+
+    instance = objects.Instance(name="inst3560",
+                                primary_node="node1.example.com",
+                                disk_template=constants.DT_PLAIN,
+                                disks=disks)
+
+    cmdlib._WipeDisks(lu, instance)
+
+    self.assertEqual(pt.history, [
+      ("disk0", 1024, True),
+      ("disk1", 500 * 1024, True),
+      ("disk2", 128, True),
+      ("disk3", constants.MAX_WIPE_CHUNK, True),
+      ("disk0", 1024, False),
+      ("disk1", 500 * 1024, False),
+      ("disk2", 128, False),
+      ("disk3", constants.MAX_WIPE_CHUNK, False),
+      ])
+
+    # Ensure the complete disk has been wiped
+    self.assertEqual(progress, dict((i.logical_id, i.size) for i in disks))
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
-- 
GitLab