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 12837ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase): 12937ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 13037ce63ebSStefan Hajnoczi 13137ce63ebSStefan Hajnoczi def setUp(self): 13237ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 13337ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 13437ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 13537ce63ebSStefan Hajnoczi self.vm.launch() 13637ce63ebSStefan Hajnoczi 13737ce63ebSStefan Hajnoczi def tearDown(self): 13837ce63ebSStefan Hajnoczi self.vm.shutdown() 13937ce63ebSStefan Hajnoczi os.remove(test_img) 14037ce63ebSStefan Hajnoczi os.remove(backing_img) 14137ce63ebSStefan Hajnoczi 14237ce63ebSStefan Hajnoczi def test_stream_stop(self): 14337ce63ebSStefan Hajnoczi import time 14437ce63ebSStefan Hajnoczi 14537ce63ebSStefan Hajnoczi self.assert_no_active_streams() 14637ce63ebSStefan Hajnoczi 147db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 14837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 14937ce63ebSStefan Hajnoczi 150*0fd05e8dSPaolo Bonzini time.sleep(0.1) 15137ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 15237ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 15337ce63ebSStefan Hajnoczi 154e425306aSStefan Hajnoczi self.cancel_and_wait() 15537ce63ebSStefan Hajnoczi 15637ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase): 15737ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 15837ce63ebSStefan Hajnoczi 15937ce63ebSStefan Hajnoczi def setUp(self): 16037ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 16137ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 16237ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 16337ce63ebSStefan Hajnoczi self.vm.launch() 16437ce63ebSStefan Hajnoczi 16537ce63ebSStefan Hajnoczi def tearDown(self): 16637ce63ebSStefan Hajnoczi self.vm.shutdown() 16737ce63ebSStefan Hajnoczi os.remove(test_img) 16837ce63ebSStefan Hajnoczi os.remove(backing_img) 16937ce63ebSStefan Hajnoczi 170e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 171e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 172e425306aSStefan Hajnoczi def perf_test_throughput(self): 17337ce63ebSStefan Hajnoczi self.assert_no_active_streams() 17437ce63ebSStefan Hajnoczi 175db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 17637ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 17737ce63ebSStefan Hajnoczi 178e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 17937ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 18037ce63ebSStefan Hajnoczi 18137ce63ebSStefan Hajnoczi completed = False 18237ce63ebSStefan Hajnoczi while not completed: 18337ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 18437ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 18537ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 18637ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 18737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 18837ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 18937ce63ebSStefan Hajnoczi completed = True 19037ce63ebSStefan Hajnoczi 19137ce63ebSStefan Hajnoczi self.assert_no_active_streams() 19237ce63ebSStefan Hajnoczi 193e425306aSStefan Hajnoczi def test_set_speed(self): 194e425306aSStefan Hajnoczi self.assert_no_active_streams() 195e425306aSStefan Hajnoczi 196e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 197e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 198e425306aSStefan Hajnoczi 199e425306aSStefan Hajnoczi # Default speed is 0 200e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 201e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 202e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 203e425306aSStefan Hajnoczi 204e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 205e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 206e425306aSStefan Hajnoczi 207e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 208e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 209e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 210e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 211e425306aSStefan Hajnoczi 212e425306aSStefan Hajnoczi self.cancel_and_wait() 213e425306aSStefan Hajnoczi 214e425306aSStefan Hajnoczi # Check setting speed in block-stream works 215e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 216e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 217e425306aSStefan Hajnoczi 218e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 219e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 220e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 221e425306aSStefan Hajnoczi 222e425306aSStefan Hajnoczi self.cancel_and_wait() 223e425306aSStefan Hajnoczi 224e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 225e425306aSStefan Hajnoczi self.assert_no_active_streams() 226e425306aSStefan Hajnoczi 227e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 228e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 229e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 230e425306aSStefan Hajnoczi 231e425306aSStefan Hajnoczi self.assert_no_active_streams() 232e425306aSStefan Hajnoczi 233e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 234e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 235e425306aSStefan Hajnoczi 236e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 237e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 238e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 239e425306aSStefan Hajnoczi 240e425306aSStefan Hajnoczi self.cancel_and_wait() 241e425306aSStefan Hajnoczi 24237ce63ebSStefan Hajnocziif __name__ == '__main__': 24337ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 244