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') 2637ce63ebSStefan Hajnoczitest_img = os.path.join(iotests.test_dir, 'test.img') 2737ce63ebSStefan Hajnoczi 2837ce63ebSStefan Hajnocziclass ImageStreamingTestCase(iotests.QMPTestCase): 2937ce63ebSStefan Hajnoczi '''Abstract base class for image streaming test cases''' 3037ce63ebSStefan Hajnoczi 3137ce63ebSStefan Hajnoczi def assert_no_active_streams(self): 3237ce63ebSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 3337ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', []) 3437ce63ebSStefan Hajnoczi 35*e425306aSStefan Hajnoczi def cancel_and_wait(self, drive='drive0'): 36*e425306aSStefan Hajnoczi '''Cancel a block job and wait for it to finish''' 37*e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-cancel', device=drive) 38*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 39*e425306aSStefan Hajnoczi 40*e425306aSStefan Hajnoczi cancelled = False 41*e425306aSStefan Hajnoczi while not cancelled: 42*e425306aSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 43*e425306aSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_CANCELLED': 44*e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 45*e425306aSStefan Hajnoczi self.assert_qmp(event, 'data/device', drive) 46*e425306aSStefan Hajnoczi cancelled = True 47*e425306aSStefan Hajnoczi 48*e425306aSStefan Hajnoczi self.assert_no_active_streams() 49*e425306aSStefan Hajnoczi 5037ce63ebSStefan Hajnocziclass TestSingleDrive(ImageStreamingTestCase): 5137ce63ebSStefan Hajnoczi image_len = 1 * 1024 * 1024 # MB 5237ce63ebSStefan Hajnoczi 5337ce63ebSStefan Hajnoczi def setUp(self): 5437ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSingleDrive.image_len)) 5537ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 5637ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 5737ce63ebSStefan Hajnoczi self.vm.launch() 5837ce63ebSStefan Hajnoczi 5937ce63ebSStefan Hajnoczi def tearDown(self): 6037ce63ebSStefan Hajnoczi self.vm.shutdown() 6137ce63ebSStefan Hajnoczi os.remove(test_img) 6237ce63ebSStefan Hajnoczi os.remove(backing_img) 6337ce63ebSStefan Hajnoczi 6437ce63ebSStefan Hajnoczi def test_stream(self): 6537ce63ebSStefan Hajnoczi self.assert_no_active_streams() 6637ce63ebSStefan Hajnoczi 67db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 6837ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 6937ce63ebSStefan Hajnoczi 7037ce63ebSStefan Hajnoczi completed = False 7137ce63ebSStefan Hajnoczi while not completed: 7237ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 7337ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 7437ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 7537ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 7637ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 7737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 7837ce63ebSStefan Hajnoczi completed = True 7937ce63ebSStefan Hajnoczi 8037ce63ebSStefan Hajnoczi self.assert_no_active_streams() 8137ce63ebSStefan Hajnoczi 8237ce63ebSStefan Hajnoczi self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', test_img), 8337ce63ebSStefan Hajnoczi 'image file not fully populated after streaming') 8437ce63ebSStefan Hajnoczi 8537ce63ebSStefan Hajnoczi def test_device_not_found(self): 86db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='nonexistent') 8737ce63ebSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'DeviceNotFound') 8837ce63ebSStefan Hajnoczi 8937ce63ebSStefan Hajnocziclass TestStreamStop(ImageStreamingTestCase): 9037ce63ebSStefan Hajnoczi image_len = 8 * 1024 * 1024 * 1024 # GB 9137ce63ebSStefan Hajnoczi 9237ce63ebSStefan Hajnoczi def setUp(self): 9337ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestStreamStop.image_len)) 9437ce63ebSStefan Hajnoczi qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 9537ce63ebSStefan Hajnoczi self.vm = iotests.VM().add_drive(test_img) 9637ce63ebSStefan Hajnoczi self.vm.launch() 9737ce63ebSStefan Hajnoczi 9837ce63ebSStefan Hajnoczi def tearDown(self): 9937ce63ebSStefan Hajnoczi self.vm.shutdown() 10037ce63ebSStefan Hajnoczi os.remove(test_img) 10137ce63ebSStefan Hajnoczi os.remove(backing_img) 10237ce63ebSStefan Hajnoczi 10337ce63ebSStefan Hajnoczi def test_stream_stop(self): 10437ce63ebSStefan Hajnoczi import time 10537ce63ebSStefan Hajnoczi 10637ce63ebSStefan Hajnoczi self.assert_no_active_streams() 10737ce63ebSStefan Hajnoczi 108db58f9c0SStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 10937ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 11037ce63ebSStefan Hajnoczi 11137ce63ebSStefan Hajnoczi time.sleep(1) 11237ce63ebSStefan Hajnoczi events = self.vm.get_qmp_events(wait=False) 11337ce63ebSStefan Hajnoczi self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 11437ce63ebSStefan Hajnoczi 115*e425306aSStefan Hajnoczi self.cancel_and_wait() 11637ce63ebSStefan Hajnoczi 11737ce63ebSStefan Hajnocziclass TestSetSpeed(ImageStreamingTestCase): 11837ce63ebSStefan Hajnoczi image_len = 80 * 1024 * 1024 # MB 11937ce63ebSStefan Hajnoczi 12037ce63ebSStefan Hajnoczi def setUp(self): 12137ce63ebSStefan Hajnoczi qemu_img('create', backing_img, str(TestSetSpeed.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 131*e425306aSStefan Hajnoczi # This is a short performance test which is not run by default. 132*e425306aSStefan Hajnoczi # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 133*e425306aSStefan Hajnoczi def perf_test_throughput(self): 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 139*e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 14037ce63ebSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 14137ce63ebSStefan Hajnoczi 14237ce63ebSStefan Hajnoczi completed = False 14337ce63ebSStefan Hajnoczi while not completed: 14437ce63ebSStefan Hajnoczi for event in self.vm.get_qmp_events(wait=True): 14537ce63ebSStefan Hajnoczi if event['event'] == 'BLOCK_JOB_COMPLETED': 14637ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/type', 'stream') 14737ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/device', 'drive0') 14837ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/offset', self.image_len) 14937ce63ebSStefan Hajnoczi self.assert_qmp(event, 'data/len', self.image_len) 15037ce63ebSStefan Hajnoczi completed = True 15137ce63ebSStefan Hajnoczi 15237ce63ebSStefan Hajnoczi self.assert_no_active_streams() 15337ce63ebSStefan Hajnoczi 154*e425306aSStefan Hajnoczi def test_set_speed(self): 155*e425306aSStefan Hajnoczi self.assert_no_active_streams() 156*e425306aSStefan Hajnoczi 157*e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 158*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 159*e425306aSStefan Hajnoczi 160*e425306aSStefan Hajnoczi # Default speed is 0 161*e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 162*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 163*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 0) 164*e425306aSStefan Hajnoczi 165*e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 166*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 167*e425306aSStefan Hajnoczi 168*e425306aSStefan Hajnoczi # Ensure the speed we set was accepted 169*e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 170*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 171*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 172*e425306aSStefan Hajnoczi 173*e425306aSStefan Hajnoczi self.cancel_and_wait() 174*e425306aSStefan Hajnoczi 175*e425306aSStefan Hajnoczi # Check setting speed in block-stream works 176*e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 177*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 178*e425306aSStefan Hajnoczi 179*e425306aSStefan Hajnoczi result = self.vm.qmp('query-block-jobs') 180*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/device', 'drive0') 181*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 182*e425306aSStefan Hajnoczi 183*e425306aSStefan Hajnoczi self.cancel_and_wait() 184*e425306aSStefan Hajnoczi 185*e425306aSStefan Hajnoczi def test_set_speed_invalid(self): 186*e425306aSStefan Hajnoczi self.assert_no_active_streams() 187*e425306aSStefan Hajnoczi 188*e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0', speed=-1) 189*e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 190*e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 191*e425306aSStefan Hajnoczi 192*e425306aSStefan Hajnoczi self.assert_no_active_streams() 193*e425306aSStefan Hajnoczi 194*e425306aSStefan Hajnoczi result = self.vm.qmp('block-stream', device='drive0') 195*e425306aSStefan Hajnoczi self.assert_qmp(result, 'return', {}) 196*e425306aSStefan Hajnoczi 197*e425306aSStefan Hajnoczi result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 198*e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/class', 'InvalidParameter') 199*e425306aSStefan Hajnoczi self.assert_qmp(result, 'error/data/name', 'speed') 200*e425306aSStefan Hajnoczi 201*e425306aSStefan Hajnoczi self.cancel_and_wait() 202*e425306aSStefan Hajnoczi 20337ce63ebSStefan Hajnocziif __name__ == '__main__': 20437ce63ebSStefan Hajnoczi iotests.main(supported_fmts=['qcow2', 'qed']) 205