]>
Commit | Line | Data |
---|---|---|
37ce63eb SH |
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 | ||
0c817347 | 21 | import time |
37ce63eb SH |
22 | import os |
23 | import iotests | |
24 | from iotests import qemu_img, qemu_io | |
ab68cdfa | 25 | import struct |
37ce63eb SH |
26 | |
27 | backing_img = os.path.join(iotests.test_dir, 'backing.img') | |
6e343609 | 28 | mid_img = os.path.join(iotests.test_dir, 'mid.img') |
37ce63eb SH |
29 | test_img = os.path.join(iotests.test_dir, 'test.img') |
30 | ||
31 | class ImageStreamingTestCase(iotests.QMPTestCase): | |
32 | '''Abstract base class for image streaming test cases''' | |
33 | ||
34 | def assert_no_active_streams(self): | |
35 | result = self.vm.qmp('query-block-jobs') | |
36 | self.assert_qmp(result, 'return', []) | |
37 | ||
e425306a SH |
38 | def cancel_and_wait(self, drive='drive0'): |
39 | '''Cancel a block job and wait for it to finish''' | |
40 | result = self.vm.qmp('block-job-cancel', device=drive) | |
41 | self.assert_qmp(result, 'return', {}) | |
42 | ||
43 | cancelled = False | |
44 | while not cancelled: | |
45 | for event in self.vm.get_qmp_events(wait=True): | |
46 | if event['event'] == 'BLOCK_JOB_CANCELLED': | |
47 | self.assert_qmp(event, 'data/type', 'stream') | |
48 | self.assert_qmp(event, 'data/device', drive) | |
49 | cancelled = True | |
50 | ||
51 | self.assert_no_active_streams() | |
52 | ||
ab68cdfa PB |
53 | def create_image(self, name, size): |
54 | file = open(name, 'w') | |
55 | i = 0 | |
56 | while i < size: | |
57 | sector = struct.pack('>l504xl', i / 512, i / 512) | |
58 | file.write(sector) | |
59 | i = i + 512 | |
60 | file.close() | |
61 | ||
62 | ||
37ce63eb SH |
63 | class TestSingleDrive(ImageStreamingTestCase): |
64 | image_len = 1 * 1024 * 1024 # MB | |
65 | ||
66 | def setUp(self): | |
ab68cdfa | 67 | self.create_image(backing_img, TestSingleDrive.image_len) |
6e343609 PB |
68 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) |
69 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) | |
37ce63eb SH |
70 | self.vm = iotests.VM().add_drive(test_img) |
71 | self.vm.launch() | |
72 | ||
73 | def tearDown(self): | |
74 | self.vm.shutdown() | |
75 | os.remove(test_img) | |
6e343609 | 76 | os.remove(mid_img) |
37ce63eb SH |
77 | os.remove(backing_img) |
78 | ||
79 | def test_stream(self): | |
80 | self.assert_no_active_streams() | |
81 | ||
db58f9c0 | 82 | result = self.vm.qmp('block-stream', device='drive0') |
37ce63eb SH |
83 | self.assert_qmp(result, 'return', {}) |
84 | ||
85 | completed = False | |
86 | while not completed: | |
87 | for event in self.vm.get_qmp_events(wait=True): | |
88 | if event['event'] == 'BLOCK_JOB_COMPLETED': | |
89 | self.assert_qmp(event, 'data/type', 'stream') | |
90 | self.assert_qmp(event, 'data/device', 'drive0') | |
91 | self.assert_qmp(event, 'data/offset', self.image_len) | |
92 | self.assert_qmp(event, 'data/len', self.image_len) | |
93 | completed = True | |
94 | ||
95 | self.assert_no_active_streams() | |
863a5d04 | 96 | self.vm.shutdown() |
37ce63eb | 97 | |
efcc7a23 PB |
98 | self.assertEqual(qemu_io('-c', 'map', backing_img), |
99 | qemu_io('-c', 'map', test_img), | |
100 | 'image file map does not match backing file after streaming') | |
37ce63eb | 101 | |
0c817347 PB |
102 | def test_stream_pause(self): |
103 | self.assert_no_active_streams() | |
104 | ||
105 | result = self.vm.qmp('block-stream', device='drive0') | |
106 | self.assert_qmp(result, 'return', {}) | |
107 | ||
108 | result = self.vm.qmp('block-job-pause', device='drive0') | |
109 | self.assert_qmp(result, 'return', {}) | |
110 | ||
111 | time.sleep(1) | |
112 | result = self.vm.qmp('query-block-jobs') | |
113 | offset = self.dictpath(result, 'return[0]/offset') | |
114 | ||
115 | time.sleep(1) | |
116 | result = self.vm.qmp('query-block-jobs') | |
117 | self.assert_qmp(result, 'return[0]/offset', offset) | |
118 | ||
119 | result = self.vm.qmp('block-job-resume', device='drive0') | |
120 | self.assert_qmp(result, 'return', {}) | |
121 | ||
122 | completed = False | |
123 | while not completed: | |
124 | for event in self.vm.get_qmp_events(wait=True): | |
125 | if event['event'] == 'BLOCK_JOB_COMPLETED': | |
126 | self.assert_qmp(event, 'data/type', 'stream') | |
127 | self.assert_qmp(event, 'data/device', 'drive0') | |
128 | self.assert_qmp(event, 'data/offset', self.image_len) | |
129 | self.assert_qmp(event, 'data/len', self.image_len) | |
130 | completed = True | |
131 | ||
132 | self.assert_no_active_streams() | |
133 | self.vm.shutdown() | |
134 | ||
135 | self.assertEqual(qemu_io('-c', 'map', backing_img), | |
136 | qemu_io('-c', 'map', test_img), | |
137 | 'image file map does not match backing file after streaming') | |
138 | ||
6e343609 PB |
139 | def test_stream_partial(self): |
140 | self.assert_no_active_streams() | |
141 | ||
142 | result = self.vm.qmp('block-stream', device='drive0', base=mid_img) | |
143 | self.assert_qmp(result, 'return', {}) | |
144 | ||
145 | completed = False | |
146 | while not completed: | |
147 | for event in self.vm.get_qmp_events(wait=True): | |
148 | if event['event'] == 'BLOCK_JOB_COMPLETED': | |
149 | self.assert_qmp(event, 'data/type', 'stream') | |
150 | self.assert_qmp(event, 'data/device', 'drive0') | |
151 | self.assert_qmp(event, 'data/offset', self.image_len) | |
152 | self.assert_qmp(event, 'data/len', self.image_len) | |
153 | completed = True | |
154 | ||
155 | self.assert_no_active_streams() | |
156 | self.vm.shutdown() | |
157 | ||
158 | self.assertEqual(qemu_io('-c', 'map', mid_img), | |
159 | qemu_io('-c', 'map', test_img), | |
160 | 'image file map does not match backing file after streaming') | |
161 | ||
37ce63eb | 162 | def test_device_not_found(self): |
db58f9c0 | 163 | result = self.vm.qmp('block-stream', device='nonexistent') |
37ce63eb SH |
164 | self.assert_qmp(result, 'error/class', 'DeviceNotFound') |
165 | ||
774a8850 SH |
166 | |
167 | class TestSmallerBackingFile(ImageStreamingTestCase): | |
168 | backing_len = 1 * 1024 * 1024 # MB | |
169 | image_len = 2 * backing_len | |
170 | ||
171 | def setUp(self): | |
172 | self.create_image(backing_img, self.backing_len) | |
173 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len)) | |
174 | self.vm = iotests.VM().add_drive(test_img) | |
175 | self.vm.launch() | |
176 | ||
177 | # If this hangs, then you are missing a fix to complete streaming when the | |
178 | # end of the backing file is reached. | |
179 | def test_stream(self): | |
180 | self.assert_no_active_streams() | |
181 | ||
182 | result = self.vm.qmp('block-stream', device='drive0') | |
183 | self.assert_qmp(result, 'return', {}) | |
184 | ||
185 | completed = False | |
186 | while not completed: | |
187 | for event in self.vm.get_qmp_events(wait=True): | |
188 | if event['event'] == 'BLOCK_JOB_COMPLETED': | |
189 | self.assert_qmp(event, 'data/type', 'stream') | |
190 | self.assert_qmp(event, 'data/device', 'drive0') | |
191 | self.assert_qmp(event, 'data/offset', self.image_len) | |
192 | self.assert_qmp(event, 'data/len', self.image_len) | |
193 | completed = True | |
194 | ||
195 | self.assert_no_active_streams() | |
196 | self.vm.shutdown() | |
197 | ||
90f0b711 PB |
198 | class TestErrors(ImageStreamingTestCase): |
199 | image_len = 2 * 1024 * 1024 # MB | |
200 | ||
201 | # this should match STREAM_BUFFER_SIZE/512 in block/stream.c | |
202 | STREAM_BUFFER_SIZE = 512 * 1024 | |
203 | ||
204 | def create_blkdebug_file(self, name, event, errno): | |
205 | file = open(name, 'w') | |
206 | file.write(''' | |
207 | [inject-error] | |
208 | state = "1" | |
209 | event = "%s" | |
210 | errno = "%d" | |
211 | immediately = "off" | |
212 | once = "on" | |
213 | sector = "%d" | |
214 | ||
215 | [set-state] | |
216 | state = "1" | |
217 | event = "%s" | |
218 | new_state = "2" | |
219 | ||
220 | [set-state] | |
221 | state = "2" | |
222 | event = "%s" | |
223 | new_state = "1" | |
224 | ''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event)) | |
225 | file.close() | |
226 | ||
227 | class TestEIO(TestErrors): | |
228 | def setUp(self): | |
229 | self.blkdebug_file = backing_img + ".blkdebug" | |
230 | self.create_image(backing_img, TestErrors.image_len) | |
231 | self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) | |
232 | qemu_img('create', '-f', iotests.imgfmt, | |
233 | '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' | |
234 | % (self.blkdebug_file, backing_img), | |
235 | test_img) | |
236 | self.vm = iotests.VM().add_drive(test_img) | |
237 | self.vm.launch() | |
238 | ||
239 | def tearDown(self): | |
240 | self.vm.shutdown() | |
241 | os.remove(test_img) | |
242 | os.remove(backing_img) | |
243 | os.remove(self.blkdebug_file) | |
244 | ||
245 | def test_report(self): | |
246 | self.assert_no_active_streams() | |
247 | ||
248 | result = self.vm.qmp('block-stream', device='drive0') | |
249 | self.assert_qmp(result, 'return', {}) | |
250 | ||
251 | completed = False | |
252 | error = False | |
253 | while not completed: | |
254 | for event in self.vm.get_qmp_events(wait=True): | |
255 | if event['event'] == 'BLOCK_JOB_ERROR': | |
256 | self.assert_qmp(event, 'data/device', 'drive0') | |
257 | self.assert_qmp(event, 'data/operation', 'read') | |
258 | error = True | |
259 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
260 | self.assertTrue(error, 'job completed unexpectedly') | |
261 | self.assert_qmp(event, 'data/type', 'stream') | |
262 | self.assert_qmp(event, 'data/device', 'drive0') | |
263 | self.assert_qmp(event, 'data/error', 'Input/output error') | |
264 | self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) | |
265 | self.assert_qmp(event, 'data/len', self.image_len) | |
266 | completed = True | |
267 | ||
268 | self.assert_no_active_streams() | |
269 | self.vm.shutdown() | |
270 | ||
271 | def test_ignore(self): | |
272 | self.assert_no_active_streams() | |
273 | ||
274 | result = self.vm.qmp('block-stream', device='drive0', on_error='ignore') | |
275 | self.assert_qmp(result, 'return', {}) | |
276 | ||
277 | error = False | |
278 | completed = False | |
279 | while not completed: | |
280 | for event in self.vm.get_qmp_events(wait=True): | |
281 | if event['event'] == 'BLOCK_JOB_ERROR': | |
282 | self.assert_qmp(event, 'data/device', 'drive0') | |
283 | self.assert_qmp(event, 'data/operation', 'read') | |
284 | result = self.vm.qmp('query-block-jobs') | |
285 | self.assert_qmp(result, 'return[0]/paused', False) | |
286 | error = True | |
287 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
288 | self.assertTrue(error, 'job completed unexpectedly') | |
289 | self.assert_qmp(event, 'data/type', 'stream') | |
290 | self.assert_qmp(event, 'data/device', 'drive0') | |
291 | self.assert_qmp(event, 'data/error', 'Input/output error') | |
292 | self.assert_qmp(event, 'data/offset', self.image_len) | |
293 | self.assert_qmp(event, 'data/len', self.image_len) | |
294 | completed = True | |
295 | ||
296 | self.assert_no_active_streams() | |
297 | self.vm.shutdown() | |
298 | ||
299 | def test_stop(self): | |
300 | self.assert_no_active_streams() | |
301 | ||
302 | result = self.vm.qmp('block-stream', device='drive0', on_error='stop') | |
303 | self.assert_qmp(result, 'return', {}) | |
304 | ||
305 | error = False | |
306 | completed = False | |
307 | while not completed: | |
308 | for event in self.vm.get_qmp_events(wait=True): | |
309 | if event['event'] == 'BLOCK_JOB_ERROR': | |
310 | self.assert_qmp(event, 'data/device', 'drive0') | |
311 | self.assert_qmp(event, 'data/operation', 'read') | |
312 | ||
313 | result = self.vm.qmp('query-block-jobs') | |
314 | self.assert_qmp(result, 'return[0]/paused', True) | |
315 | self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) | |
316 | self.assert_qmp(result, 'return[0]/io-status', 'failed') | |
317 | ||
318 | result = self.vm.qmp('block-job-resume', device='drive0') | |
319 | self.assert_qmp(result, 'return', {}) | |
320 | ||
321 | result = self.vm.qmp('query-block-jobs') | |
322 | self.assert_qmp(result, 'return[0]/paused', False) | |
323 | self.assert_qmp(result, 'return[0]/io-status', 'ok') | |
324 | error = True | |
325 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
326 | self.assertTrue(error, 'job completed unexpectedly') | |
327 | self.assert_qmp(event, 'data/type', 'stream') | |
328 | self.assert_qmp(event, 'data/device', 'drive0') | |
329 | self.assert_qmp_absent(event, 'data/error') | |
330 | self.assert_qmp(event, 'data/offset', self.image_len) | |
331 | self.assert_qmp(event, 'data/len', self.image_len) | |
332 | completed = True | |
333 | ||
334 | self.assert_no_active_streams() | |
335 | self.vm.shutdown() | |
336 | ||
337 | def test_enospc(self): | |
338 | self.assert_no_active_streams() | |
339 | ||
340 | result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') | |
341 | self.assert_qmp(result, 'return', {}) | |
342 | ||
343 | completed = False | |
344 | error = False | |
345 | while not completed: | |
346 | for event in self.vm.get_qmp_events(wait=True): | |
347 | if event['event'] == 'BLOCK_JOB_ERROR': | |
348 | self.assert_qmp(event, 'data/device', 'drive0') | |
349 | self.assert_qmp(event, 'data/operation', 'read') | |
350 | error = True | |
351 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
352 | self.assertTrue(error, 'job completed unexpectedly') | |
353 | self.assert_qmp(event, 'data/type', 'stream') | |
354 | self.assert_qmp(event, 'data/device', 'drive0') | |
355 | self.assert_qmp(event, 'data/error', 'Input/output error') | |
356 | self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE) | |
357 | self.assert_qmp(event, 'data/len', self.image_len) | |
358 | completed = True | |
359 | ||
360 | self.assert_no_active_streams() | |
361 | self.vm.shutdown() | |
362 | ||
363 | class TestENOSPC(TestErrors): | |
364 | def setUp(self): | |
365 | self.blkdebug_file = backing_img + ".blkdebug" | |
366 | self.create_image(backing_img, TestErrors.image_len) | |
367 | self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28) | |
368 | qemu_img('create', '-f', iotests.imgfmt, | |
369 | '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' | |
370 | % (self.blkdebug_file, backing_img), | |
371 | test_img) | |
372 | self.vm = iotests.VM().add_drive(test_img) | |
373 | self.vm.launch() | |
374 | ||
375 | def tearDown(self): | |
376 | self.vm.shutdown() | |
377 | os.remove(test_img) | |
378 | os.remove(backing_img) | |
379 | os.remove(self.blkdebug_file) | |
380 | ||
381 | def test_enospc(self): | |
382 | self.assert_no_active_streams() | |
383 | ||
384 | result = self.vm.qmp('block-stream', device='drive0', on_error='enospc') | |
385 | self.assert_qmp(result, 'return', {}) | |
386 | ||
387 | error = False | |
388 | completed = False | |
389 | while not completed: | |
390 | for event in self.vm.get_qmp_events(wait=True): | |
391 | if event['event'] == 'BLOCK_JOB_ERROR': | |
392 | self.assert_qmp(event, 'data/device', 'drive0') | |
393 | self.assert_qmp(event, 'data/operation', 'read') | |
394 | ||
395 | result = self.vm.qmp('query-block-jobs') | |
396 | self.assert_qmp(result, 'return[0]/paused', True) | |
397 | self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE) | |
398 | self.assert_qmp(result, 'return[0]/io-status', 'nospace') | |
399 | ||
400 | result = self.vm.qmp('block-job-resume', device='drive0') | |
401 | self.assert_qmp(result, 'return', {}) | |
402 | ||
403 | result = self.vm.qmp('query-block-jobs') | |
404 | self.assert_qmp(result, 'return[0]/paused', False) | |
405 | self.assert_qmp(result, 'return[0]/io-status', 'ok') | |
406 | error = True | |
407 | elif event['event'] == 'BLOCK_JOB_COMPLETED': | |
408 | self.assertTrue(error, 'job completed unexpectedly') | |
409 | self.assert_qmp(event, 'data/type', 'stream') | |
410 | self.assert_qmp(event, 'data/device', 'drive0') | |
411 | self.assert_qmp_absent(event, 'data/error') | |
412 | self.assert_qmp(event, 'data/offset', self.image_len) | |
413 | self.assert_qmp(event, 'data/len', self.image_len) | |
414 | completed = True | |
415 | ||
416 | self.assert_no_active_streams() | |
417 | self.vm.shutdown() | |
774a8850 | 418 | |
37ce63eb SH |
419 | class TestStreamStop(ImageStreamingTestCase): |
420 | image_len = 8 * 1024 * 1024 * 1024 # GB | |
421 | ||
422 | def setUp(self): | |
423 | qemu_img('create', backing_img, str(TestStreamStop.image_len)) | |
424 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) | |
425 | self.vm = iotests.VM().add_drive(test_img) | |
426 | self.vm.launch() | |
427 | ||
428 | def tearDown(self): | |
429 | self.vm.shutdown() | |
430 | os.remove(test_img) | |
431 | os.remove(backing_img) | |
432 | ||
433 | def test_stream_stop(self): | |
37ce63eb SH |
434 | self.assert_no_active_streams() |
435 | ||
db58f9c0 | 436 | result = self.vm.qmp('block-stream', device='drive0') |
37ce63eb SH |
437 | self.assert_qmp(result, 'return', {}) |
438 | ||
0fd05e8d | 439 | time.sleep(0.1) |
37ce63eb SH |
440 | events = self.vm.get_qmp_events(wait=False) |
441 | self.assertEqual(events, [], 'unexpected QMP event: %s' % events) | |
442 | ||
e425306a | 443 | self.cancel_and_wait() |
37ce63eb | 444 | |
37ce63eb SH |
445 | class TestSetSpeed(ImageStreamingTestCase): |
446 | image_len = 80 * 1024 * 1024 # MB | |
447 | ||
448 | def setUp(self): | |
449 | qemu_img('create', backing_img, str(TestSetSpeed.image_len)) | |
450 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) | |
451 | self.vm = iotests.VM().add_drive(test_img) | |
452 | self.vm.launch() | |
453 | ||
454 | def tearDown(self): | |
455 | self.vm.shutdown() | |
456 | os.remove(test_img) | |
457 | os.remove(backing_img) | |
458 | ||
e425306a SH |
459 | # This is a short performance test which is not run by default. |
460 | # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput" | |
461 | def perf_test_throughput(self): | |
37ce63eb SH |
462 | self.assert_no_active_streams() |
463 | ||
db58f9c0 | 464 | result = self.vm.qmp('block-stream', device='drive0') |
37ce63eb SH |
465 | self.assert_qmp(result, 'return', {}) |
466 | ||
e425306a | 467 | result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) |
37ce63eb SH |
468 | self.assert_qmp(result, 'return', {}) |
469 | ||
470 | completed = False | |
471 | while not completed: | |
472 | for event in self.vm.get_qmp_events(wait=True): | |
473 | if event['event'] == 'BLOCK_JOB_COMPLETED': | |
474 | self.assert_qmp(event, 'data/type', 'stream') | |
475 | self.assert_qmp(event, 'data/device', 'drive0') | |
476 | self.assert_qmp(event, 'data/offset', self.image_len) | |
477 | self.assert_qmp(event, 'data/len', self.image_len) | |
478 | completed = True | |
479 | ||
480 | self.assert_no_active_streams() | |
481 | ||
e425306a SH |
482 | def test_set_speed(self): |
483 | self.assert_no_active_streams() | |
484 | ||
485 | result = self.vm.qmp('block-stream', device='drive0') | |
486 | self.assert_qmp(result, 'return', {}) | |
487 | ||
488 | # Default speed is 0 | |
489 | result = self.vm.qmp('query-block-jobs') | |
490 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
491 | self.assert_qmp(result, 'return[0]/speed', 0) | |
492 | ||
493 | result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) | |
494 | self.assert_qmp(result, 'return', {}) | |
495 | ||
496 | # Ensure the speed we set was accepted | |
497 | result = self.vm.qmp('query-block-jobs') | |
498 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
499 | self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) | |
500 | ||
501 | self.cancel_and_wait() | |
502 | ||
503 | # Check setting speed in block-stream works | |
504 | result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024) | |
505 | self.assert_qmp(result, 'return', {}) | |
506 | ||
507 | result = self.vm.qmp('query-block-jobs') | |
508 | self.assert_qmp(result, 'return[0]/device', 'drive0') | |
509 | self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) | |
510 | ||
511 | self.cancel_and_wait() | |
512 | ||
513 | def test_set_speed_invalid(self): | |
514 | self.assert_no_active_streams() | |
515 | ||
516 | result = self.vm.qmp('block-stream', device='drive0', speed=-1) | |
58c8cce2 | 517 | self.assert_qmp(result, 'error/class', 'GenericError') |
e425306a SH |
518 | |
519 | self.assert_no_active_streams() | |
520 | ||
521 | result = self.vm.qmp('block-stream', device='drive0') | |
522 | self.assert_qmp(result, 'return', {}) | |
523 | ||
524 | result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) | |
58c8cce2 | 525 | self.assert_qmp(result, 'error/class', 'GenericError') |
e425306a SH |
526 | |
527 | self.cancel_and_wait() | |
528 | ||
37ce63eb SH |
529 | if __name__ == '__main__': |
530 | iotests.main(supported_fmts=['qcow2', 'qed']) |