xref: /openbmc/qemu/tests/qemu-iotests/030 (revision e425306a)
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