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 2137ce63ebSStefan Hajnocziimport os 2237ce63ebSStefan Hajnocziimport iotests 2337ce63ebSStefan Hajnoczifrom iotests import qemu_img, qemu_io 24ab68cdfaSPaolo Bonziniimport struct 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 3037ce63ebSStefan Hajnocziclass ImageStreamingTestCase(iotests.QMPTestCase): 3137ce63ebSStefan Hajnoczi '''Abstract base class for image streaming test cases''' 3237ce63ebSStefan Hajnoczi 3337ce63ebSStefan Hajnoczi def assert_no_active_streams(self): 3437ce63ebSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 3537ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', []) 3637ce63ebSStefan Hajnoczi 37e425306aSStefan Hajnoczi def cancel_and_wait(self, drive='drive0'): 38e425306aSStefan Hajnoczi '''Cancel a block job and wait for it to finish''' 39e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-cancel', device=drive) 40e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 41e425306aSStefan Hajnoczi 42e425306aSStefan Hajnoczi cancelled = False 43e425306aSStefan Hajnoczi while not cancelled: 44e425306aSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 45e425306aSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_CANCELLED': 46e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 47e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/device', drive) 48e425306aSStefan Hajnoczi cancelled = True 49e425306aSStefan Hajnoczi 50e425306aSStefan Hajnoczi self.assert_no_active_streams() 51e425306aSStefan Hajnoczi 52ab68cdfaSPaolo Bonzini def create_image(self, name, size): 53ab68cdfaSPaolo Bonzini file = open(name, 'w') 54ab68cdfaSPaolo Bonzini i = 0 55ab68cdfaSPaolo Bonzini while i < size: 56ab68cdfaSPaolo Bonzini sector = struct.pack('>l504xl', i / 512, i / 512) 57ab68cdfaSPaolo Bonzini file.write(sector) 58ab68cdfaSPaolo Bonzini i = i + 512 59ab68cdfaSPaolo Bonzini file.close() 60ab68cdfaSPaolo Bonzini 61ab68cdfaSPaolo Bonzini 6237ce63ebSStefan Hajnocziclass TestSingleDrive(ImageStreamingTestCase): 6337ce63ebSStefan Hajnoczi image_len = 1 * 1024 * 1024 # MB 6437ce63ebSStefan Hajnoczi 6537ce63ebSStefan Hajnoczi def setUp(self): 66ab68cdfaSPaolo Bonzini self.create_image(backing_img, TestSingleDrive.image_len) 676e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) 686e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) 6937ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 7037ce63ebSStefan Hajnoczi self.vm.launch() 7137ce63ebSStefan Hajnoczi 7237ce63ebSStefan Hajnoczi def tearDown(self): 7337ce63ebSStefan Hajnoczi self.vm.shutdown() 7437ce63ebSStefan Hajnoczi os.remove(test_img) 756e343609SPaolo Bonzini os.remove(mid_img) 7637ce63ebSStefan Hajnoczi os.remove(backing_img) 7737ce63ebSStefan Hajnoczi 7837ce63ebSStefan Hajnoczi def test_stream(self): 7937ce63ebSStefan Hajnoczi self.assert_no_active_streams() 8037ce63ebSStefan Hajnoczi 81db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 8237ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 8337ce63ebSStefan Hajnoczi 8437ce63ebSStefan Hajnoczi completed = False 8537ce63ebSStefan Hajnoczi while not completed: 8637ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 8737ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 8837ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 8937ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 9037ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 9137ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 9237ce63ebSStefan Hajnoczi completed = True 9337ce63ebSStefan Hajnoczi 9437ce63ebSStefan Hajnoczi self.assert_no_active_streams() 95863a5d04SPaolo Bonzini self.vm.shutdown() 9637ce63ebSStefan Hajnoczi 97efcc7a23SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', backing_img), 98efcc7a23SPaolo Bonzini qemu_io('-c', 'map', test_img), 99efcc7a23SPaolo Bonzini 'image file map does not match backing file after streaming') 10037ce63ebSStefan Hajnoczi 1016e343609SPaolo Bonzini def test_stream_partial(self): 1026e343609SPaolo Bonzini self.assert_no_active_streams() 1036e343609SPaolo Bonzini 1046e343609SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', base=mid_img) 1056e343609SPaolo Bonzini self.assert_qmp(result, 'return', {}) 1066e343609SPaolo Bonzini 1076e343609SPaolo Bonzini completed = False 1086e343609SPaolo Bonzini while not completed: 1096e343609SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 1106e343609SPaolo Bonzini if event['event'] == 'BLOCK_JOB_COMPLETED': 1116e343609SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 1126e343609SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 1136e343609SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 1146e343609SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 1156e343609SPaolo Bonzini completed = True 1166e343609SPaolo Bonzini 1176e343609SPaolo Bonzini self.assert_no_active_streams() 1186e343609SPaolo Bonzini self.vm.shutdown() 1196e343609SPaolo Bonzini 1206e343609SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', mid_img), 1216e343609SPaolo Bonzini qemu_io('-c', 'map', test_img), 1226e343609SPaolo Bonzini 'image file map does not match backing file after streaming') 1236e343609SPaolo Bonzini 12437ce63ebSStefan Hajnoczi def test_device_not_found(self): 125db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='nonexistent') 12637ce63ebSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'DeviceNotFound') 12737ce63ebSStefan Hajnoczi 128*774a8850SStefan Hajnoczi 129*774a8850SStefan Hajnocziclass TestSmallerBackingFile(ImageStreamingTestCase): 130*774a8850SStefan Hajnoczi backing_len = 1 * 1024 * 1024 # MB 131*774a8850SStefan Hajnoczi image_len = 2 * backing_len 132*774a8850SStefan Hajnoczi 133*774a8850SStefan Hajnoczi def setUp(self): 134*774a8850SStefan Hajnoczi self.create_image(backing_img, self.backing_len) 135*774a8850SStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) 136*774a8850SStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 137*774a8850SStefan Hajnoczi self.vm.launch() 138*774a8850SStefan Hajnoczi 139*774a8850SStefan Hajnoczi # If this hangs, then you are missing a fix to complete streaming when the 140*774a8850SStefan Hajnoczi # end of the backing file is reached. 141*774a8850SStefan Hajnoczi def test_stream(self): 142*774a8850SStefan Hajnoczi self.assert_no_active_streams() 143*774a8850SStefan Hajnoczi 144*774a8850SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 145*774a8850SStefan Hajnoczi self.assert_qmp(result, 'return', {}) 146*774a8850SStefan Hajnoczi 147*774a8850SStefan Hajnoczi completed = False 148*774a8850SStefan Hajnoczi while not completed: 149*774a8850SStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 150*774a8850SStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 151*774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 152*774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 153*774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 154*774a8850SStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 155*774a8850SStefan Hajnoczi completed = True 156*774a8850SStefan Hajnoczi 157*774a8850SStefan Hajnoczi self.assert_no_active_streams() 158*774a8850SStefan Hajnoczi self.vm.shutdown() 159*774a8850SStefan Hajnoczi 160*774a8850SStefan Hajnoczi 16137ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase): 16237ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 16337ce63ebSStefan Hajnoczi 16437ce63ebSStefan Hajnoczi def setUp(self): 16537ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 16637ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 16737ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 16837ce63ebSStefan Hajnoczi self.vm.launch() 16937ce63ebSStefan Hajnoczi 17037ce63ebSStefan Hajnoczi def tearDown(self): 17137ce63ebSStefan Hajnoczi self.vm.shutdown() 17237ce63ebSStefan Hajnoczi os.remove(test_img) 17337ce63ebSStefan Hajnoczi os.remove(backing_img) 17437ce63ebSStefan Hajnoczi 17537ce63ebSStefan Hajnoczi def test_stream_stop(self): 17637ce63ebSStefan Hajnoczi import time 17737ce63ebSStefan Hajnoczi 17837ce63ebSStefan Hajnoczi self.assert_no_active_streams() 17937ce63ebSStefan Hajnoczi 180db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 18137ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 18237ce63ebSStefan Hajnoczi 1830fd05e8dSPaolo Bonzini time.sleep(0.1) 18437ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 18537ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 18637ce63ebSStefan Hajnoczi 187e425306aSStefan Hajnoczi self.cancel_and_wait() 18837ce63ebSStefan Hajnoczi 18937ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase): 19037ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 19137ce63ebSStefan Hajnoczi 19237ce63ebSStefan Hajnoczi def setUp(self): 19337ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 19437ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 19537ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 19637ce63ebSStefan Hajnoczi self.vm.launch() 19737ce63ebSStefan Hajnoczi 19837ce63ebSStefan Hajnoczi def tearDown(self): 19937ce63ebSStefan Hajnoczi self.vm.shutdown() 20037ce63ebSStefan Hajnoczi os.remove(test_img) 20137ce63ebSStefan Hajnoczi os.remove(backing_img) 20237ce63ebSStefan Hajnoczi 203e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 204e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 205e425306aSStefan Hajnoczi def perf_test_throughput(self): 20637ce63ebSStefan Hajnoczi self.assert_no_active_streams() 20737ce63ebSStefan Hajnoczi 208db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 20937ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 21037ce63ebSStefan Hajnoczi 211e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 21237ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 21337ce63ebSStefan Hajnoczi 21437ce63ebSStefan Hajnoczi completed = False 21537ce63ebSStefan Hajnoczi while not completed: 21637ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 21737ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 21837ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 21937ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 22037ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 22137ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 22237ce63ebSStefan Hajnoczi completed = True 22337ce63ebSStefan Hajnoczi 22437ce63ebSStefan Hajnoczi self.assert_no_active_streams() 22537ce63ebSStefan Hajnoczi 226e425306aSStefan Hajnoczi def test_set_speed(self): 227e425306aSStefan Hajnoczi self.assert_no_active_streams() 228e425306aSStefan Hajnoczi 229e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 230e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 231e425306aSStefan Hajnoczi 232e425306aSStefan Hajnoczi # Default speed is 0 233e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 234e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 235e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 236e425306aSStefan Hajnoczi 237e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 238e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 239e425306aSStefan Hajnoczi 240e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 241e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 242e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 243e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 244e425306aSStefan Hajnoczi 245e425306aSStefan Hajnoczi self.cancel_and_wait() 246e425306aSStefan Hajnoczi 247e425306aSStefan Hajnoczi # Check setting speed in block-stream works 248e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 249e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 250e425306aSStefan Hajnoczi 251e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 252e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 253e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 254e425306aSStefan Hajnoczi 255e425306aSStefan Hajnoczi self.cancel_and_wait() 256e425306aSStefan Hajnoczi 257e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 258e425306aSStefan Hajnoczi self.assert_no_active_streams() 259e425306aSStefan Hajnoczi 260e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 26158c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 262e425306aSStefan Hajnoczi 263e425306aSStefan Hajnoczi self.assert_no_active_streams() 264e425306aSStefan Hajnoczi 265e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 266e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 267e425306aSStefan Hajnoczi 268e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 26958c8cce2SKevin Wolf self.assert_qmp(result, 'error/class', 'GenericError') 270e425306aSStefan Hajnoczi 271e425306aSStefan Hajnoczi self.cancel_and_wait() 272e425306aSStefan Hajnoczi 27337ce63ebSStefan Hajnocziif __name__ == '__main__': 27437ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 275