mirror of https://github.com/xemu-project/xemu.git
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:
parent
b40dacdc7c
commit
6d8be96762
|
@ -29,6 +29,26 @@ backing_img = os.path.join(iotests.test_dir, 'backing.img')
|
||||||
test_img = os.path.join(iotests.test_dir, 'test.img')
|
test_img = os.path.join(iotests.test_dir, 'test.img')
|
||||||
target_img = os.path.join(iotests.test_dir, 'target.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):
|
class TestSyncModesNoneAndTop(iotests.QMPTestCase):
|
||||||
image_len = 64 * 1024 * 1024 # MB
|
image_len = 64 * 1024 * 1024 # MB
|
||||||
|
|
||||||
|
@ -108,5 +128,172 @@ class TestBeforeWriteNotifier(iotests.QMPTestCase):
|
||||||
event = self.cancel_and_wait()
|
event = self.cancel_and_wait()
|
||||||
self.assert_qmp(event, 'data/type', 'backup')
|
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__':
|
if __name__ == '__main__':
|
||||||
iotests.main(supported_fmts=['qcow2', 'qed'])
|
iotests.main(supported_fmts=['qcow2', 'qed'])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
...
|
.........
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 3 tests
|
Ran 9 tests
|
||||||
|
|
||||||
OK
|
OK
|
||||||
|
|
Loading…
Reference in New Issue