137ce63ebSStefan Hajnoczi#!/usr/bin/env python 237ce63ebSStefan Hajnoczi# 337ce63ebSStefan Hajnoczi# Tests for image streaming. 437ce63ebSStefan Hajnoczi# 537ce63ebSStefan Hajnoczi# Copyright (C) 2012 IBM Corp. 637ce63ebSStefan Hajnoczi# 737ce63ebSStefan Hajnoczi# This program is free software; you can redistribute it and/or modify 837ce63ebSStefan Hajnoczi# it under the terms of the GNU General Public License as published by 937ce63ebSStefan Hajnoczi# the Free Software Foundation; either version 2 of the License, or 1037ce63ebSStefan Hajnoczi# (at your option) any later version. 1137ce63ebSStefan Hajnoczi# 1237ce63ebSStefan Hajnoczi# This program is distributed in the hope that it will be useful, 1337ce63ebSStefan Hajnoczi# but WITHOUT ANY WARRANTY; without even the implied warranty of 1437ce63ebSStefan Hajnoczi# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1537ce63ebSStefan Hajnoczi# GNU General Public License for more details. 1637ce63ebSStefan Hajnoczi# 1737ce63ebSStefan Hajnoczi# You should have received a copy of the GNU General Public License 1837ce63ebSStefan Hajnoczi# along with this program. If not, see <http://www.gnu.org/licenses/>. 1937ce63ebSStefan Hajnoczi# 2037ce63ebSStefan Hajnoczi 210c817347SPaolo Bonziniimport time 2237ce63ebSStefan Hajnocziimport os 2337ce63ebSStefan Hajnocziimport iotests 2437ce63ebSStefan Hajnoczifrom iotests import qemu_img, qemu_io 2537ce63ebSStefan Hajnoczi 2637ce63ebSStefan Hajnoczibacking_img = os.path.join(iotests.test_dir, 'backing.img') 276e343609SPaolo Bonzinimid_img = os.path.join(iotests.test_dir, 'mid.img') 2837ce63ebSStefan Hajnoczitest_img = os.path.join(iotests.test_dir, 'test.img') 2937ce63ebSStefan Hajnoczi 302499a096SStefan Hajnocziclass TestSingleDrive(iotests.QMPTestCase): 3137ce63ebSStefan Hajnoczi image_len = 1 * 1024 * 1024 # MB 3237ce63ebSStefan Hajnoczi 3337ce63ebSStefan Hajnoczi def setUp(self): 342499a096SStefan Hajnoczi iotests.create_image(backing_img, TestSingleDrive.image_len) 356e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) 366e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) 3790c9b167SKevin Wolf qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img) 385e302a7dSAlberto Garcia qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img) 397b8a9e5aSAlberto Garcia self.vm = iotests.VM().add_drive("blkdebug::" + test_img, "backing.node-name=mid") 4037ce63ebSStefan Hajnoczi self.vm.launch() 4137ce63ebSStefan Hajnoczi 4237ce63ebSStefan Hajnoczi def tearDown(self): 4337ce63ebSStefan Hajnoczi self.vm.shutdown() 4437ce63ebSStefan Hajnoczi os.remove(test_img) 456e343609SPaolo Bonzini os.remove(mid_img) 4637ce63ebSStefan Hajnoczi os.remove(backing_img) 4737ce63ebSStefan Hajnoczi 4837ce63ebSStefan Hajnoczi def test_stream(self): 49ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 5037ce63ebSStefan Hajnoczi 51db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 5237ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 5337ce63ebSStefan Hajnoczi 549974ad40SFam Zheng self.wait_until_completed() 5537ce63ebSStefan Hajnoczi 56ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 57863a5d04SPaolo Bonzini self.vm.shutdown() 5837ce63ebSStefan Hajnoczi 5990c9b167SKevin Wolf self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), 6090c9b167SKevin Wolf qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 61efcc7a23SPaolo Bonzini 'image file map does not match backing file after streaming') 6237ce63ebSStefan Hajnoczi 637b8a9e5aSAlberto Garcia def test_stream_intermediate(self): 647b8a9e5aSAlberto Garcia self.assert_no_active_block_jobs() 657b8a9e5aSAlberto Garcia 667b8a9e5aSAlberto Garcia self.assertNotEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), 677b8a9e5aSAlberto Garcia qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), 687b8a9e5aSAlberto Garcia 'image file map matches backing file before streaming') 697b8a9e5aSAlberto Garcia 707b8a9e5aSAlberto Garcia result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid') 717b8a9e5aSAlberto Garcia self.assert_qmp(result, 'return', {}) 727b8a9e5aSAlberto Garcia 737b8a9e5aSAlberto Garcia self.wait_until_completed(drive='stream-mid') 747b8a9e5aSAlberto Garcia 757b8a9e5aSAlberto Garcia self.assert_no_active_block_jobs() 767b8a9e5aSAlberto Garcia self.vm.shutdown() 777b8a9e5aSAlberto Garcia 787b8a9e5aSAlberto Garcia self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), 797b8a9e5aSAlberto Garcia qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), 807b8a9e5aSAlberto Garcia 'image file map does not match backing file after streaming') 817b8a9e5aSAlberto Garcia 820c817347SPaolo Bonzini def test_stream_pause(self): 83ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 840c817347SPaolo Bonzini 85b59b3d57SFam Zheng self.vm.pause_drive('drive0') 860c817347SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0') 870c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 880c817347SPaolo Bonzini 890c817347SPaolo Bonzini result = self.vm.qmp('block-job-pause', device='drive0') 900c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 910c817347SPaolo Bonzini 920c817347SPaolo Bonzini time.sleep(1) 930c817347SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 940c817347SPaolo Bonzini offset = self.dictpath(result, 'return[0]/offset') 950c817347SPaolo Bonzini 960c817347SPaolo Bonzini time.sleep(1) 970c817347SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 980c817347SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', offset) 990c817347SPaolo Bonzini 1000c817347SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 1010c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1020c817347SPaolo Bonzini 103b59b3d57SFam Zheng self.vm.resume_drive('drive0') 1049974ad40SFam Zheng self.wait_until_completed() 1050c817347SPaolo Bonzini 106ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 1070c817347SPaolo Bonzini self.vm.shutdown() 1080c817347SPaolo Bonzini 10990c9b167SKevin Wolf self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), 11090c9b167SKevin Wolf qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 1110c817347SPaolo Bonzini 'image file map does not match backing file after streaming') 1120c817347SPaolo Bonzini 113409d5498SAlberto Garcia def test_stream_no_op(self): 114409d5498SAlberto Garcia self.assert_no_active_block_jobs() 115409d5498SAlberto Garcia 116409d5498SAlberto Garcia # The image map is empty before the operation 117409d5498SAlberto Garcia empty_map = qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img) 118409d5498SAlberto Garcia 119409d5498SAlberto Garcia # This is a no-op: no data should ever be copied from the base image 120409d5498SAlberto Garcia result = self.vm.qmp('block-stream', device='drive0', base=mid_img) 121409d5498SAlberto Garcia self.assert_qmp(result, 'return', {}) 122409d5498SAlberto Garcia 123409d5498SAlberto Garcia self.wait_until_completed() 124409d5498SAlberto Garcia 125409d5498SAlberto Garcia self.assert_no_active_block_jobs() 126409d5498SAlberto Garcia self.vm.shutdown() 127409d5498SAlberto Garcia 128409d5498SAlberto Garcia self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 129409d5498SAlberto Garcia empty_map, 'image file map changed after a no-op') 130409d5498SAlberto Garcia 1316e343609SPaolo Bonzini def test_stream_partial(self): 132ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 1336e343609SPaolo Bonzini 1345e302a7dSAlberto Garcia result = self.vm.qmp('block-stream', device='drive0', base=backing_img) 1356e343609SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1366e343609SPaolo Bonzini 1379974ad40SFam Zheng self.wait_until_completed() 1386e343609SPaolo Bonzini 139ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 1406e343609SPaolo Bonzini self.vm.shutdown() 1416e343609SPaolo Bonzini 14290c9b167SKevin Wolf self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), 14390c9b167SKevin Wolf qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 1446e343609SPaolo Bonzini 'image file map does not match backing file after streaming') 1456e343609SPaolo Bonzini 14637ce63ebSStefan Hajnoczi def test_device_not_found(self): 147db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='nonexistent') 148b6c1bae5SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 14937ce63ebSStefan Hajnoczi 150774a8850SStefan Hajnoczi 151c1a34322SAlberto Garciaclass TestParallelOps(iotests.QMPTestCase): 152c1a34322SAlberto Garcia num_ops = 4 # Number of parallel block-stream operations 153c1a34322SAlberto Garcia num_imgs = num_ops * 2 + 1 154c1a34322SAlberto Garcia image_len = num_ops * 1024 * 1024 155c1a34322SAlberto Garcia imgs = [] 156c1a34322SAlberto Garcia 157c1a34322SAlberto Garcia def setUp(self): 158c1a34322SAlberto Garcia opts = [] 159c1a34322SAlberto Garcia self.imgs = [] 160c1a34322SAlberto Garcia 161c1a34322SAlberto Garcia # Initialize file names and command-line options 162c1a34322SAlberto Garcia for i in range(self.num_imgs): 163c1a34322SAlberto Garcia img_depth = self.num_imgs - i - 1 164c1a34322SAlberto Garcia opts.append("backing." * img_depth + "node-name=node%d" % i) 165c1a34322SAlberto Garcia self.imgs.append(os.path.join(iotests.test_dir, 'img-%d.img' % i)) 166c1a34322SAlberto Garcia 167c1a34322SAlberto Garcia # Create all images 168c1a34322SAlberto Garcia iotests.create_image(self.imgs[0], self.image_len) 169c1a34322SAlberto Garcia for i in range(1, self.num_imgs): 170c1a34322SAlberto Garcia qemu_img('create', '-f', iotests.imgfmt, 171c1a34322SAlberto Garcia '-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i]) 172c1a34322SAlberto Garcia 173c1a34322SAlberto Garcia # Put data into the images we are copying data from 174c1a34322SAlberto Garcia for i in range(self.num_imgs / 2): 175c1a34322SAlberto Garcia img_index = i * 2 + 1 176c1a34322SAlberto Garcia # Alternate between 512k and 1M. 177c1a34322SAlberto Garcia # This way jobs will not finish in the same order they were created 178c1a34322SAlberto Garcia num_kb = 512 + 512 * (i % 2) 179c1a34322SAlberto Garcia qemu_io('-f', iotests.imgfmt, 180c1a34322SAlberto Garcia '-c', 'write -P %d %d %d' % (i, i*1024*1024, num_kb * 1024), 181c1a34322SAlberto Garcia self.imgs[img_index]) 182c1a34322SAlberto Garcia 183c1a34322SAlberto Garcia # Attach the drive to the VM 184c1a34322SAlberto Garcia self.vm = iotests.VM() 185c1a34322SAlberto Garcia self.vm.add_drive(self.imgs[-1], ','.join(opts)) 186c1a34322SAlberto Garcia self.vm.launch() 187c1a34322SAlberto Garcia 188c1a34322SAlberto Garcia def tearDown(self): 189c1a34322SAlberto Garcia self.vm.shutdown() 190c1a34322SAlberto Garcia for img in self.imgs: 191c1a34322SAlberto Garcia os.remove(img) 192c1a34322SAlberto Garcia 193c1a34322SAlberto Garcia # Test that it's possible to run several block-stream operations 194c1a34322SAlberto Garcia # in parallel in the same snapshot chain 195c1a34322SAlberto Garcia def test_stream_parallel(self): 196c1a34322SAlberto Garcia self.assert_no_active_block_jobs() 197c1a34322SAlberto Garcia 198c1a34322SAlberto Garcia # Check that the maps don't match before the streaming operations 199c1a34322SAlberto Garcia for i in range(2, self.num_imgs, 2): 200c1a34322SAlberto Garcia self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), 201c1a34322SAlberto Garcia qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), 202c1a34322SAlberto Garcia 'image file map matches backing file before streaming') 203c1a34322SAlberto Garcia 204c1a34322SAlberto Garcia # Create all streaming jobs 205c1a34322SAlberto Garcia pending_jobs = [] 206c1a34322SAlberto Garcia for i in range(2, self.num_imgs, 2): 207c1a34322SAlberto Garcia node_name = 'node%d' % i 208c1a34322SAlberto Garcia job_id = 'stream-%s' % node_name 209c1a34322SAlberto Garcia pending_jobs.append(job_id) 210c1a34322SAlberto Garcia result = self.vm.qmp('block-stream', device=node_name, job_id=job_id, base=self.imgs[i-2], speed=512*1024) 211c1a34322SAlberto Garcia self.assert_qmp(result, 'return', {}) 212c1a34322SAlberto Garcia 213c1a34322SAlberto Garcia # Wait for all jobs to be finished. 214c1a34322SAlberto Garcia while len(pending_jobs) > 0: 215c1a34322SAlberto Garcia for event in self.vm.get_qmp_events(wait=True): 216c1a34322SAlberto Garcia if event['event'] == 'BLOCK_JOB_COMPLETED': 217c1a34322SAlberto Garcia job_id = self.dictpath(event, 'data/device') 218c1a34322SAlberto Garcia self.assertTrue(job_id in pending_jobs) 219c1a34322SAlberto Garcia self.assert_qmp_absent(event, 'data/error') 220c1a34322SAlberto Garcia pending_jobs.remove(job_id) 221c1a34322SAlberto Garcia 222c1a34322SAlberto Garcia self.assert_no_active_block_jobs() 223c1a34322SAlberto Garcia self.vm.shutdown() 224c1a34322SAlberto Garcia 225c1a34322SAlberto Garcia # Check that all maps match now 226c1a34322SAlberto Garcia for i in range(2, self.num_imgs, 2): 227c1a34322SAlberto Garcia self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), 228c1a34322SAlberto Garcia qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), 229c1a34322SAlberto Garcia 'image file map does not match backing file after streaming') 230c1a34322SAlberto Garcia 231*eb290b78SAlberto Garcia # Test that it's not possible to perform two block-stream 232*eb290b78SAlberto Garcia # operations if there are nodes involved in both. 233*eb290b78SAlberto Garcia def test_overlapping_1(self): 234*eb290b78SAlberto Garcia self.assert_no_active_block_jobs() 235*eb290b78SAlberto Garcia 236*eb290b78SAlberto Garcia # Set a speed limit to make sure that this job blocks the rest 237*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node4', job_id='stream-node4', base=self.imgs[1], speed=1024*1024) 238*eb290b78SAlberto Garcia self.assert_qmp(result, 'return', {}) 239*eb290b78SAlberto Garcia 240*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node5', job_id='stream-node5', base=self.imgs[2]) 241*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 242*eb290b78SAlberto Garcia 243*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node3', job_id='stream-node3', base=self.imgs[2]) 244*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 245*eb290b78SAlberto Garcia 246*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node4', job_id='stream-node4-v2') 247*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 248*eb290b78SAlberto Garcia 249*eb290b78SAlberto Garcia # block-commit should also fail if it touches nodes used by the stream job 250*eb290b78SAlberto Garcia result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[4], job_id='commit-node4') 251*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 252*eb290b78SAlberto Garcia 253*eb290b78SAlberto Garcia result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[1], top=self.imgs[3], job_id='commit-node1') 254*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 255*eb290b78SAlberto Garcia 256*eb290b78SAlberto Garcia # This fails because it needs to modify the backing string in node2, which is blocked 257*eb290b78SAlberto Garcia result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[0], top=self.imgs[1], job_id='commit-node0') 258*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 259*eb290b78SAlberto Garcia 260*eb290b78SAlberto Garcia self.wait_until_completed(drive='stream-node4') 261*eb290b78SAlberto Garcia self.assert_no_active_block_jobs() 262*eb290b78SAlberto Garcia 263*eb290b78SAlberto Garcia # Similar to test_overlapping_1, but with block-commit 264*eb290b78SAlberto Garcia # blocking the other jobs 265*eb290b78SAlberto Garcia def test_overlapping_2(self): 266*eb290b78SAlberto Garcia self.assertLessEqual(9, self.num_imgs) 267*eb290b78SAlberto Garcia self.assert_no_active_block_jobs() 268*eb290b78SAlberto Garcia 269*eb290b78SAlberto Garcia # Set a speed limit to make sure that this job blocks the rest 270*eb290b78SAlberto Garcia result = self.vm.qmp('block-commit', device='drive0', top=self.imgs[5], base=self.imgs[3], job_id='commit-node3', speed=1024*1024) 271*eb290b78SAlberto Garcia self.assert_qmp(result, 'return', {}) 272*eb290b78SAlberto Garcia 273*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node3', job_id='stream-node3') 274*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 275*eb290b78SAlberto Garcia 276*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node6', base=self.imgs[2], job_id='stream-node6') 277*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 278*eb290b78SAlberto Garcia 279*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node4', base=self.imgs[2], job_id='stream-node4') 280*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 281*eb290b78SAlberto Garcia 282*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node6', base=self.imgs[4], job_id='stream-node6-v2') 283*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 284*eb290b78SAlberto Garcia 285*eb290b78SAlberto Garcia # This fails because block-commit needs to block node6, the overlay of the 'top' image 286*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node7', base=self.imgs[5], job_id='stream-node6-v3') 287*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 288*eb290b78SAlberto Garcia 289*eb290b78SAlberto Garcia # This fails because block-commit currently blocks the active layer even if it's not used 290*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0') 291*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 292*eb290b78SAlberto Garcia 293*eb290b78SAlberto Garcia self.wait_until_completed(drive='commit-node3') 294*eb290b78SAlberto Garcia 295*eb290b78SAlberto Garcia # Similar to test_overlapping_2, but here block-commit doesn't use the 'top' parameter. 296*eb290b78SAlberto Garcia # Internally this uses a mirror block job, hence the separate test case. 297*eb290b78SAlberto Garcia def test_overlapping_3(self): 298*eb290b78SAlberto Garcia self.assertLessEqual(8, self.num_imgs) 299*eb290b78SAlberto Garcia self.assert_no_active_block_jobs() 300*eb290b78SAlberto Garcia 301*eb290b78SAlberto Garcia # Set a speed limit to make sure that this job blocks the rest 302*eb290b78SAlberto Garcia result = self.vm.qmp('block-commit', device='drive0', base=self.imgs[3], job_id='commit-drive0', speed=1024*1024) 303*eb290b78SAlberto Garcia self.assert_qmp(result, 'return', {}) 304*eb290b78SAlberto Garcia 305*eb290b78SAlberto Garcia result = self.vm.qmp('block-stream', device='node5', base=self.imgs[3], job_id='stream-node6') 306*eb290b78SAlberto Garcia self.assert_qmp(result, 'error/class', 'GenericError') 307*eb290b78SAlberto Garcia 308*eb290b78SAlberto Garcia event = self.vm.get_qmp_event(wait=True) 309*eb290b78SAlberto Garcia self.assertEqual(event['event'], 'BLOCK_JOB_READY') 310*eb290b78SAlberto Garcia self.assert_qmp(event, 'data/device', 'commit-drive0') 311*eb290b78SAlberto Garcia self.assert_qmp(event, 'data/type', 'commit') 312*eb290b78SAlberto Garcia self.assert_qmp_absent(event, 'data/error') 313*eb290b78SAlberto Garcia 314*eb290b78SAlberto Garcia result = self.vm.qmp('block-job-complete', device='commit-drive0') 315*eb290b78SAlberto Garcia self.assert_qmp(result, 'return', {}) 316*eb290b78SAlberto Garcia 317*eb290b78SAlberto Garcia self.wait_until_completed(drive='commit-drive0') 318*eb290b78SAlberto Garcia self.assert_no_active_block_jobs() 319*eb290b78SAlberto Garcia 3202499a096SStefan Hajnocziclass TestSmallerBackingFile(iotests.QMPTestCase): 321774a8850SStefan Hajnoczi backing_len = 1 * 1024 * 1024 # MB 322774a8850SStefan Hajnoczi image_len = 2 * backing_len 323774a8850SStefan Hajnoczi 324774a8850SStefan Hajnoczi def setUp(self): 3252499a096SStefan Hajnoczi iotests.create_image(backing_img, self.backing_len) 326774a8850SStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) 327774a8850SStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 328774a8850SStefan Hajnoczi self.vm.launch() 329774a8850SStefan Hajnoczi 330774a8850SStefan Hajnoczi # If this hangs, then you are missing a fix to complete streaming when the 331774a8850SStefan Hajnoczi # end of the backing file is reached. 332774a8850SStefan Hajnoczi def test_stream(self): 333ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 334774a8850SStefan Hajnoczi 335774a8850SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 336774a8850SStefan Hajnoczi self.assert_qmp(result, 'return', {}) 337774a8850SStefan Hajnoczi 3389974ad40SFam Zheng self.wait_until_completed() 339774a8850SStefan Hajnoczi 340ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 341774a8850SStefan Hajnoczi self.vm.shutdown() 342774a8850SStefan Hajnoczi 3432499a096SStefan Hajnocziclass TestErrors(iotests.QMPTestCase): 34490f0b711SPaolo Bonzini image_len = 2 * 1024 * 1024 # MB 34590f0b711SPaolo Bonzini 34690f0b711SPaolo Bonzini # this should match STREAM_BUFFER_SIZE/512 in block/stream.c 34790f0b711SPaolo Bonzini STREAM_BUFFER_SIZE = 512 * 1024 34890f0b711SPaolo Bonzini 34990f0b711SPaolo Bonzini def create_blkdebug_file(self, name, event, errno): 35090f0b711SPaolo Bonzini file = open(name, 'w') 35190f0b711SPaolo Bonzini file.write(''' 35290f0b711SPaolo Bonzini[inject-error] 35390f0b711SPaolo Bonzinistate = "1" 35490f0b711SPaolo Bonzinievent = "%s" 35590f0b711SPaolo Bonzinierrno = "%d" 35690f0b711SPaolo Bonziniimmediately = "off" 35790f0b711SPaolo Bonzinionce = "on" 35890f0b711SPaolo Bonzinisector = "%d" 35990f0b711SPaolo Bonzini 36090f0b711SPaolo Bonzini[set-state] 36190f0b711SPaolo Bonzinistate = "1" 36290f0b711SPaolo Bonzinievent = "%s" 36390f0b711SPaolo Bonzininew_state = "2" 36490f0b711SPaolo Bonzini 36590f0b711SPaolo Bonzini[set-state] 36690f0b711SPaolo Bonzinistate = "2" 36790f0b711SPaolo Bonzinievent = "%s" 36890f0b711SPaolo Bonzininew_state = "1" 36990f0b711SPaolo Bonzini''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event)) 37090f0b711SPaolo Bonzini file.close() 37190f0b711SPaolo Bonzini 37290f0b711SPaolo Bonziniclass TestEIO(TestErrors): 37390f0b711SPaolo Bonzini def setUp(self): 37490f0b711SPaolo Bonzini self.blkdebug_file = backing_img + ".blkdebug" 3752499a096SStefan Hajnoczi iotests.create_image(backing_img, TestErrors.image_len) 37690f0b711SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) 37790f0b711SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, 37890f0b711SPaolo Bonzini '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 37990f0b711SPaolo Bonzini % (self.blkdebug_file, backing_img), 38090f0b711SPaolo Bonzini test_img) 38190f0b711SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 38290f0b711SPaolo Bonzini self.vm.launch() 38390f0b711SPaolo Bonzini 38490f0b711SPaolo Bonzini def tearDown(self): 38590f0b711SPaolo Bonzini self.vm.shutdown() 38690f0b711SPaolo Bonzini os.remove(test_img) 38790f0b711SPaolo Bonzini os.remove(backing_img) 38890f0b711SPaolo Bonzini os.remove(self.blkdebug_file) 38990f0b711SPaolo Bonzini 39090f0b711SPaolo Bonzini def test_report(self): 391ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 39290f0b711SPaolo Bonzini 39390f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0') 39490f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 39590f0b711SPaolo Bonzini 39690f0b711SPaolo Bonzini completed = False 39790f0b711SPaolo Bonzini error = False 39890f0b711SPaolo Bonzini while not completed: 39990f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 40090f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 40190f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 40290f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 40390f0b711SPaolo Bonzini error = True 40490f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 40590f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 40690f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 40790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 40890f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 40990f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) 41090f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 41190f0b711SPaolo Bonzini completed = True 41290f0b711SPaolo Bonzini 413ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 41490f0b711SPaolo Bonzini self.vm.shutdown() 41590f0b711SPaolo Bonzini 41690f0b711SPaolo Bonzini def test_ignore(self): 417ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 41890f0b711SPaolo Bonzini 41990f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='ignore') 42090f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 42190f0b711SPaolo Bonzini 42290f0b711SPaolo Bonzini error = False 42390f0b711SPaolo Bonzini completed = False 42490f0b711SPaolo Bonzini while not completed: 42590f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 42690f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 42790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 42890f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 42990f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 43090f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 43190f0b711SPaolo Bonzini error = True 43290f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 43390f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 43490f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 43590f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 43690f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 43790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 43890f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 43990f0b711SPaolo Bonzini completed = True 44090f0b711SPaolo Bonzini 441ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 44290f0b711SPaolo Bonzini self.vm.shutdown() 44390f0b711SPaolo Bonzini 44490f0b711SPaolo Bonzini def test_stop(self): 445ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 44690f0b711SPaolo Bonzini 44790f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='stop') 44890f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 44990f0b711SPaolo Bonzini 45090f0b711SPaolo Bonzini error = False 45190f0b711SPaolo Bonzini completed = False 45290f0b711SPaolo Bonzini while not completed: 45390f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 45490f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 45501809194SJohn Snow error = True 45690f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 45790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 45890f0b711SPaolo Bonzini 45990f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 46090f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 46190f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) 46290f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'failed') 46390f0b711SPaolo Bonzini 46490f0b711SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 46590f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 46690f0b711SPaolo Bonzini 46790f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 46801809194SJohn Snow if result == {'return': []}: 46901809194SJohn Snow # Race; likely already finished. Check. 47001809194SJohn Snow continue 47190f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 47290f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 47390f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 47490f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 47590f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 47690f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 47790f0b711SPaolo Bonzini self.assert_qmp_absent(event, 'data/error') 47890f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 47990f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 48090f0b711SPaolo Bonzini completed = True 48190f0b711SPaolo Bonzini 482ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 48390f0b711SPaolo Bonzini self.vm.shutdown() 48490f0b711SPaolo Bonzini 48590f0b711SPaolo Bonzini def test_enospc(self): 486ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 48790f0b711SPaolo Bonzini 48890f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') 48990f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 49090f0b711SPaolo Bonzini 49190f0b711SPaolo Bonzini completed = False 49290f0b711SPaolo Bonzini error = False 49390f0b711SPaolo Bonzini while not completed: 49490f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 49590f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 49690f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 49790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 49890f0b711SPaolo Bonzini error = True 49990f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 50090f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 50190f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 50290f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 50390f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 50490f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) 50590f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 50690f0b711SPaolo Bonzini completed = True 50790f0b711SPaolo Bonzini 508ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 50990f0b711SPaolo Bonzini self.vm.shutdown() 51090f0b711SPaolo Bonzini 51190f0b711SPaolo Bonziniclass TestENOSPC(TestErrors): 51290f0b711SPaolo Bonzini def setUp(self): 51390f0b711SPaolo Bonzini self.blkdebug_file = backing_img + ".blkdebug" 5142499a096SStefan Hajnoczi iotests.create_image(backing_img, TestErrors.image_len) 51590f0b711SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28) 51690f0b711SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, 51790f0b711SPaolo Bonzini '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 51890f0b711SPaolo Bonzini % (self.blkdebug_file, backing_img), 51990f0b711SPaolo Bonzini test_img) 52090f0b711SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 52190f0b711SPaolo Bonzini self.vm.launch() 52290f0b711SPaolo Bonzini 52390f0b711SPaolo Bonzini def tearDown(self): 52490f0b711SPaolo Bonzini self.vm.shutdown() 52590f0b711SPaolo Bonzini os.remove(test_img) 52690f0b711SPaolo Bonzini os.remove(backing_img) 52790f0b711SPaolo Bonzini os.remove(self.blkdebug_file) 52890f0b711SPaolo Bonzini 52990f0b711SPaolo Bonzini def test_enospc(self): 530ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 53190f0b711SPaolo Bonzini 53290f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') 53390f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 53490f0b711SPaolo Bonzini 53590f0b711SPaolo Bonzini error = False 53690f0b711SPaolo Bonzini completed = False 53790f0b711SPaolo Bonzini while not completed: 53890f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 53990f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 54090f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 54190f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 54290f0b711SPaolo Bonzini 54390f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 54490f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 54590f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) 54690f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'nospace') 54790f0b711SPaolo Bonzini 54890f0b711SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 54990f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 55090f0b711SPaolo Bonzini 55190f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 55290f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 55390f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 55490f0b711SPaolo Bonzini error = True 55590f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 55690f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 55790f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 55890f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 55990f0b711SPaolo Bonzini self.assert_qmp_absent(event, 'data/error') 56090f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 56190f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 56290f0b711SPaolo Bonzini completed = True 56390f0b711SPaolo Bonzini 564ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 56590f0b711SPaolo Bonzini self.vm.shutdown() 566774a8850SStefan Hajnoczi 5672499a096SStefan Hajnocziclass TestStreamStop(iotests.QMPTestCase): 56837ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 56937ce63ebSStefan Hajnoczi 57037ce63ebSStefan Hajnoczi def setUp(self): 57137ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 57290c9b167SKevin Wolf qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) 57337ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 57490c9b167SKevin Wolf qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) 575b59b3d57SFam Zheng self.vm = iotests.VM().add_drive("blkdebug::" + test_img) 57637ce63ebSStefan Hajnoczi self.vm.launch() 57737ce63ebSStefan Hajnoczi 57837ce63ebSStefan Hajnoczi def tearDown(self): 57937ce63ebSStefan Hajnoczi self.vm.shutdown() 58037ce63ebSStefan Hajnoczi os.remove(test_img) 58137ce63ebSStefan Hajnoczi os.remove(backing_img) 58237ce63ebSStefan Hajnoczi 58337ce63ebSStefan Hajnoczi def test_stream_stop(self): 584ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 58537ce63ebSStefan Hajnoczi 586b59b3d57SFam Zheng self.vm.pause_drive('drive0') 587db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 58837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 58937ce63ebSStefan Hajnoczi 5900fd05e8dSPaolo Bonzini time.sleep(0.1) 59137ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 59237ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 59337ce63ebSStefan Hajnoczi 594b59b3d57SFam Zheng self.cancel_and_wait(resume=True) 59537ce63ebSStefan Hajnoczi 5962499a096SStefan Hajnocziclass TestSetSpeed(iotests.QMPTestCase): 59737ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 59837ce63ebSStefan Hajnoczi 59937ce63ebSStefan Hajnoczi def setUp(self): 60037ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 60190c9b167SKevin Wolf qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 32M', backing_img) 60237ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 60390c9b167SKevin Wolf qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 32M 32M', test_img) 604b59b3d57SFam Zheng self.vm = iotests.VM().add_drive('blkdebug::' + test_img) 60537ce63ebSStefan Hajnoczi self.vm.launch() 60637ce63ebSStefan Hajnoczi 60737ce63ebSStefan Hajnoczi def tearDown(self): 60837ce63ebSStefan Hajnoczi self.vm.shutdown() 60937ce63ebSStefan Hajnoczi os.remove(test_img) 61037ce63ebSStefan Hajnoczi os.remove(backing_img) 61137ce63ebSStefan Hajnoczi 612e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 613e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 614e425306aSStefan Hajnoczi def perf_test_throughput(self): 615ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 61637ce63ebSStefan Hajnoczi 617db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 61837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 61937ce63ebSStefan Hajnoczi 620e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 62137ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 62237ce63ebSStefan Hajnoczi 6239974ad40SFam Zheng self.wait_until_completed() 62437ce63ebSStefan Hajnoczi 625ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 62637ce63ebSStefan Hajnoczi 627e425306aSStefan Hajnoczi def test_set_speed(self): 628ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 629e425306aSStefan Hajnoczi 630b59b3d57SFam Zheng self.vm.pause_drive('drive0') 631e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 632e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 633e425306aSStefan Hajnoczi 634e425306aSStefan Hajnoczi # Default speed is 0 635e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 636e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 637e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 638e425306aSStefan Hajnoczi 639e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 640e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 641e425306aSStefan Hajnoczi 642e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 643e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 644e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 645e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 646e425306aSStefan Hajnoczi 647b59b3d57SFam Zheng self.cancel_and_wait(resume=True) 648b59b3d57SFam Zheng self.vm.pause_drive('drive0') 649e425306aSStefan Hajnoczi 650e425306aSStefan Hajnoczi # Check setting speed in block-stream works 651e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 652e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 653e425306aSStefan Hajnoczi 654e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 655e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 656e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 657e425306aSStefan Hajnoczi 658b59b3d57SFam Zheng self.cancel_and_wait(resume=True) 659e425306aSStefan Hajnoczi 660e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 661ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 662e425306aSStefan Hajnoczi 663e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 66458c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 665e425306aSStefan Hajnoczi 666ecc1c88eSStefan Hajnoczi self.assert_no_active_block_jobs() 667e425306aSStefan Hajnoczi 668e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 669e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 670e425306aSStefan Hajnoczi 671e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 67258c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 673e425306aSStefan Hajnoczi 674e425306aSStefan Hajnoczi self.cancel_and_wait() 675e425306aSStefan Hajnoczi 67637ce63ebSStefan Hajnocziif __name__ == '__main__': 67737ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 678