1#!/usr/bin/env python 2# 3# Tests for image streaming. 4# 5# Copyright (C) 2012 IBM Corp. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20 21import os 22import iotests 23from iotests import qemu_img, qemu_io 24 25backing_img = os.path.join(iotests.test_dir, 'backing.img') 26test_img = os.path.join(iotests.test_dir, 'test.img') 27 28class ImageStreamingTestCase(iotests.QMPTestCase): 29 '''Abstract base class for image streaming test cases''' 30 31 def assert_no_active_streams(self): 32 result = self.vm.qmp('query-block-jobs') 33 self.assert_qmp(result, 'return', []) 34 35 def cancel_and_wait(self, drive='drive0'): 36 '''Cancel a block job and wait for it to finish''' 37 result = self.vm.qmp('block-job-cancel', device=drive) 38 self.assert_qmp(result, 'return', {}) 39 40 cancelled = False 41 while not cancelled: 42 for event in self.vm.get_qmp_events(wait=True): 43 if event['event'] == 'BLOCK_JOB_CANCELLED': 44 self.assert_qmp(event, 'data/type', 'stream') 45 self.assert_qmp(event, 'data/device', drive) 46 cancelled = True 47 48 self.assert_no_active_streams() 49 50class TestSingleDrive(ImageStreamingTestCase): 51 image_len = 1 * 1024 * 1024 # MB 52 53 def setUp(self): 54 qemu_img('create', backing_img, str(TestSingleDrive.image_len)) 55 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 56 self.vm = iotests.VM().add_drive(test_img) 57 self.vm.launch() 58 59 def tearDown(self): 60 self.vm.shutdown() 61 os.remove(test_img) 62 os.remove(backing_img) 63 64 def test_stream(self): 65 self.assert_no_active_streams() 66 67 result = self.vm.qmp('block-stream', device='drive0') 68 self.assert_qmp(result, 'return', {}) 69 70 completed = False 71 while not completed: 72 for event in self.vm.get_qmp_events(wait=True): 73 if event['event'] == 'BLOCK_JOB_COMPLETED': 74 self.assert_qmp(event, 'data/type', 'stream') 75 self.assert_qmp(event, 'data/device', 'drive0') 76 self.assert_qmp(event, 'data/offset', self.image_len) 77 self.assert_qmp(event, 'data/len', self.image_len) 78 completed = True 79 80 self.assert_no_active_streams() 81 82 self.assertFalse('sectors not allocated' in qemu_io('-c', 'map', test_img), 83 'image file not fully populated after streaming') 84 85 def test_device_not_found(self): 86 result = self.vm.qmp('block-stream', device='nonexistent') 87 self.assert_qmp(result, 'error/class', 'DeviceNotFound') 88 89class TestStreamStop(ImageStreamingTestCase): 90 image_len = 8 * 1024 * 1024 * 1024 # GB 91 92 def setUp(self): 93 qemu_img('create', backing_img, str(TestStreamStop.image_len)) 94 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 95 self.vm = iotests.VM().add_drive(test_img) 96 self.vm.launch() 97 98 def tearDown(self): 99 self.vm.shutdown() 100 os.remove(test_img) 101 os.remove(backing_img) 102 103 def test_stream_stop(self): 104 import time 105 106 self.assert_no_active_streams() 107 108 result = self.vm.qmp('block-stream', device='drive0') 109 self.assert_qmp(result, 'return', {}) 110 111 time.sleep(1) 112 events = self.vm.get_qmp_events(wait=False) 113 self.assertEqual(events, [], 'unexpected QMP event: %s' % events) 114 115 self.cancel_and_wait() 116 117class TestSetSpeed(ImageStreamingTestCase): 118 image_len = 80 * 1024 * 1024 # MB 119 120 def setUp(self): 121 qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 122 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 123 self.vm = iotests.VM().add_drive(test_img) 124 self.vm.launch() 125 126 def tearDown(self): 127 self.vm.shutdown() 128 os.remove(test_img) 129 os.remove(backing_img) 130 131 # This is a short performance test which is not run by default. 132 # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" 133 def perf_test_throughput(self): 134 self.assert_no_active_streams() 135 136 result = self.vm.qmp('block-stream', device='drive0') 137 self.assert_qmp(result, 'return', {}) 138 139 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 140 self.assert_qmp(result, 'return', {}) 141 142 completed = False 143 while not completed: 144 for event in self.vm.get_qmp_events(wait=True): 145 if event['event'] == 'BLOCK_JOB_COMPLETED': 146 self.assert_qmp(event, 'data/type', 'stream') 147 self.assert_qmp(event, 'data/device', 'drive0') 148 self.assert_qmp(event, 'data/offset', self.image_len) 149 self.assert_qmp(event, 'data/len', self.image_len) 150 completed = True 151 152 self.assert_no_active_streams() 153 154 def test_set_speed(self): 155 self.assert_no_active_streams() 156 157 result = self.vm.qmp('block-stream', device='drive0') 158 self.assert_qmp(result, 'return', {}) 159 160 # Default speed is 0 161 result = self.vm.qmp('query-block-jobs') 162 self.assert_qmp(result, 'return[0]/device', 'drive0') 163 self.assert_qmp(result, 'return[0]/speed', 0) 164 165 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 166 self.assert_qmp(result, 'return', {}) 167 168 # Ensure the speed we set was accepted 169 result = self.vm.qmp('query-block-jobs') 170 self.assert_qmp(result, 'return[0]/device', 'drive0') 171 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 172 173 self.cancel_and_wait() 174 175 # Check setting speed in block-stream works 176 result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) 177 self.assert_qmp(result, 'return', {}) 178 179 result = self.vm.qmp('query-block-jobs') 180 self.assert_qmp(result, 'return[0]/device', 'drive0') 181 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 182 183 self.cancel_and_wait() 184 185 def test_set_speed_invalid(self): 186 self.assert_no_active_streams() 187 188 result = self.vm.qmp('block-stream', device='drive0', speed=-1) 189 self.assert_qmp(result, 'error/class', 'InvalidParameter') 190 self.assert_qmp(result, 'error/data/name', 'speed') 191 192 self.assert_no_active_streams() 193 194 result = self.vm.qmp('block-stream', device='drive0') 195 self.assert_qmp(result, 'return', {}) 196 197 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 198 self.assert_qmp(result, 'error/class', 'InvalidParameter') 199 self.assert_qmp(result, 'error/data/name', 'speed') 200 201 self.cancel_and_wait() 202 203if __name__ == '__main__': 204 iotests.main(supported_fmts=['qcow2', 'qed']) 205