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 2437ce63ebSStefan Hajnoczi 2537ce63ebSStefan Hajnoczibacking_img = os.path.join(iotests.test_dir, 'backing.img') 266e343609SPaolo Bonzinimid_img = os.path.join(iotests.test_dir, 'mid.img') 2737ce63ebSStefan Hajnoczitest_img = os.path.join(iotests.test_dir, 'test.img') 2837ce63ebSStefan Hajnoczi 2937ce63ebSStefan Hajnocziclass ImageStreamingTestCase(iotests.QMPTestCase): 3037ce63ebSStefan Hajnoczi '''Abstract base class for image streaming test cases''' 3137ce63ebSStefan Hajnoczi 3237ce63ebSStefan Hajnoczi def assert_no_active_streams(self): 3337ce63ebSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 3437ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', []) 3537ce63ebSStefan Hajnoczi 36e425306aSStefan Hajnoczi def cancel_and_wait(self, drive='drive0'): 37e425306aSStefan Hajnoczi '''Cancel a block job and wait for it to finish''' 38e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-cancel', device=drive) 39e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 40e425306aSStefan Hajnoczi 41e425306aSStefan Hajnoczi cancelled = False 42e425306aSStefan Hajnoczi while not cancelled: 43e425306aSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 44e425306aSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_CANCELLED': 45e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 46e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/device', drive) 47e425306aSStefan Hajnoczi cancelled = True 48e425306aSStefan Hajnoczi 49e425306aSStefan Hajnoczi self.assert_no_active_streams() 50e425306aSStefan Hajnoczi 5137ce63ebSStefan Hajnocziclass TestSingleDrive(ImageStreamingTestCase): 5237ce63ebSStefan Hajnoczi image_len = 1 * 1024 * 1024 # MB 5337ce63ebSStefan Hajnoczi 5437ce63ebSStefan Hajnoczi def setUp(self): 5537ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSingleDrive.image_len)) 566e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) 576e343609SPaolo Bonzini qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) 5837ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 5937ce63ebSStefan Hajnoczi self.vm.launch() 6037ce63ebSStefan Hajnoczi 6137ce63ebSStefan Hajnoczi def tearDown(self): 6237ce63ebSStefan Hajnoczi self.vm.shutdown() 6337ce63ebSStefan Hajnoczi os.remove(test_img) 646e343609SPaolo Bonzini os.remove(mid_img) 6537ce63ebSStefan Hajnoczi os.remove(backing_img) 6637ce63ebSStefan Hajnoczi 6737ce63ebSStefan Hajnoczi def test_stream(self): 6837ce63ebSStefan Hajnoczi self.assert_no_active_streams() 6937ce63ebSStefan Hajnoczi 70db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 7137ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 7237ce63ebSStefan Hajnoczi 7337ce63ebSStefan Hajnoczi completed = False 7437ce63ebSStefan Hajnoczi while not completed: 7537ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 7637ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 7737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 7837ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 7937ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 8037ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 8137ce63ebSStefan Hajnoczi completed = True 8237ce63ebSStefan Hajnoczi 8337ce63ebSStefan Hajnoczi self.assert_no_active_streams() 84863a5d04SPaolo Bonzini self.vm.shutdown() 8537ce63ebSStefan Hajnoczi 86*efcc7a23SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', backing_img), 87*efcc7a23SPaolo Bonzini qemu_io('-c', 'map', test_img), 88*efcc7a23SPaolo Bonzini 'image file map does not match backing file after streaming') 8937ce63ebSStefan Hajnoczi 906e343609SPaolo Bonzini def test_stream_partial(self): 916e343609SPaolo Bonzini self.assert_no_active_streams() 926e343609SPaolo Bonzini 936e343609SPaolo Bonzini result = self.vm.qmp('block-stream', device='drive0', base=mid_img) 946e343609SPaolo Bonzini self.assert_qmp(result, 'return', {}) 956e343609SPaolo Bonzini 966e343609SPaolo Bonzini completed = False 976e343609SPaolo Bonzini while not completed: 986e343609SPaolo Bonzini for event in self.vm.get_qmp_events(wait=True): 996e343609SPaolo Bonzini if event['event'] == 'BLOCK_JOB_COMPLETED': 1006e343609SPaolo Bonzini self.assert_qmp(event, 'data/type', 'stream') 1016e343609SPaolo Bonzini self.assert_qmp(event, 'data/device', 'drive0') 1026e343609SPaolo Bonzini self.assert_qmp(event, 'data/offset', self.image_len) 1036e343609SPaolo Bonzini self.assert_qmp(event, 'data/len', self.image_len) 1046e343609SPaolo Bonzini completed = True 1056e343609SPaolo Bonzini 1066e343609SPaolo Bonzini self.assert_no_active_streams() 1076e343609SPaolo Bonzini self.vm.shutdown() 1086e343609SPaolo Bonzini 1096e343609SPaolo Bonzini self.assertEqual(qemu_io('-c', 'map', mid_img), 1106e343609SPaolo Bonzini qemu_io('-c', 'map', test_img), 1116e343609SPaolo Bonzini 'image file map does not match backing file after streaming') 1126e343609SPaolo Bonzini 11337ce63ebSStefan Hajnoczi def test_device_not_found(self): 114db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='nonexistent') 11537ce63ebSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'DeviceNotFound') 11637ce63ebSStefan Hajnoczi 11737ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase): 11837ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 11937ce63ebSStefan Hajnoczi 12037ce63ebSStefan Hajnoczi def setUp(self): 12137ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 12237ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 12337ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 12437ce63ebSStefan Hajnoczi self.vm.launch() 12537ce63ebSStefan Hajnoczi 12637ce63ebSStefan Hajnoczi def tearDown(self): 12737ce63ebSStefan Hajnoczi self.vm.shutdown() 12837ce63ebSStefan Hajnoczi os.remove(test_img) 12937ce63ebSStefan Hajnoczi os.remove(backing_img) 13037ce63ebSStefan Hajnoczi 13137ce63ebSStefan Hajnoczi def test_stream_stop(self): 13237ce63ebSStefan Hajnoczi import time 13337ce63ebSStefan Hajnoczi 13437ce63ebSStefan Hajnoczi self.assert_no_active_streams() 13537ce63ebSStefan Hajnoczi 136db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 13737ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 13837ce63ebSStefan Hajnoczi 13937ce63ebSStefan Hajnoczi time.sleep(1) 14037ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 14137ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 14237ce63ebSStefan Hajnoczi 143e425306aSStefan Hajnoczi self.cancel_and_wait() 14437ce63ebSStefan Hajnoczi 14537ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase): 14637ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 14737ce63ebSStefan Hajnoczi 14837ce63ebSStefan Hajnoczi def setUp(self): 14937ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 15037ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 15137ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 15237ce63ebSStefan Hajnoczi self.vm.launch() 15337ce63ebSStefan Hajnoczi 15437ce63ebSStefan Hajnoczi def tearDown(self): 15537ce63ebSStefan Hajnoczi self.vm.shutdown() 15637ce63ebSStefan Hajnoczi os.remove(test_img) 15737ce63ebSStefan Hajnoczi os.remove(backing_img) 15837ce63ebSStefan Hajnoczi 159e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 160e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 161e425306aSStefan Hajnoczi def perf_test_throughput(self): 16237ce63ebSStefan Hajnoczi self.assert_no_active_streams() 16337ce63ebSStefan Hajnoczi 164db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 16537ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 16637ce63ebSStefan Hajnoczi 167e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 16837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 16937ce63ebSStefan Hajnoczi 17037ce63ebSStefan Hajnoczi completed = False 17137ce63ebSStefan Hajnoczi while not completed: 17237ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 17337ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 17437ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 17537ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 17637ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 17737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 17837ce63ebSStefan Hajnoczi completed = True 17937ce63ebSStefan Hajnoczi 18037ce63ebSStefan Hajnoczi self.assert_no_active_streams() 18137ce63ebSStefan Hajnoczi 182e425306aSStefan Hajnoczi def test_set_speed(self): 183e425306aSStefan Hajnoczi self.assert_no_active_streams() 184e425306aSStefan Hajnoczi 185e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 186e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 187e425306aSStefan Hajnoczi 188e425306aSStefan Hajnoczi # Default speed is 0 189e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 190e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 191e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 192e425306aSStefan Hajnoczi 193e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 194e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 195e425306aSStefan Hajnoczi 196e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 197e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 198e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 199e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 200e425306aSStefan Hajnoczi 201e425306aSStefan Hajnoczi self.cancel_and_wait() 202e425306aSStefan Hajnoczi 203e425306aSStefan Hajnoczi # Check setting speed in block-stream works 204e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 205e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 206e425306aSStefan Hajnoczi 207e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 208e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 209e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 210e425306aSStefan Hajnoczi 211e425306aSStefan Hajnoczi self.cancel_and_wait() 212e425306aSStefan Hajnoczi 213e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 214e425306aSStefan Hajnoczi self.assert_no_active_streams() 215e425306aSStefan Hajnoczi 216e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 217e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 218e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 219e425306aSStefan Hajnoczi 220e425306aSStefan Hajnoczi self.assert_no_active_streams() 221e425306aSStefan Hajnoczi 222e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 223e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 224e425306aSStefan Hajnoczi 225e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 226e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 227e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 228e425306aSStefan Hajnoczi 229e425306aSStefan Hajnoczi self.cancel_and_wait() 230e425306aSStefan Hajnoczi 23137ce63ebSStefan Hajnocziif __name__ == '__main__': 23237ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 233