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.
Reviewed-by: Max Reitz <mre...@redhat.com> Signed-off-by: John Snow <js...@redhat.com> --- tests/qemu-iotests/124 | 57 ++++++++++++++++++++++++++++++++++++++++++- tests/qemu-iotests/124.out | 4 +-- tests/qemu-iotests/iotests.py | 6 +++-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index da8f0e0..1c07387 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -135,7 +135,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) @@ -180,6 +184,57 @@ class TestIncrementalBackup(iotests.QMPTestCase): return True + def test_incremental_failure(self): + '''Test: Verify backups made after a failure are correct. + + Simulate a failure during an incremental backup block job, + emulate additional writes, then create another incremental backup + afterwards and verify that the backup created is correct. + ''' + + # Create a blkdebug interface to this img as 'drive1' + result = self.vm.qmp('blockdev-add', options={ + 'id': 'drive1', + 'driver': iotests.imgfmt, + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': self.test_img + }, + 'set-state': [{ + 'event': 'flush_to_disk', + 'state': 1, + 'new_state': 2 + }], + 'inject-error': [{ + 'event': 'read_aio', + 'errno': 5, + 'state': 2, + 'immediately': False, + 'once': True + }], + } + }) + self.assert_qmp(result, 'return', {}) + + self.create_full_backup() + self.add_bitmap('bitmap0', 'drive1') + # Note: at this point, during a normal execution, + # Assume that the VM resumes and begins issuing IO requests here. + + 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/124.out b/tests/qemu-iotests/124.out index 8d7e996..89968f3 100644 --- a/tests/qemu-iotests/124.out +++ b/tests/qemu-iotests/124.out @@ -1,5 +1,5 @@ -... +.... ---------------------------------------------------------------------- -Ran 3 tests +Ran 4 tests OK diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 1402854..0522501 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -273,14 +273,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 -- 1.9.3