diff mbox

[V3,3/3] qemu-iotests: Add 088 new test for drive-mirror-replace.

Message ID 1394810322-13237-4-git-send-email-benoit.canet@irqsave.net
State New
Headers show

Commit Message

Benoît Canet March 14, 2014, 3:18 p.m. UTC
Tests for drive-mirror-replace whose purpose is to enable quorum file mirroring
and replacement after failure.

Signed-off-by: Benoit Canet <benoit@irqsave.net>
---
 tests/qemu-iotests/041        |  34 +------
 tests/qemu-iotests/088        | 219 ++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/088.out    |   5 +
 tests/qemu-iotests/group      |   1 +
 tests/qemu-iotests/iotests.py |  33 +++++++
 5 files changed, 259 insertions(+), 33 deletions(-)
 create mode 100755 tests/qemu-iotests/088
 create mode 100644 tests/qemu-iotests/088.out

Comments

Max Reitz March 15, 2014, 7:58 p.m. UTC | #1
On 14.03.2014 16:18, Benoît Canet wrote:
> Tests for drive-mirror-replace whose purpose is to enable quorum file mirroring
> and replacement after failure.
>
> Signed-off-by: Benoit Canet <benoit@irqsave.net>
> ---
>   tests/qemu-iotests/041        |  34 +------
>   tests/qemu-iotests/088        | 219 ++++++++++++++++++++++++++++++++++++++++++
>   tests/qemu-iotests/088.out    |   5 +
>   tests/qemu-iotests/group      |   1 +
>   tests/qemu-iotests/iotests.py |  33 +++++++
>   5 files changed, 259 insertions(+), 33 deletions(-)
>   create mode 100755 tests/qemu-iotests/088
>   create mode 100644 tests/qemu-iotests/088.out

Reviewed-by: Max Reitz <mreitz@redhat.com>
diff mbox

Patch

diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index ec470b2..10535a6 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -21,45 +21,13 @@ 
 import time
 import os
 import iotests
-from iotests import qemu_img, qemu_io
+from iotests import qemu_img, qemu_io, ImageMirroringTestCase
 
 backing_img = os.path.join(iotests.test_dir, 'backing.img')
 target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
 test_img = os.path.join(iotests.test_dir, 'test.img')
 target_img = os.path.join(iotests.test_dir, 'target.img')
 
-class ImageMirroringTestCase(iotests.QMPTestCase):
-    '''Abstract base class for image mirroring test cases'''
-
-    def wait_ready(self, drive='drive0'):
-        '''Wait until a block job BLOCK_JOB_READY event'''
-        ready = False
-        while not ready:
-            for event in self.vm.get_qmp_events(wait=True):
-                if event['event'] == 'BLOCK_JOB_READY':
-                    self.assert_qmp(event, 'data/type', 'mirror')
-                    self.assert_qmp(event, 'data/device', drive)
-                    ready = True
-
-    def wait_ready_and_cancel(self, drive='drive0'):
-        self.wait_ready(drive)
-        event = self.cancel_and_wait()
-        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
-        self.assert_qmp(event, 'data/type', 'mirror')
-        self.assert_qmp(event, 'data/offset', self.image_len)
-        self.assert_qmp(event, 'data/len', self.image_len)
-
-    def complete_and_wait(self, drive='drive0', wait_ready=True):
-        '''Complete a block job and wait for it to finish'''
-        if wait_ready:
-            self.wait_ready()
-
-        result = self.vm.qmp('block-job-complete', device=drive)
-        self.assert_qmp(result, 'return', {})
-
-        event = self.wait_until_completed()
-        self.assert_qmp(event, 'data/type', 'mirror')
-
 class TestSingleDrive(ImageMirroringTestCase):
     image_len = 1 * 1024 * 1024 # MB
 
diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088
new file mode 100755
index 0000000..5a5d1b4
--- /dev/null
+++ b/tests/qemu-iotests/088
@@ -0,0 +1,219 @@ 
+#!/usr/bin/env python
+#
+# Tests for Quorum image replacement
+#
+# Copyright (C) 2014 Nodalink, EURL.
+#
+# based on 041
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+import subprocess
+import time
+import os
+import iotests
+from iotests import qemu_img, qemu_img_args
+from iotests import ImageMirroringTestCase
+
+quorum_img1 = os.path.join(iotests.test_dir, 'quorum1.img')
+quorum_img2 = os.path.join(iotests.test_dir, 'quorum2.img')
+quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
+quorum_backup_img = os.path.join(iotests.test_dir, 'quorum_backup.img')
+quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
+quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
+
+class TestRepairQuorum(ImageMirroringTestCase):
+    """ This class test quorum file repair using drive-mirror.
+        It's mostly a fork of TestSingleDrive. """
+    image_len = 1 * 1024 * 1024 # MB
+    IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
+
+    def setUp(self):
+        self.vm = iotests.VM()
+
+        # Add each individual quorum images
+        for i in self.IMAGES:
+            qemu_img('create', '-f', iotests.imgfmt, i,
+                     str(self.image_len))
+            # Assign a node name to each quorum image in order to manipulate
+            # them
+            opts = "node-name=img%i" % self.IMAGES.index(i)
+            self.vm = self.vm.add_drive(i, opts)
+
+        self.vm.launch()
+
+        #assemble the quorum block device from the individual files
+        args = { "options" : { "driver": "quorum", "id": "quorum0",
+                 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
+        result = self.vm.qmp("blockdev-add", **args)
+        self.assert_qmp(result, 'return', {})
+
+
+    def tearDown(self):
+        self.vm.shutdown()
+        for i in self.IMAGES + [ quorum_repair_img ]:
+            # Do a try/except because the test may have deleted some images
+            try:
+                os.remove(i)
+            except OSError:
+                pass
+
+    def test_complete(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='img1', new_node_name='img11')
+        self.assert_qmp(result, 'return', {})
+
+        event = self.wait_until_completed(drive='quorum0')
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        result = self.vm.qmp('query-named-block-nodes')
+        self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
+        # TODO: a better test requiring some QEMU infrastructure will be added
+        #       to check that this file is really driven by quorum
+        self.vm.shutdown()
+        self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
+                        'target image does not match source after mirroring')
+
+    def test_device_not_active(self):
+        result = self.vm.qmp('drive-mirror-replace', device='quorum12',
+                             target_reference='img1', new_node_name='img11')
+        self.assert_qmp(result, 'error/class', 'DeviceNotActive')
+        self.vm.shutdown()
+
+    def test_sync_no_full(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='none',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='img1', new_node_name='img11')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+    def test_sync_empty_reference(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='', new_node_name='img11')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+    def test_sync_no_reference(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             new_node_name='img11')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+    def test_sync_no_node_name(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='img1')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+    def test_sync_empty_node_name(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='img1', new_node_name='')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+    def test_source_and_dest_equal(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
+                             target=quorum_repair_img, format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_ready(drive='quorum0')
+
+        result = self.vm.qmp('drive-mirror-replace', device='quorum0',
+                             target_reference='quorum0', new_node_name='img11')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        event = self.cancel_and_wait(drive='quorum0', resume=True)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
+        self.vm.shutdown()
+
+if __name__ == '__main__':
+    p1 = subprocess.Popen(qemu_img_args, stdout=subprocess.PIPE)
+    p2 = subprocess.Popen(["grep", "quorum"], stdin=p1.stdout, stdout=subprocess.PIPE)
+    p1.stdout.close()  # Allow p1 to receive a SIGsubprocess.PIPE if p2 exits.
+    has_quorum = len(p2.communicate()[0]) != 0
+    if has_quorum:
+        iotests.main(supported_fmts=['qcow2', 'qed'])
+    else:
+        iotests.notrun("no builtin quorum support")
diff --git a/tests/qemu-iotests/088.out b/tests/qemu-iotests/088.out
new file mode 100644
index 0000000..594c16f
--- /dev/null
+++ b/tests/qemu-iotests/088.out
@@ -0,0 +1,5 @@ 
+........
+----------------------------------------------------------------------
+Ran 8 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index b96c6bc..e590d09 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -89,3 +89,4 @@ 
 085 rw auto quick
 086 rw auto quick
 087 rw auto quick
+088 rw auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e4fa9af..a803943 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -272,6 +272,39 @@  class QMPTestCase(unittest.TestCase):
         self.assert_no_active_block_jobs()
         return event
 
+# made common here for 041 and 088
+class ImageMirroringTestCase(QMPTestCase):
+    '''Abstract base class for image mirroring test cases'''
+
+    def wait_ready(self, drive='drive0'):
+        '''Wait until a block job BLOCK_JOB_READY event'''
+        ready = False
+        while not ready:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_READY':
+                    self.assert_qmp(event, 'data/type', 'mirror')
+                    self.assert_qmp(event, 'data/device', drive)
+                    ready = True
+
+    def wait_ready_and_cancel(self, drive='drive0'):
+        self.wait_ready(drive=drive)
+        event = self.cancel_and_wait(drive=drive)
+        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
+        self.assert_qmp(event, 'data/type', 'mirror')
+        self.assert_qmp(event, 'data/offset', self.image_len)
+        self.assert_qmp(event, 'data/len', self.image_len)
+
+    def complete_and_wait(self, drive='drive0', wait_ready=True):
+        '''Complete a block job and wait for it to finish'''
+        if wait_ready:
+            self.wait_ready(drive=drive)
+
+        result = self.vm.qmp('block-job-complete', device=drive)
+        self.assert_qmp(result, 'return', {})
+
+        event = self.wait_until_completed(drive=drive)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
 def notrun(reason):
     '''Skip this test suite'''
     # Each test in qemu-iotests has a number ("seq")