Patchwork [17/47] qemu-iotests: add tests for streaming error handling

login
register
mail settings
Submitter Paolo Bonzini
Date July 24, 2012, 11:03 a.m.
Message ID <1343127865-16608-18-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/172847/
State New
Headers show

Comments

Paolo Bonzini - July 24, 2012, 11:03 a.m.
Add a test for each of report/ignore/stop.  The tests use blkdebug
to generate an error in the middle of a script.  The error is
recoverable (once = "on") so that we can test resuming a job after
stopping for an error.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/qemu-iotests/030        |  138 +++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/group      |    2 +-
 tests/qemu-iotests/iotests.py |    7 +++
 3 files changed, 146 insertions(+), 1 deletion(-)
Kevin Wolf - Aug. 1, 2012, 10:43 a.m.
Am 24.07.2012 13:03, schrieb Paolo Bonzini:
> Add a test for each of report/ignore/stop.  The tests use blkdebug
> to generate an error in the middle of a script.  The error is
> recoverable (once = "on") so that we can test resuming a job after
> stopping for an error.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/qemu-iotests/030        |  138 +++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/group      |    2 +-
>  tests/qemu-iotests/iotests.py |    7 +++
>  3 files changed, 146 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
> index 0163945..c65bf5e 100755
> --- a/tests/qemu-iotests/030
> +++ b/tests/qemu-iotests/030
> @@ -163,6 +163,144 @@ class TestSingleDrive(ImageStreamingTestCase):
>          result = self.vm.qmp('block-stream', device='nonexistent')
>          self.assert_qmp(result, 'error/class', 'DeviceNotFound')
>  
> +class TestErrors(ImageStreamingTestCase):
> +    image_len = 2 * 1024 * 1024 # MB
> +
> +    # this should match STREAM_BUFFER_SIZE/512 in block/stream.c
> +    STREAM_BUFFER_SIZE = 512 * 1024
> +
> +    def create_blkdebug_file(self, name, event, errno):
> +        file = open(name, 'w')
> +        file.write('''
> +[inject-error]
> +state = "1"
> +event = "%s"
> +errno = "%d"
> +immediately = "off"
> +once = "on"
> +sector = "%d"
> +
> +[set-state]
> +state = "1"
> +event = "%s"
> +new_state = "2"
> +
> +[set-state]
> +state = "2"
> +event = "%s"
> +new_state = "1"
> +''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event))
> +        file.close()
> +
> +    def setUp(self):
> +        self.blkdebug_file = backing_img + ".blkdebug"
> +        self.create_image(backing_img, TestErrors.image_len)
> +        self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
> +        qemu_img('create', '-f', iotests.imgfmt,
> +                 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
> +                       % (self.blkdebug_file, backing_img),
> +                 test_img)
> +        self.vm = iotests.VM().add_drive(test_img)
> +        self.vm.launch()
> +
> +    def tearDown(self):
> +        self.vm.shutdown()
> +        os.remove(test_img)
> +        os.remove(backing_img)
> +        os.remove(self.blkdebug_file)
> +
> +    def test_report(self):
> +        self.assert_no_active_streams()
> +
> +        result = self.vm.qmp('block-stream', device='drive0')
> +        self.assert_qmp(result, 'return', {})
> +
> +        completed = False
> +        error = False
> +        while not completed:
> +            for event in self.vm.get_qmp_events(wait=True):
> +                if event['event'] == 'BLOCK_JOB_ERROR':
> +                    self.assert_qmp(event, 'data/device', 'drive0')
> +                    self.assert_qmp(event, 'data/operation', 'read')

data/action should be asserted as well (same in the other tests).

What about adding an enospc test as well, once with EIO and once with
ENOSPC?

Kevin
Paolo Bonzini - Aug. 1, 2012, 11:09 a.m.
Il 01/08/2012 12:43, Kevin Wolf ha scritto:
>> > +
>> > +    def test_report(self):
>> > +        self.assert_no_active_streams()
>> > +
>> > +        result = self.vm.qmp('block-stream', device='drive0')
>> > +        self.assert_qmp(result, 'return', {})
>> > +
>> > +        completed = False
>> > +        error = False
>> > +        while not completed:
>> > +            for event in self.vm.get_qmp_events(wait=True):
>> > +                if event['event'] == 'BLOCK_JOB_ERROR':
>> > +                    self.assert_qmp(event, 'data/device', 'drive0')
>> > +                    self.assert_qmp(event, 'data/operation', 'read')
> data/action should be asserted as well (same in the other tests).
> 
> What about adding an enospc test as well, once with EIO and once with
> ENOSPC?

Ok.

Paolo

Patch

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 0163945..c65bf5e 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -163,6 +163,144 @@  class TestSingleDrive(ImageStreamingTestCase):
         result = self.vm.qmp('block-stream', device='nonexistent')
         self.assert_qmp(result, 'error/class', 'DeviceNotFound')
 
+class TestErrors(ImageStreamingTestCase):
+    image_len = 2 * 1024 * 1024 # MB
+
+    # this should match STREAM_BUFFER_SIZE/512 in block/stream.c
+    STREAM_BUFFER_SIZE = 512 * 1024
+
+    def create_blkdebug_file(self, name, event, errno):
+        file = open(name, 'w')
+        file.write('''
+[inject-error]
+state = "1"
+event = "%s"
+errno = "%d"
+immediately = "off"
+once = "on"
+sector = "%d"
+
+[set-state]
+state = "1"
+event = "%s"
+new_state = "2"
+
+[set-state]
+state = "2"
+event = "%s"
+new_state = "1"
+''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event))
+        file.close()
+
+    def setUp(self):
+        self.blkdebug_file = backing_img + ".blkdebug"
+        self.create_image(backing_img, TestErrors.image_len)
+        self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
+        qemu_img('create', '-f', iotests.imgfmt,
+                 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
+                       % (self.blkdebug_file, backing_img),
+                 test_img)
+        self.vm = iotests.VM().add_drive(test_img)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+        os.remove(backing_img)
+        os.remove(self.blkdebug_file)
+
+    def test_report(self):
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block-stream', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        completed = False
+        error = False
+        while not completed:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_ERROR':
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/operation', 'read')
+                    error = True
+                elif event['event'] == 'BLOCK_JOB_COMPLETED':
+                    self.assertTrue(error, 'job completed unexpectedly')
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/error', 'Input/output error')
+                    self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
+                    self.assert_qmp(event, 'data/len', self.image_len)
+                    completed = True
+
+        self.assert_no_active_streams()
+        self.vm.shutdown()
+
+    def test_ignore(self):
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block-stream', device='drive0', on_error='ignore')
+        self.assert_qmp(result, 'return', {})
+
+        error = False
+        completed = False
+        while not completed:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_ERROR':
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/operation', 'read')
+                    result = self.vm.qmp('query-block-jobs')
+                    self.assert_qmp(result, 'return[0]/paused', False)
+                    error = True
+                elif event['event'] == 'BLOCK_JOB_COMPLETED':
+                    self.assertTrue(error, 'job completed unexpectedly')
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/error', 'Input/output error')
+                    self.assert_qmp(event, 'data/offset', self.image_len)
+                    self.assert_qmp(event, 'data/len', self.image_len)
+                    completed = True
+
+        self.assert_no_active_streams()
+        self.vm.shutdown()
+
+    def test_stop(self):
+        self.assert_no_active_streams()
+
+        result = self.vm.qmp('block-stream', device='drive0', on_error='stop')
+        self.assert_qmp(result, 'return', {})
+
+        error = False
+        completed = False
+        while not completed:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_ERROR':
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp(event, 'data/operation', 'read')
+
+                    result = self.vm.qmp('query-block-jobs')
+                    self.assert_qmp(result, 'return[0]/paused', True)
+                    self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE)
+                    self.assert_qmp(result, 'return[0]/io-status', 'failed')
+
+                    result = self.vm.qmp('block-job-resume', device='drive0')
+                    self.assert_qmp(result, 'return', {})
+
+                    result = self.vm.qmp('query-block-jobs')
+                    self.assert_qmp(result, 'return[0]/paused', False)
+                    self.assert_qmp(result, 'return[0]/io-status', 'ok')
+                    error = True
+                elif event['event'] == 'BLOCK_JOB_COMPLETED':
+                    self.assertTrue(error, 'job completed unexpectedly')
+                    self.assert_qmp(event, 'data/type', 'stream')
+                    self.assert_qmp(event, 'data/device', 'drive0')
+                    self.assert_qmp_absent(event, 'data/error')
+                    self.assert_qmp(event, 'data/offset', self.image_len)
+                    self.assert_qmp(event, 'data/len', self.image_len)
+                    completed = True
+
+        self.assert_no_active_streams()
+        self.vm.shutdown()
+
 class TestStreamStop(ImageStreamingTestCase):
     image_len = 8 * 1024 * 1024 * 1024 # GB
 
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 7a2c92b..a569bc9 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -36,7 +36,7 @@ 
 027 rw auto quick
 028 rw backing auto
 029 rw auto quick
-030 rw auto
+030 rw auto backing
 031 rw auto quick
 032 rw auto
 033 rw auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index a94ea75..3c60b2d 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -138,6 +138,13 @@  class QMPTestCase(unittest.TestCase):
                     self.fail('invalid index "%s" in path "%s" in "%s"' % (idx, path, str(d)))
         return d
 
+    def assert_qmp_absent(self, d, path):
+        try:
+            result = self.dictpath(d, path)
+        except AssertionError:
+            return
+        self.fail('path "%s" has value "%s"' % (path, str(result)))
+
     def assert_qmp(self, d, path, value):
         '''Assert that the value for a specific path in a QMP dict matches'''
         result = self.dictpath(d, path)