Signed-off-by: Alberto Garcia <be...@igalia.com> --- tests/qemu-iotests/139 | 189 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/139.out | 5 ++ tests/qemu-iotests/group | 1 + 3 files changed, 195 insertions(+) create mode 100644 tests/qemu-iotests/139 create mode 100644 tests/qemu-iotests/139.out
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 new file mode 100644 index 0000000..325ac7a --- /dev/null +++ b/tests/qemu-iotests/139 @@ -0,0 +1,189 @@ +#!/usr/bin/env python +# +# Test cases for the QMP 'blockdev-del' command +# +# Copyright (C) 2015 Igalia, S.L. +# Author: Alberto Garcia <be...@igalia.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import os +import iotests +import time + +base_img = os.path.join(iotests.test_dir, 'base.img') +new_img = os.path.join(iotests.test_dir, 'new.img') + +class TestBlockdevDel(iotests.QMPTestCase): + + def setUp(self): + iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M') + self.vm = iotests.VM() + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(base_img) + if os.path.isfile(new_img): + os.remove(new_img) + + def addBlockDev(self, block_backend = True): + opts = {'node-name': 'node0', + 'driver': iotests.imgfmt, + 'file': {'filename': base_img, + 'driver': 'file'}} + if block_backend: + opts['id'] = 'drive0' + result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts) + self.assert_qmp(result, 'return', {}) + + def delBlockDev(self, use_node_name = False, expect_error = False): + if use_node_name: + result = self.vm.qmp('blockdev-del', device = 'node0') + else: + result = self.vm.qmp('blockdev-del', device = 'drive0') + if expect_error: + self.assert_qmp(result, 'error/class', 'GenericError') + else: + self.assert_qmp(result, 'return', {}) + + def addDeviceModel(self): + result = self.vm.qmp('device_add', id = 'device0', + driver = 'virtio-blk-pci', drive = 'drive0') + self.assert_qmp(result, 'return', {}) + + def delDeviceModel(self): + result = self.vm.qmp('device_del', id = 'device0') + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('system_reset') + self.assert_qmp(result, 'return', {}) + + device_path = '/machine/peripheral/device0/virtio-backend' + event = self.vm.event_wait(name="DEVICE_DELETED", + match={'data': {'path': device_path}}) + self.assertNotEqual(event, None) + + event = self.vm.event_wait(name="DEVICE_DELETED", + match={'data': {'device': 'device0'}}) + self.assertNotEqual(event, None) + + def ejectDrive(self, expect_error = False): + result = self.vm.qmp('eject', device = 'drive0') + if expect_error: + self.assert_qmp(result, 'error/class', 'GenericError') + else: + self.assert_qmp(result, 'return', {}) + + def createSnapshot(self): + opts = {'node-name': 'node0', + 'snapshot-file': new_img, + 'snapshot-node-name': 'overlay0', + 'format': iotests.imgfmt} + result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts) + self.assert_qmp(result, 'return', {}) + + def createMirror(self): + opts = {'device': 'drive0', + 'target': new_img, + 'sync': 'top', + 'format': iotests.imgfmt} + result = self.vm.qmp('drive-mirror', conv_keys=False, **opts) + self.assert_qmp(result, 'return', {}) + + def completeBlockJob(self): + result = self.vm.qmp('block-job-complete', device='drive0') + self.assert_qmp(result, 'return', {}) + + def addQuorumDrive(self): + iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M') + drive_0 = {'driver': iotests.imgfmt, + 'node-name': 'node0', + 'file': {'driver': 'file', + 'filename': base_img}} + drive_1 = {'driver': iotests.imgfmt, + 'node-name': 'node1', + 'file': {'driver': 'file', + 'filename': new_img}} + opts = {'driver': 'quorum', + 'id': 'drive0', + 'vote-threshold': 1, + 'children': [ drive_0, drive_1 ]} + result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts) + self.assert_qmp(result, 'return', {}) + + def testNodeWithoutBackend(self): + self.addBlockDev(block_backend = False) + self.delBlockDev(use_node_name = False, expect_error = True) + self.delBlockDev(use_node_name = True) + + def testBlockBackendUsingDeviceName(self): + self.addBlockDev(block_backend = True) + self.delBlockDev(use_node_name = False) + + def testBlockBackendUsingNodeName(self): + self.addBlockDev(block_backend = True) + self.delBlockDev(use_node_name = True) + + def testEject(self): + self.addBlockDev() + self.ejectDrive() + self.delBlockDev() + + def testDeviceModel(self): + self.addBlockDev() + self.addDeviceModel() + self.ejectDrive(expect_error = True) + self.delBlockDev(expect_error = True) + self.delDeviceModel() + self.delBlockDev() + + def testDriveEject(self): + self.addBlockDev() + self.addDeviceModel() + self.delDeviceModel() + self.ejectDrive() + self.delBlockDev(use_node_name = True, expect_error = True) + self.delBlockDev() + + def testSnapshot(self): + self.addBlockDev() + self.createSnapshot() + # This fails because 'node0' is now being used as a backing image + self.delBlockDev(use_node_name = True, expect_error = True) + # This succeeds because the backend now points to the overlay image + self.delBlockDev() + + def testMirror(self): + self.addBlockDev() + self.createMirror() + # The block job prevents removing the device + self.delBlockDev(use_node_name = False, expect_error = True) + self.delBlockDev(use_node_name = True, expect_error = True) + self.completeBlockJob() + # This fails because the mirror operation got rid of 'node0' + self.delBlockDev(use_node_name = True, expect_error = True) + # This succeeds because the backend now points to the new image + self.delBlockDev() + + def testQuorum(self): + self.addQuorumDrive() + # 'node0' is a children of the Quorum device, we cannot remove it + self.delBlockDev(use_node_name = True, expect_error = True) + # 'drive0' is the Quorum device itself + self.delBlockDev(use_node_name = False) + +if __name__ == '__main__': + iotests.main(supported_fmts=["qcow2"]) diff --git a/tests/qemu-iotests/139.out b/tests/qemu-iotests/139.out new file mode 100644 index 0000000..dae404e --- /dev/null +++ b/tests/qemu-iotests/139.out @@ -0,0 +1,5 @@ +......... +---------------------------------------------------------------------- +Ran 9 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 85329af..bf0b6c6 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -137,3 +137,4 @@ 135 rw auto 137 rw auto 138 rw auto quick +139 rw auto quick -- 2.6.1