iotests: test manual job dismissal

Signed-off-by: John Snow <jsnow@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
John Snow 2018-03-10 03:27:45 -05:00 committed by Kevin Wolf
parent b40dacdc7c
commit 6d8be96762
2 changed files with 189 additions and 2 deletions

View File

@ -29,6 +29,26 @@ backing_img = os.path.join(iotests.test_dir, 'backing.img')
test_img = os.path.join(iotests.test_dir, 'test.img')
target_img = os.path.join(iotests.test_dir, 'target.img')
def img_create(img, fmt=iotests.imgfmt, size='64M', **kwargs):
fullname = os.path.join(iotests.test_dir, '%s.%s' % (img, fmt))
optargs = []
for k,v in kwargs.iteritems():
optargs = optargs + ['-o', '%s=%s' % (k,v)]
args = ['create', '-f', fmt] + optargs + [fullname, size]
iotests.qemu_img(*args)
return fullname
def try_remove(img):
try:
os.remove(img)
except OSError:
pass
def io_write_patterns(img, patterns):
for pattern in patterns:
iotests.qemu_io('-c', 'write -P%s %s %s' % pattern, img)
class TestSyncModesNoneAndTop(iotests.QMPTestCase):
image_len = 64 * 1024 * 1024 # MB
@ -108,5 +128,172 @@ class TestBeforeWriteNotifier(iotests.QMPTestCase):
event = self.cancel_and_wait()
self.assert_qmp(event, 'data/type', 'backup')
class BackupTest(iotests.QMPTestCase):
def setUp(self):
self.vm = iotests.VM()
self.test_img = img_create('test')
self.dest_img = img_create('dest')
self.vm.add_drive(self.test_img)
self.vm.launch()
def tearDown(self):
self.vm.shutdown()
try_remove(self.test_img)
try_remove(self.dest_img)
def hmp_io_writes(self, drive, patterns):
for pattern in patterns:
self.vm.hmp_qemu_io(drive, 'write -P%s %s %s' % pattern)
self.vm.hmp_qemu_io(drive, 'flush')
def qmp_backup_and_wait(self, cmd='drive-backup', serror=None,
aerror=None, **kwargs):
if not self.qmp_backup(cmd, serror, **kwargs):
return False
return self.qmp_backup_wait(kwargs['device'], aerror)
def qmp_backup(self, cmd='drive-backup',
error=None, **kwargs):
self.assertTrue('device' in kwargs)
res = self.vm.qmp(cmd, **kwargs)
if error:
self.assert_qmp(res, 'error/desc', error)
return False
self.assert_qmp(res, 'return', {})
return True
def qmp_backup_wait(self, device, error=None):
event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED",
match={'data': {'device': device}})
self.assertNotEqual(event, None)
try:
failure = self.dictpath(event, 'data/error')
except AssertionError:
# Backup succeeded.
self.assert_qmp(event, 'data/offset', event['data']['len'])
return True
else:
# Failure.
self.assert_qmp(event, 'data/error', qerror)
return False
def test_dismiss_false(self):
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
sync='full', target=self.dest_img,
auto_dismiss=True)
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
def test_dismiss_true(self):
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
sync='full', target=self.dest_img,
auto_dismiss=False)
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return[0]/status', 'concluded')
res = self.vm.qmp('block-job-dismiss', id='drive0')
self.assert_qmp(res, 'return', {})
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
def test_dismiss_bad_id(self):
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
res = self.vm.qmp('block-job-dismiss', id='foobar')
self.assert_qmp(res, 'error/class', 'DeviceNotActive')
def test_dismiss_collision(self):
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
sync='full', target=self.dest_img,
auto_dismiss=False)
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return[0]/status', 'concluded')
# Leave zombie job un-dismissed, observe a failure:
res = self.qmp_backup_and_wait(serror='Need a root block node',
device='drive0', format=iotests.imgfmt,
sync='full', target=self.dest_img,
auto_dismiss=False)
self.assertEqual(res, False)
# OK, dismiss the zombie.
res = self.vm.qmp('block-job-dismiss', id='drive0')
self.assert_qmp(res, 'return', {})
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
# Ensure it's really gone.
self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
sync='full', target=self.dest_img,
auto_dismiss=False)
def dismissal_failure(self, dismissal_opt):
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
# Give blkdebug something to chew on
self.hmp_io_writes('drive0',
(('0x9a', 0, 512),
('0x55', '8M', '352k'),
('0x78', '15872k', '1M')))
# Add destination node via blkdebug
res = self.vm.qmp('blockdev-add',
node_name='target0',
driver=iotests.imgfmt,
file={
'driver': 'blkdebug',
'image': {
'driver': 'file',
'filename': self.dest_img
},
'inject-error': [{
'event': 'write_aio',
'errno': 5,
'immediately': False,
'once': True
}],
})
self.assert_qmp(res, 'return', {})
res = self.qmp_backup(cmd='blockdev-backup',
device='drive0', target='target0',
on_target_error='stop',
sync='full',
auto_dismiss=dismissal_opt)
self.assertTrue(res)
event = self.vm.event_wait(name="BLOCK_JOB_ERROR",
match={'data': {'device': 'drive0'}})
self.assertNotEqual(event, None)
# OK, job should be wedged
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return[0]/status', 'paused')
res = self.vm.qmp('block-job-dismiss', id='drive0')
self.assert_qmp(res, 'error/desc',
"Job 'drive0' in state 'paused' cannot accept"
" command verb 'dismiss'")
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return[0]/status', 'paused')
# OK, unstick job and move forward.
res = self.vm.qmp('block-job-resume', device='drive0')
self.assert_qmp(res, 'return', {})
# And now we need to wait for it to conclude;
res = self.qmp_backup_wait(device='drive0')
self.assertTrue(res)
if not dismissal_opt:
# Job should now be languishing:
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return[0]/status', 'concluded')
res = self.vm.qmp('block-job-dismiss', id='drive0')
self.assert_qmp(res, 'return', {})
res = self.vm.qmp('query-block-jobs')
self.assert_qmp(res, 'return', [])
def test_dismiss_premature(self):
self.dismissal_failure(False)
def test_dismiss_erroneous(self):
self.dismissal_failure(True)
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2', 'qed'])

View File

@ -1,5 +1,5 @@
...
.........
----------------------------------------------------------------------
Ran 3 tests
Ran 9 tests
OK