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 25ab68cdfaSPaolo Bonziniimport struct 2637ce63ebSStefan Hajnoczi 2737ce63ebSStefan Hajnoczibacking_img = os.path.join(iotests.test_dir, 'backing.img') 286e343609SPaolo Bonzinimid_img = os.path.join(iotests.test_dir, 'mid.img') 2937ce63ebSStefan Hajnoczitest_img = os.path.join(iotests.test_dir, 'test.img') 3037ce63ebSStefan Hajnoczi 3137ce63ebSStefan Hajnocziclass ImageStreamingTestCase(iotests.QMPTestCase): 3237ce63ebSStefan Hajnoczi '''Abstract base class for image streaming test cases''' 3337ce63ebSStefan Hajnoczi 3437ce63ebSStefan Hajnoczi def assert_no_active_streams(self): 3537ce63ebSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 3637ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', []) 3737ce63ebSStefan Hajnoczi 38e425306aSStefan Hajnoczi def cancel_and_wait(self, drive='drive0'): 39e425306aSStefan Hajnoczi '''Cancel a block job and wait for it to finish''' 40e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-cancel', device=drive) 41e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 42e425306aSStefan Hajnoczi 43e425306aSStefan Hajnoczi cancelled = False 44e425306aSStefan Hajnoczi while not cancelled: 45e425306aSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 46e425306aSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_CANCELLED': 47e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 48e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/device', drive) 49e425306aSStefan Hajnoczi cancelled = True 50e425306aSStefan Hajnoczi 51e425306aSStefan Hajnoczi self.assert_no_active_streams() 52e425306aSStefan Hajnoczi 53ab68cdfaSPaolo Bonzini def create_image(self, name, size): 54ab68cdfaSPaolo Bonzini file = open(name, 'w') 55ab68cdfaSPaolo Bonzini i = 0 56ab68cdfaSPaolo Bonzini while i < size: 57ab68cdfaSPaolo Bonzini sector = struct.pack('>l504xl', i / 512, i / 512) 58ab68cdfaSPaolo Bonzini file.write(sector) 59ab68cdfaSPaolo Bonzini i = i + 512 60ab68cdfaSPaolo Bonzini file.close() 61ab68cdfaSPaolo Bonzini 62ab68cdfaSPaolo Bonzini 6337ce63ebSStefan Hajnocziclass TestSingleDrive(ImageStreamingTestCase): 6437ce63ebSStefan Hajnoczi image_len = 1 * 1024 * 1024 # MB 6537ce63ebSStefan Hajnoczi 6637ce63ebSStefan Hajnoczi def setUp(self): 67ab68cdfaSPaolo Bonzini self.create_image(backing_img, TestSingleDrive.image_len) 686e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) 696e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) 7037ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 7137ce63ebSStefan Hajnoczi self.vm.launch() 7237ce63ebSStefan Hajnoczi 7337ce63ebSStefan Hajnoczi def tearDown(self): 7437ce63ebSStefan Hajnoczi self.vm.shutdown() 7537ce63ebSStefan Hajnoczi os.remove(test_img) 766e343609SPaolo Bonzini os.remove(mid_img) 7737ce63ebSStefan Hajnoczi os.remove(backing_img) 7837ce63ebSStefan Hajnoczi 7937ce63ebSStefan Hajnoczi def test_stream(self): 8037ce63ebSStefan Hajnoczi self.assert_no_active_streams() 8137ce63ebSStefan Hajnoczi 82db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 8337ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 8437ce63ebSStefan Hajnoczi 8537ce63ebSStefan Hajnoczi completed = False 8637ce63ebSStefan Hajnoczi while not completed: 8737ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 8837ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 8937ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 9037ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 9137ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 9237ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 9337ce63ebSStefan Hajnoczi completed = True 9437ce63ebSStefan Hajnoczi 9537ce63ebSStefan Hajnoczi self.assert_no_active_streams() 96863a5d04SPaolo Bonzini self.vm.shutdown() 9737ce63ebSStefan Hajnoczi 98efcc7a23SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', backing_img), 99efcc7a23SPaolo Bonzini qemu_io('-c', 'map', test_img), 100efcc7a23SPaolo Bonzini 'image file map does not match backing file after streaming') 10137ce63ebSStefan Hajnoczi 1020c817347SPaolo Bonzini def test_stream_pause(self): 1030c817347SPaolo Bonzini self.assert_no_active_streams() 1040c817347SPaolo Bonzini 1050c817347SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0') 1060c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1070c817347SPaolo Bonzini 1080c817347SPaolo Bonzini result = self.vm.qmp('block-job-pause', device='drive0') 1090c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1100c817347SPaolo Bonzini 1110c817347SPaolo Bonzini time.sleep(1) 1120c817347SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 1130c817347SPaolo Bonzini offset = self.dictpath(result, 'return[0]/offset') 1140c817347SPaolo Bonzini 1150c817347SPaolo Bonzini time.sleep(1) 1160c817347SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 1170c817347SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', offset) 1180c817347SPaolo Bonzini 1190c817347SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 1200c817347SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1210c817347SPaolo Bonzini 1220c817347SPaolo Bonzini completed = False 1230c817347SPaolo Bonzini while not completed: 1240c817347SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 1250c817347SPaolo Bonzini if event['event'] == 'BLOCK_JOB_COMPLETED': 1260c817347SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 1270c817347SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 1280c817347SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 1290c817347SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 1300c817347SPaolo Bonzini completed = True 1310c817347SPaolo Bonzini 1320c817347SPaolo Bonzini self.assert_no_active_streams() 1330c817347SPaolo Bonzini self.vm.shutdown() 1340c817347SPaolo Bonzini 1350c817347SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', backing_img), 1360c817347SPaolo Bonzini qemu_io('-c', 'map', test_img), 1370c817347SPaolo Bonzini 'image file map does not match backing file after streaming') 1380c817347SPaolo Bonzini 1396e343609SPaolo Bonzini def test_stream_partial(self): 1406e343609SPaolo Bonzini self.assert_no_active_streams() 1416e343609SPaolo Bonzini 1426e343609SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', base=mid_img) 1436e343609SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1446e343609SPaolo Bonzini 1456e343609SPaolo Bonzini completed = False 1466e343609SPaolo Bonzini while not completed: 1476e343609SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 1486e343609SPaolo Bonzini if event['event'] == 'BLOCK_JOB_COMPLETED': 1496e343609SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 1506e343609SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 1516e343609SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 1526e343609SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 1536e343609SPaolo Bonzini completed = True 1546e343609SPaolo Bonzini 1556e343609SPaolo Bonzini self.assert_no_active_streams() 1566e343609SPaolo Bonzini self.vm.shutdown() 1576e343609SPaolo Bonzini 1586e343609SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', mid_img), 1596e343609SPaolo Bonzini qemu_io('-c', 'map', test_img), 1606e343609SPaolo Bonzini 'image file map does not match backing file after streaming') 1616e343609SPaolo Bonzini 16237ce63ebSStefan Hajnoczi def test_device_not_found(self): 163db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='nonexistent') 16437ce63ebSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'DeviceNotFound') 16537ce63ebSStefan Hajnoczi 166774a8850SStefan Hajnoczi 167774a8850SStefan Hajnocziclass TestSmallerBackingFile(ImageStreamingTestCase): 168774a8850SStefan Hajnoczi backing_len = 1 * 1024 * 1024 # MB 169774a8850SStefan Hajnoczi image_len = 2 * backing_len 170774a8850SStefan Hajnoczi 171774a8850SStefan Hajnoczi def setUp(self): 172774a8850SStefan Hajnoczi self.create_image(backing_img, self.backing_len) 173774a8850SStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) 174774a8850SStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 175774a8850SStefan Hajnoczi self.vm.launch() 176774a8850SStefan Hajnoczi 177774a8850SStefan Hajnoczi # If this hangs, then you are missing a fix to complete streaming when the 178774a8850SStefan Hajnoczi # end of the backing file is reached. 179774a8850SStefan Hajnoczi def test_stream(self): 180774a8850SStefan Hajnoczi self.assert_no_active_streams() 181774a8850SStefan Hajnoczi 182774a8850SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 183774a8850SStefan Hajnoczi self.assert_qmp(result, 'return', {}) 184774a8850SStefan Hajnoczi 185774a8850SStefan Hajnoczi completed = False 186774a8850SStefan Hajnoczi while not completed: 187774a8850SStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 188774a8850SStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 189774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 190774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 191774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 192774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 193774a8850SStefan Hajnoczi completed = True 194774a8850SStefan Hajnoczi 195774a8850SStefan Hajnoczi self.assert_no_active_streams() 196774a8850SStefan Hajnoczi self.vm.shutdown() 197774a8850SStefan Hajnoczi 198*90f0b711SPaolo Bonziniclass TestErrors(ImageStreamingTestCase): 199*90f0b711SPaolo Bonzini image_len = 2 * 1024 * 1024 # MB 200*90f0b711SPaolo Bonzini 201*90f0b711SPaolo Bonzini # this should match STREAM_BUFFER_SIZE/512 in block/stream.c 202*90f0b711SPaolo Bonzini STREAM_BUFFER_SIZE = 512 * 1024 203*90f0b711SPaolo Bonzini 204*90f0b711SPaolo Bonzini def create_blkdebug_file(self, name, event, errno): 205*90f0b711SPaolo Bonzini file = open(name, 'w') 206*90f0b711SPaolo Bonzini file.write(''' 207*90f0b711SPaolo Bonzini[inject-error] 208*90f0b711SPaolo Bonzinistate = "1" 209*90f0b711SPaolo Bonzinievent = "%s" 210*90f0b711SPaolo Bonzinierrno = "%d" 211*90f0b711SPaolo Bonziniimmediately = "off" 212*90f0b711SPaolo Bonzinionce = "on" 213*90f0b711SPaolo Bonzinisector = "%d" 214*90f0b711SPaolo Bonzini 215*90f0b711SPaolo Bonzini[set-state] 216*90f0b711SPaolo Bonzinistate = "1" 217*90f0b711SPaolo Bonzinievent = "%s" 218*90f0b711SPaolo Bonzininew_state = "2" 219*90f0b711SPaolo Bonzini 220*90f0b711SPaolo Bonzini[set-state] 221*90f0b711SPaolo Bonzinistate = "2" 222*90f0b711SPaolo Bonzinievent = "%s" 223*90f0b711SPaolo Bonzininew_state = "1" 224*90f0b711SPaolo Bonzini''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event)) 225*90f0b711SPaolo Bonzini file.close() 226*90f0b711SPaolo Bonzini 227*90f0b711SPaolo Bonziniclass TestEIO(TestErrors): 228*90f0b711SPaolo Bonzini def setUp(self): 229*90f0b711SPaolo Bonzini self.blkdebug_file = backing_img + ".blkdebug" 230*90f0b711SPaolo Bonzini self.create_image(backing_img, TestErrors.image_len) 231*90f0b711SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) 232*90f0b711SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, 233*90f0b711SPaolo Bonzini '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 234*90f0b711SPaolo Bonzini % (self.blkdebug_file, backing_img), 235*90f0b711SPaolo Bonzini test_img) 236*90f0b711SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 237*90f0b711SPaolo Bonzini self.vm.launch() 238*90f0b711SPaolo Bonzini 239*90f0b711SPaolo Bonzini def tearDown(self): 240*90f0b711SPaolo Bonzini self.vm.shutdown() 241*90f0b711SPaolo Bonzini os.remove(test_img) 242*90f0b711SPaolo Bonzini os.remove(backing_img) 243*90f0b711SPaolo Bonzini os.remove(self.blkdebug_file) 244*90f0b711SPaolo Bonzini 245*90f0b711SPaolo Bonzini def test_report(self): 246*90f0b711SPaolo Bonzini self.assert_no_active_streams() 247*90f0b711SPaolo Bonzini 248*90f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0') 249*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 250*90f0b711SPaolo Bonzini 251*90f0b711SPaolo Bonzini completed = False 252*90f0b711SPaolo Bonzini error = False 253*90f0b711SPaolo Bonzini while not completed: 254*90f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 255*90f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 256*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 257*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 258*90f0b711SPaolo Bonzini error = True 259*90f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 260*90f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 261*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 262*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 263*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 264*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) 265*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 266*90f0b711SPaolo Bonzini completed = True 267*90f0b711SPaolo Bonzini 268*90f0b711SPaolo Bonzini self.assert_no_active_streams() 269*90f0b711SPaolo Bonzini self.vm.shutdown() 270*90f0b711SPaolo Bonzini 271*90f0b711SPaolo Bonzini def test_ignore(self): 272*90f0b711SPaolo Bonzini self.assert_no_active_streams() 273*90f0b711SPaolo Bonzini 274*90f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='ignore') 275*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 276*90f0b711SPaolo Bonzini 277*90f0b711SPaolo Bonzini error = False 278*90f0b711SPaolo Bonzini completed = False 279*90f0b711SPaolo Bonzini while not completed: 280*90f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 281*90f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 282*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 283*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 284*90f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 285*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 286*90f0b711SPaolo Bonzini error = True 287*90f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 288*90f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 289*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 290*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 291*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 292*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 293*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 294*90f0b711SPaolo Bonzini completed = True 295*90f0b711SPaolo Bonzini 296*90f0b711SPaolo Bonzini self.assert_no_active_streams() 297*90f0b711SPaolo Bonzini self.vm.shutdown() 298*90f0b711SPaolo Bonzini 299*90f0b711SPaolo Bonzini def test_stop(self): 300*90f0b711SPaolo Bonzini self.assert_no_active_streams() 301*90f0b711SPaolo Bonzini 302*90f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='stop') 303*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 304*90f0b711SPaolo Bonzini 305*90f0b711SPaolo Bonzini error = False 306*90f0b711SPaolo Bonzini completed = False 307*90f0b711SPaolo Bonzini while not completed: 308*90f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 309*90f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 310*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 311*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 312*90f0b711SPaolo Bonzini 313*90f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 314*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 315*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) 316*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'failed') 317*90f0b711SPaolo Bonzini 318*90f0b711SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 319*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 320*90f0b711SPaolo Bonzini 321*90f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 322*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 323*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 324*90f0b711SPaolo Bonzini error = True 325*90f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 326*90f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 327*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 328*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 329*90f0b711SPaolo Bonzini self.assert_qmp_absent(event, 'data/error') 330*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 331*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 332*90f0b711SPaolo Bonzini completed = True 333*90f0b711SPaolo Bonzini 334*90f0b711SPaolo Bonzini self.assert_no_active_streams() 335*90f0b711SPaolo Bonzini self.vm.shutdown() 336*90f0b711SPaolo Bonzini 337*90f0b711SPaolo Bonzini def test_enospc(self): 338*90f0b711SPaolo Bonzini self.assert_no_active_streams() 339*90f0b711SPaolo Bonzini 340*90f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') 341*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 342*90f0b711SPaolo Bonzini 343*90f0b711SPaolo Bonzini completed = False 344*90f0b711SPaolo Bonzini error = False 345*90f0b711SPaolo Bonzini while not completed: 346*90f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 347*90f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 348*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 349*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 350*90f0b711SPaolo Bonzini error = True 351*90f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 352*90f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 353*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 354*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 355*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/error', 'Input/output error') 356*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) 357*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 358*90f0b711SPaolo Bonzini completed = True 359*90f0b711SPaolo Bonzini 360*90f0b711SPaolo Bonzini self.assert_no_active_streams() 361*90f0b711SPaolo Bonzini self.vm.shutdown() 362*90f0b711SPaolo Bonzini 363*90f0b711SPaolo Bonziniclass TestENOSPC(TestErrors): 364*90f0b711SPaolo Bonzini def setUp(self): 365*90f0b711SPaolo Bonzini self.blkdebug_file = backing_img + ".blkdebug" 366*90f0b711SPaolo Bonzini self.create_image(backing_img, TestErrors.image_len) 367*90f0b711SPaolo Bonzini self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28) 368*90f0b711SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, 369*90f0b711SPaolo Bonzini '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 370*90f0b711SPaolo Bonzini % (self.blkdebug_file, backing_img), 371*90f0b711SPaolo Bonzini test_img) 372*90f0b711SPaolo Bonzini self.vm = iotests.VM().add_drive(test_img) 373*90f0b711SPaolo Bonzini self.vm.launch() 374*90f0b711SPaolo Bonzini 375*90f0b711SPaolo Bonzini def tearDown(self): 376*90f0b711SPaolo Bonzini self.vm.shutdown() 377*90f0b711SPaolo Bonzini os.remove(test_img) 378*90f0b711SPaolo Bonzini os.remove(backing_img) 379*90f0b711SPaolo Bonzini os.remove(self.blkdebug_file) 380*90f0b711SPaolo Bonzini 381*90f0b711SPaolo Bonzini def test_enospc(self): 382*90f0b711SPaolo Bonzini self.assert_no_active_streams() 383*90f0b711SPaolo Bonzini 384*90f0b711SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') 385*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 386*90f0b711SPaolo Bonzini 387*90f0b711SPaolo Bonzini error = False 388*90f0b711SPaolo Bonzini completed = False 389*90f0b711SPaolo Bonzini while not completed: 390*90f0b711SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 391*90f0b711SPaolo Bonzini if event['event'] == 'BLOCK_JOB_ERROR': 392*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 393*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/operation', 'read') 394*90f0b711SPaolo Bonzini 395*90f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 396*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', True) 397*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) 398*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'nospace') 399*90f0b711SPaolo Bonzini 400*90f0b711SPaolo Bonzini result = self.vm.qmp('block-job-resume', device='drive0') 401*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return', {}) 402*90f0b711SPaolo Bonzini 403*90f0b711SPaolo Bonzini result = self.vm.qmp('query-block-jobs') 404*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/paused', False) 405*90f0b711SPaolo Bonzini self.assert_qmp(result, 'return[0]/io-status', 'ok') 406*90f0b711SPaolo Bonzini error = True 407*90f0b711SPaolo Bonzini elif event['event'] == 'BLOCK_JOB_COMPLETED': 408*90f0b711SPaolo Bonzini self.assertTrue(error, 'job completed unexpectedly') 409*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 410*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 411*90f0b711SPaolo Bonzini self.assert_qmp_absent(event, 'data/error') 412*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 413*90f0b711SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 414*90f0b711SPaolo Bonzini completed = True 415*90f0b711SPaolo Bonzini 416*90f0b711SPaolo Bonzini self.assert_no_active_streams() 417*90f0b711SPaolo Bonzini self.vm.shutdown() 418774a8850SStefan Hajnoczi 41937ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase): 42037ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 42137ce63ebSStefan Hajnoczi 42237ce63ebSStefan Hajnoczi def setUp(self): 42337ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 42437ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 42537ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 42637ce63ebSStefan Hajnoczi self.vm.launch() 42737ce63ebSStefan Hajnoczi 42837ce63ebSStefan Hajnoczi def tearDown(self): 42937ce63ebSStefan Hajnoczi self.vm.shutdown() 43037ce63ebSStefan Hajnoczi os.remove(test_img) 43137ce63ebSStefan Hajnoczi os.remove(backing_img) 43237ce63ebSStefan Hajnoczi 43337ce63ebSStefan Hajnoczi def test_stream_stop(self): 43437ce63ebSStefan Hajnoczi self.assert_no_active_streams() 43537ce63ebSStefan Hajnoczi 436db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 43737ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 43837ce63ebSStefan Hajnoczi 4390fd05e8dSPaolo Bonzini time.sleep(0.1) 44037ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 44137ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 44237ce63ebSStefan Hajnoczi 443e425306aSStefan Hajnoczi self.cancel_and_wait() 44437ce63ebSStefan Hajnoczi 44537ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase): 44637ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 44737ce63ebSStefan Hajnoczi 44837ce63ebSStefan Hajnoczi def setUp(self): 44937ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 45037ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 45137ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 45237ce63ebSStefan Hajnoczi self.vm.launch() 45337ce63ebSStefan Hajnoczi 45437ce63ebSStefan Hajnoczi def tearDown(self): 45537ce63ebSStefan Hajnoczi self.vm.shutdown() 45637ce63ebSStefan Hajnoczi os.remove(test_img) 45737ce63ebSStefan Hajnoczi os.remove(backing_img) 45837ce63ebSStefan Hajnoczi 459e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 460e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 461e425306aSStefan Hajnoczi def perf_test_throughput(self): 46237ce63ebSStefan Hajnoczi self.assert_no_active_streams() 46337ce63ebSStefan Hajnoczi 464db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 46537ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 46637ce63ebSStefan Hajnoczi 467e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 46837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 46937ce63ebSStefan Hajnoczi 47037ce63ebSStefan Hajnoczi completed = False 47137ce63ebSStefan Hajnoczi while not completed: 47237ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 47337ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 47437ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 47537ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 47637ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 47737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 47837ce63ebSStefan Hajnoczi completed = True 47937ce63ebSStefan Hajnoczi 48037ce63ebSStefan Hajnoczi self.assert_no_active_streams() 48137ce63ebSStefan Hajnoczi 482e425306aSStefan Hajnoczi def test_set_speed(self): 483e425306aSStefan Hajnoczi self.assert_no_active_streams() 484e425306aSStefan Hajnoczi 485e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 486e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 487e425306aSStefan Hajnoczi 488e425306aSStefan Hajnoczi # Default speed is 0 489e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 490e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 491e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 492e425306aSStefan Hajnoczi 493e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 494e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 495e425306aSStefan Hajnoczi 496e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 497e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 498e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 499e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 500e425306aSStefan Hajnoczi 501e425306aSStefan Hajnoczi self.cancel_and_wait() 502e425306aSStefan Hajnoczi 503e425306aSStefan Hajnoczi # Check setting speed in block-stream works 504e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 505e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 506e425306aSStefan Hajnoczi 507e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 508e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 509e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 510e425306aSStefan Hajnoczi 511e425306aSStefan Hajnoczi self.cancel_and_wait() 512e425306aSStefan Hajnoczi 513e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 514e425306aSStefan Hajnoczi self.assert_no_active_streams() 515e425306aSStefan Hajnoczi 516e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 51758c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 518e425306aSStefan Hajnoczi 519e425306aSStefan Hajnoczi self.assert_no_active_streams() 520e425306aSStefan Hajnoczi 521e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 522e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 523e425306aSStefan Hajnoczi 524e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 52558c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 526e425306aSStefan Hajnoczi 527e425306aSStefan Hajnoczi self.cancel_and_wait() 528e425306aSStefan Hajnoczi 52937ce63ebSStefan Hajnocziif __name__ == '__main__': 53037ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 531