diff mbox

[v12,17/17] iotests: add incremental backup failure recovery test

Message ID 1423532117-14490-18-git-send-email-jsnow@redhat.com
State New
Headers show

Commit Message

John Snow Feb. 10, 2015, 1:35 a.m. UTC
To test the failure case, we modify iotests.py to allow us to specify
that we'd like to allow failures when we wait for block job events.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 tests/qemu-iotests/112        | 55 ++++++++++++++++++++++++++++++++++++++++++-
 tests/qemu-iotests/112.out    |  4 ++--
 tests/qemu-iotests/iotests.py |  6 +++--
 3 files changed, 60 insertions(+), 5 deletions(-)

Comments

Max Reitz Feb. 11, 2015, 10:01 p.m. UTC | #1
On 2015-02-09 at 20:35, John Snow wrote:
> To test the failure case, we modify iotests.py to allow us to specify
> that we'd like to allow failures when we wait for block job events.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   tests/qemu-iotests/112        | 55 ++++++++++++++++++++++++++++++++++++++++++-
>   tests/qemu-iotests/112.out    |  4 ++--
>   tests/qemu-iotests/iotests.py |  6 +++--
>   3 files changed, 60 insertions(+), 5 deletions(-)
>
> diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
> index 7d1a6ec..0c1d35a 100644
> --- a/tests/qemu-iotests/112
> +++ b/tests/qemu-iotests/112
> @@ -24,6 +24,11 @@ import os
>   import iotests
>   from iotests import qemu_img, qemu_io, create_image
>   
> +def blkdebug_rule(file, type, **kwargs):
> +    file.write('[%s]\n' % type)
> +    for key, value in kwargs.iteritems():
> +        file.write('%s = "%s"\n' % (key, value))
> +    file.write('\n')
>   
>   def io_write_patterns(img, patterns):
>       for pattern in patterns:
> @@ -136,7 +141,11 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>                                mode='existing')
>           self.assert_qmp(result, 'return', {})
>   
> -        event = self.wait_until_completed(bitmap.node, check_offset=validate)
> +        event = self.wait_until_completed(bitmap.node, check_offset=validate,
> +                                          allow_failures=(not validate))
> +        if 'error' in event['data']:
> +            bitmap.del_target()
> +            return False
>           if validate:
>               return self.check_incremental(target)
>   
> @@ -221,6 +230,50 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>           self.assertTrue(res1 and res2)
>   
>   
> +    def test_incremental_failure(self):
> +        blkdebug = os.path.join(iotests.test_dir, 'blkdebug.conf')
> +        self.files.append(blkdebug)
> +
> +        with open(blkdebug, 'w+') as file:
> +            blkdebug_rule(file, 'set-state',
> +                          event="flush_to_disk",
> +                          state="1",
> +                          new_state="2")
> +            blkdebug_rule(file, 'inject-error',
> +                          event="read_aio", errno="5",
> +                          state="2", immediately="off",
> +                          once="on")
> +
> +        # Create a blkdebug interface to this img as 'drive1'
> +        result = self.vm.qmp('blockdev-add', options={
> +            'id': 'drive1',
> +            'driver': iotests.imgfmt,
> +            'file': {
> +                'driver': 'blkdebug',
> +                'config': blkdebug,
> +                'image': {
> +                    'driver': 'file',
> +                    'filename': self.test_img
> +                }
> +            }
> +        })

Awwww, I've written such a nice QMP interface and you won't use it? :'-(

See test 071, I encourage you to try. ;-)

Max

> +        self.assert_qmp(result, 'return', {})
> +
> +        self.create_full_backup()
> +        self.add_bitmap('bitmap0', 'drive1')
> +        self.vm.hmp("c")
> +        self.hmp_io_writes('drive1', (('0xab', 0, 512),
> +                                      ('0xfe', '16M', '256k'),
> +                                      ('0x64', '32736k', '64k')))
> +
> +        result = self.create_incremental(validate=False)
> +        self.assertFalse(result)
> +        self.hmp_io_writes('drive1', (('0x9a', 0, 512),
> +                                      ('0x55', '8M', '352k'),
> +                                      ('0x78', '15872k', '1M')))
> +        self.create_incremental()
> +
> +
>       def test_sync_dirty_bitmap_missing(self):
>           self.assert_no_active_block_jobs()
>           self.files.append(self.foo_img)
> diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
> index 89968f3..914e373 100644
> --- a/tests/qemu-iotests/112.out
> +++ b/tests/qemu-iotests/112.out
> @@ -1,5 +1,5 @@
> -....
> +.....
>   ----------------------------------------------------------------------
> -Ran 4 tests
> +Ran 5 tests
>   
>   OK
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index 6bff935..e452c40 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -264,14 +264,16 @@ class QMPTestCase(unittest.TestCase):
>           self.assert_no_active_block_jobs()
>           return result
>   
> -    def wait_until_completed(self, drive='drive0', check_offset=True):
> +    def wait_until_completed(self, drive='drive0', check_offset=True,
> +                             allow_failures=False):
>           '''Wait for a block job to finish, returning the event'''
>           completed = False
>           while not completed:
>               for event in self.vm.get_qmp_events(wait=True):
>                   if event['event'] == 'BLOCK_JOB_COMPLETED':
>                       self.assert_qmp(event, 'data/device', drive)
> -                    self.assert_qmp_absent(event, 'data/error')
> +                    if not allow_failures:
> +                        self.assert_qmp_absent(event, 'data/error')
>                       if check_offset:
>                           self.assert_qmp(event, 'data/offset', event['data']['len'])
>                       completed = True
John Snow Feb. 11, 2015, 10:08 p.m. UTC | #2
On 02/11/2015 05:01 PM, Max Reitz wrote:
> On 2015-02-09 at 20:35, John Snow wrote:
>> To test the failure case, we modify iotests.py to allow us to specify
>> that we'd like to allow failures when we wait for block job events.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   tests/qemu-iotests/112        | 55
>> ++++++++++++++++++++++++++++++++++++++++++-
>>   tests/qemu-iotests/112.out    |  4 ++--
>>   tests/qemu-iotests/iotests.py |  6 +++--
>>   3 files changed, 60 insertions(+), 5 deletions(-)
>>
>> diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
>> index 7d1a6ec..0c1d35a 100644
>> --- a/tests/qemu-iotests/112
>> +++ b/tests/qemu-iotests/112
>> @@ -24,6 +24,11 @@ import os
>>   import iotests
>>   from iotests import qemu_img, qemu_io, create_image
>> +def blkdebug_rule(file, type, **kwargs):
>> +    file.write('[%s]\n' % type)
>> +    for key, value in kwargs.iteritems():
>> +        file.write('%s = "%s"\n' % (key, value))
>> +    file.write('\n')
>>   def io_write_patterns(img, patterns):
>>       for pattern in patterns:
>> @@ -136,7 +141,11 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>>                                mode='existing')
>>           self.assert_qmp(result, 'return', {})
>> -        event = self.wait_until_completed(bitmap.node,
>> check_offset=validate)
>> +        event = self.wait_until_completed(bitmap.node,
>> check_offset=validate,
>> +                                          allow_failures=(not validate))
>> +        if 'error' in event['data']:
>> +            bitmap.del_target()
>> +            return False
>>           if validate:
>>               return self.check_incremental(target)
>> @@ -221,6 +230,50 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>>           self.assertTrue(res1 and res2)
>> +    def test_incremental_failure(self):
>> +        blkdebug = os.path.join(iotests.test_dir, 'blkdebug.conf')
>> +        self.files.append(blkdebug)
>> +
>> +        with open(blkdebug, 'w+') as file:
>> +            blkdebug_rule(file, 'set-state',
>> +                          event="flush_to_disk",
>> +                          state="1",
>> +                          new_state="2")
>> +            blkdebug_rule(file, 'inject-error',
>> +                          event="read_aio", errno="5",
>> +                          state="2", immediately="off",
>> +                          once="on")
>> +
>> +        # Create a blkdebug interface to this img as 'drive1'
>> +        result = self.vm.qmp('blockdev-add', options={
>> +            'id': 'drive1',
>> +            'driver': iotests.imgfmt,
>> +            'file': {
>> +                'driver': 'blkdebug',
>> +                'config': blkdebug,
>> +                'image': {
>> +                    'driver': 'file',
>> +                    'filename': self.test_img
>> +                }
>> +            }
>> +        })
>
> Awwww, I've written such a nice QMP interface and you won't use it? :'-(
>
> See test 071, I encourage you to try. ;-)
>
> Max
>

Aww, you're going to hold out on me for that?

(Actually, I did notice when you reviewed my blkdebug patch but not 
before then. This was already working so I just left it. (Though it is 
nicer in that you don't have to create a file. (I'll look.)))

>> +        self.assert_qmp(result, 'return', {})
>> +
>> +        self.create_full_backup()
>> +        self.add_bitmap('bitmap0', 'drive1')
>> +        self.vm.hmp("c")
>> +        self.hmp_io_writes('drive1', (('0xab', 0, 512),
>> +                                      ('0xfe', '16M', '256k'),
>> +                                      ('0x64', '32736k', '64k')))
>> +
>> +        result = self.create_incremental(validate=False)
>> +        self.assertFalse(result)
>> +        self.hmp_io_writes('drive1', (('0x9a', 0, 512),
>> +                                      ('0x55', '8M', '352k'),
>> +                                      ('0x78', '15872k', '1M')))
>> +        self.create_incremental()
>> +
>> +
>>       def test_sync_dirty_bitmap_missing(self):
>>           self.assert_no_active_block_jobs()
>>           self.files.append(self.foo_img)
>> diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
>> index 89968f3..914e373 100644
>> --- a/tests/qemu-iotests/112.out
>> +++ b/tests/qemu-iotests/112.out
>> @@ -1,5 +1,5 @@
>> -....
>> +.....
>>   ----------------------------------------------------------------------
>> -Ran 4 tests
>> +Ran 5 tests
>>   OK
>> diff --git a/tests/qemu-iotests/iotests.py
>> b/tests/qemu-iotests/iotests.py
>> index 6bff935..e452c40 100644
>> --- a/tests/qemu-iotests/iotests.py
>> +++ b/tests/qemu-iotests/iotests.py
>> @@ -264,14 +264,16 @@ class QMPTestCase(unittest.TestCase):
>>           self.assert_no_active_block_jobs()
>>           return result
>> -    def wait_until_completed(self, drive='drive0', check_offset=True):
>> +    def wait_until_completed(self, drive='drive0', check_offset=True,
>> +                             allow_failures=False):
>>           '''Wait for a block job to finish, returning the event'''
>>           completed = False
>>           while not completed:
>>               for event in self.vm.get_qmp_events(wait=True):
>>                   if event['event'] == 'BLOCK_JOB_COMPLETED':
>>                       self.assert_qmp(event, 'data/device', drive)
>> -                    self.assert_qmp_absent(event, 'data/error')
>> +                    if not allow_failures:
>> +                        self.assert_qmp_absent(event, 'data/error')
>>                       if check_offset:
>>                           self.assert_qmp(event, 'data/offset',
>> event['data']['len'])
>>                       completed = True
>
Max Reitz Feb. 11, 2015, 10:11 p.m. UTC | #3
On 2015-02-11 at 17:08, John Snow wrote:
>
>
> On 02/11/2015 05:01 PM, Max Reitz wrote:
>> On 2015-02-09 at 20:35, John Snow wrote:
>>> To test the failure case, we modify iotests.py to allow us to specify
>>> that we'd like to allow failures when we wait for block job events.
>>>
>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>> ---
>>>   tests/qemu-iotests/112        | 55
>>> ++++++++++++++++++++++++++++++++++++++++++-
>>>   tests/qemu-iotests/112.out    |  4 ++--
>>>   tests/qemu-iotests/iotests.py |  6 +++--
>>>   3 files changed, 60 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
>>> index 7d1a6ec..0c1d35a 100644
>>> --- a/tests/qemu-iotests/112
>>> +++ b/tests/qemu-iotests/112
>>> @@ -24,6 +24,11 @@ import os
>>>   import iotests
>>>   from iotests import qemu_img, qemu_io, create_image
>>> +def blkdebug_rule(file, type, **kwargs):
>>> +    file.write('[%s]\n' % type)
>>> +    for key, value in kwargs.iteritems():
>>> +        file.write('%s = "%s"\n' % (key, value))
>>> +    file.write('\n')
>>>   def io_write_patterns(img, patterns):
>>>       for pattern in patterns:
>>> @@ -136,7 +141,11 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>>>                                mode='existing')
>>>           self.assert_qmp(result, 'return', {})
>>> -        event = self.wait_until_completed(bitmap.node,
>>> check_offset=validate)
>>> +        event = self.wait_until_completed(bitmap.node,
>>> check_offset=validate,
>>> +                                          allow_failures=(not 
>>> validate))
>>> +        if 'error' in event['data']:
>>> +            bitmap.del_target()
>>> +            return False
>>>           if validate:
>>>               return self.check_incremental(target)
>>> @@ -221,6 +230,50 @@ class TestIncrementalBackup(iotests.QMPTestCase):
>>>           self.assertTrue(res1 and res2)
>>> +    def test_incremental_failure(self):
>>> +        blkdebug = os.path.join(iotests.test_dir, 'blkdebug.conf')
>>> +        self.files.append(blkdebug)
>>> +
>>> +        with open(blkdebug, 'w+') as file:
>>> +            blkdebug_rule(file, 'set-state',
>>> +                          event="flush_to_disk",
>>> +                          state="1",
>>> +                          new_state="2")
>>> +            blkdebug_rule(file, 'inject-error',
>>> +                          event="read_aio", errno="5",
>>> +                          state="2", immediately="off",
>>> +                          once="on")
>>> +
>>> +        # Create a blkdebug interface to this img as 'drive1'
>>> +        result = self.vm.qmp('blockdev-add', options={
>>> +            'id': 'drive1',
>>> +            'driver': iotests.imgfmt,
>>> +            'file': {
>>> +                'driver': 'blkdebug',
>>> +                'config': blkdebug,
>>> +                'image': {
>>> +                    'driver': 'file',
>>> +                    'filename': self.test_img
>>> +                }
>>> +            }
>>> +        })
>>
>> Awwww, I've written such a nice QMP interface and you won't use it? :'-(
>>
>> See test 071, I encourage you to try. ;-)
>>
>> Max
>>
>
> Aww, you're going to hold out on me for that?

Yes, not least because I would have to take a peek into Python's I/O 
functions first. ;-)

Max

> (Actually, I did notice when you reviewed my blkdebug patch but not 
> before then. This was already working so I just left it. (Though it is 
> nicer in that you don't have to create a file. (I'll look.)))
>
>>> +        self.assert_qmp(result, 'return', {})
>>> +
>>> +        self.create_full_backup()
>>> +        self.add_bitmap('bitmap0', 'drive1')
>>> +        self.vm.hmp("c")
>>> +        self.hmp_io_writes('drive1', (('0xab', 0, 512),
>>> +                                      ('0xfe', '16M', '256k'),
>>> +                                      ('0x64', '32736k', '64k')))
>>> +
>>> +        result = self.create_incremental(validate=False)
>>> +        self.assertFalse(result)
>>> +        self.hmp_io_writes('drive1', (('0x9a', 0, 512),
>>> +                                      ('0x55', '8M', '352k'),
>>> +                                      ('0x78', '15872k', '1M')))
>>> +        self.create_incremental()
>>> +
>>> +
>>>       def test_sync_dirty_bitmap_missing(self):
>>>           self.assert_no_active_block_jobs()
>>>           self.files.append(self.foo_img)
>>> diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
>>> index 89968f3..914e373 100644
>>> --- a/tests/qemu-iotests/112.out
>>> +++ b/tests/qemu-iotests/112.out
>>> @@ -1,5 +1,5 @@
>>> -....
>>> +.....
>>> ----------------------------------------------------------------------
>>> -Ran 4 tests
>>> +Ran 5 tests
>>>   OK
>>> diff --git a/tests/qemu-iotests/iotests.py
>>> b/tests/qemu-iotests/iotests.py
>>> index 6bff935..e452c40 100644
>>> --- a/tests/qemu-iotests/iotests.py
>>> +++ b/tests/qemu-iotests/iotests.py
>>> @@ -264,14 +264,16 @@ class QMPTestCase(unittest.TestCase):
>>>           self.assert_no_active_block_jobs()
>>>           return result
>>> -    def wait_until_completed(self, drive='drive0', check_offset=True):
>>> +    def wait_until_completed(self, drive='drive0', check_offset=True,
>>> +                             allow_failures=False):
>>>           '''Wait for a block job to finish, returning the event'''
>>>           completed = False
>>>           while not completed:
>>>               for event in self.vm.get_qmp_events(wait=True):
>>>                   if event['event'] == 'BLOCK_JOB_COMPLETED':
>>>                       self.assert_qmp(event, 'data/device', drive)
>>> -                    self.assert_qmp_absent(event, 'data/error')
>>> +                    if not allow_failures:
>>> +                        self.assert_qmp_absent(event, 'data/error')
>>>                       if check_offset:
>>>                           self.assert_qmp(event, 'data/offset',
>>> event['data']['len'])
>>>                       completed = True
>>
diff mbox

Patch

diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 7d1a6ec..0c1d35a 100644
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -24,6 +24,11 @@  import os
 import iotests
 from iotests import qemu_img, qemu_io, create_image
 
+def blkdebug_rule(file, type, **kwargs):
+    file.write('[%s]\n' % type)
+    for key, value in kwargs.iteritems():
+        file.write('%s = "%s"\n' % (key, value))
+    file.write('\n')
 
 def io_write_patterns(img, patterns):
     for pattern in patterns:
@@ -136,7 +141,11 @@  class TestIncrementalBackup(iotests.QMPTestCase):
                              mode='existing')
         self.assert_qmp(result, 'return', {})
 
-        event = self.wait_until_completed(bitmap.node, check_offset=validate)
+        event = self.wait_until_completed(bitmap.node, check_offset=validate,
+                                          allow_failures=(not validate))
+        if 'error' in event['data']:
+            bitmap.del_target()
+            return False
         if validate:
             return self.check_incremental(target)
 
@@ -221,6 +230,50 @@  class TestIncrementalBackup(iotests.QMPTestCase):
         self.assertTrue(res1 and res2)
 
 
+    def test_incremental_failure(self):
+        blkdebug = os.path.join(iotests.test_dir, 'blkdebug.conf')
+        self.files.append(blkdebug)
+
+        with open(blkdebug, 'w+') as file:
+            blkdebug_rule(file, 'set-state',
+                          event="flush_to_disk",
+                          state="1",
+                          new_state="2")
+            blkdebug_rule(file, 'inject-error',
+                          event="read_aio", errno="5",
+                          state="2", immediately="off",
+                          once="on")
+
+        # Create a blkdebug interface to this img as 'drive1'
+        result = self.vm.qmp('blockdev-add', options={
+            'id': 'drive1',
+            'driver': iotests.imgfmt,
+            'file': {
+                'driver': 'blkdebug',
+                'config': blkdebug,
+                'image': {
+                    'driver': 'file',
+                    'filename': self.test_img
+                }
+            }
+        })
+        self.assert_qmp(result, 'return', {})
+
+        self.create_full_backup()
+        self.add_bitmap('bitmap0', 'drive1')
+        self.vm.hmp("c")
+        self.hmp_io_writes('drive1', (('0xab', 0, 512),
+                                      ('0xfe', '16M', '256k'),
+                                      ('0x64', '32736k', '64k')))
+
+        result = self.create_incremental(validate=False)
+        self.assertFalse(result)
+        self.hmp_io_writes('drive1', (('0x9a', 0, 512),
+                                      ('0x55', '8M', '352k'),
+                                      ('0x78', '15872k', '1M')))
+        self.create_incremental()
+
+
     def test_sync_dirty_bitmap_missing(self):
         self.assert_no_active_block_jobs()
         self.files.append(self.foo_img)
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
index 89968f3..914e373 100644
--- a/tests/qemu-iotests/112.out
+++ b/tests/qemu-iotests/112.out
@@ -1,5 +1,5 @@ 
-....
+.....
 ----------------------------------------------------------------------
-Ran 4 tests
+Ran 5 tests
 
 OK
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 6bff935..e452c40 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -264,14 +264,16 @@  class QMPTestCase(unittest.TestCase):
         self.assert_no_active_block_jobs()
         return result
 
-    def wait_until_completed(self, drive='drive0', check_offset=True):
+    def wait_until_completed(self, drive='drive0', check_offset=True,
+                             allow_failures=False):
         '''Wait for a block job to finish, returning the event'''
         completed = False
         while not completed:
             for event in self.vm.get_qmp_events(wait=True):
                 if event['event'] == 'BLOCK_JOB_COMPLETED':
                     self.assert_qmp(event, 'data/device', drive)
-                    self.assert_qmp_absent(event, 'data/error')
+                    if not allow_failures:
+                        self.assert_qmp_absent(event, 'data/error')
                     if check_offset:
                         self.assert_qmp(event, 'data/offset', event['data']['len'])
                     completed = True