3 # Tests for image mirroring.
5 # Copyright (C) 2012 Red Hat, Inc.
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.
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.
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/>.
24 from iotests
import qemu_img
, qemu_io
26 backing_img
= os
.path
.join(iotests
.test_dir
, 'backing.img')
27 target_backing_img
= os
.path
.join(iotests
.test_dir
, 'target-backing.img')
28 test_img
= os
.path
.join(iotests
.test_dir
, 'test.img')
29 target_img
= os
.path
.join(iotests
.test_dir
, 'target.img')
31 class ImageMirroringTestCase(iotests
.QMPTestCase
):
32 '''Abstract base class for image mirroring test cases'''
34 def wait_ready(self
, drive
='drive0'):
35 '''Wait until a block job BLOCK_JOB_READY event'''
38 for event
in self
.vm
.get_qmp_events(wait
=True):
39 if event
['event'] == 'BLOCK_JOB_READY':
40 self
.assert_qmp(event
, 'data/type', 'mirror')
41 self
.assert_qmp(event
, 'data/device', drive
)
44 def wait_ready_and_cancel(self
, drive
='drive0'):
45 self
.wait_ready(drive
)
46 event
= self
.cancel_and_wait()
47 self
.assertEquals(event
['event'], 'BLOCK_JOB_COMPLETED')
48 self
.assert_qmp(event
, 'data/type', 'mirror')
49 self
.assert_qmp(event
, 'data/offset', self
.image_len
)
50 self
.assert_qmp(event
, 'data/len', self
.image_len
)
52 def complete_and_wait(self
, drive
='drive0', wait_ready
=True):
53 '''Complete a block job and wait for it to finish'''
57 result
= self
.vm
.qmp('block-job-complete', device
=drive
)
58 self
.assert_qmp(result
, 'return', {})
62 for event
in self
.vm
.get_qmp_events(wait
=True):
63 if event
['event'] == 'BLOCK_JOB_COMPLETED':
64 self
.assert_qmp(event
, 'data/type', 'mirror')
65 self
.assert_qmp(event
, 'data/device', drive
)
66 self
.assert_qmp_absent(event
, 'data/error')
67 self
.assert_qmp(event
, 'data/offset', self
.image_len
)
68 self
.assert_qmp(event
, 'data/len', self
.image_len
)
71 self
.assert_no_active_block_jobs()
73 class TestSingleDrive(ImageMirroringTestCase
):
74 image_len
= 1 * 1024 * 1024 # MB
77 iotests
.create_image(backing_img
, TestSingleDrive
.image_len
)
78 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
79 self
.vm
= iotests
.VM().add_drive(test_img
)
85 os
.remove(backing_img
)
91 def test_complete(self
):
92 self
.assert_no_active_block_jobs()
94 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
96 self
.assert_qmp(result
, 'return', {})
98 self
.complete_and_wait()
99 result
= self
.vm
.qmp('query-block')
100 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
102 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
103 'target image does not match source after mirroring')
105 def test_cancel(self
):
106 self
.assert_no_active_block_jobs()
108 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
110 self
.assert_qmp(result
, 'return', {})
112 self
.cancel_and_wait(force
=True)
113 result
= self
.vm
.qmp('query-block')
114 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
117 def test_cancel_after_ready(self
):
118 self
.assert_no_active_block_jobs()
120 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
122 self
.assert_qmp(result
, 'return', {})
124 self
.wait_ready_and_cancel()
125 result
= self
.vm
.qmp('query-block')
126 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
128 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
129 'target image does not match source after mirroring')
131 def test_pause(self
):
132 self
.assert_no_active_block_jobs()
134 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
136 self
.assert_qmp(result
, 'return', {})
138 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
139 self
.assert_qmp(result
, 'return', {})
142 result
= self
.vm
.qmp('query-block-jobs')
143 offset
= self
.dictpath(result
, 'return[0]/offset')
146 result
= self
.vm
.qmp('query-block-jobs')
147 self
.assert_qmp(result
, 'return[0]/offset', offset
)
149 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
150 self
.assert_qmp(result
, 'return', {})
152 self
.complete_and_wait()
154 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
155 'target image does not match source after mirroring')
157 def test_small_buffer(self
):
158 self
.assert_no_active_block_jobs()
160 # A small buffer is rounded up automatically
161 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
162 buf_size
=4096, target
=target_img
)
163 self
.assert_qmp(result
, 'return', {})
165 self
.complete_and_wait()
166 result
= self
.vm
.qmp('query-block')
167 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
169 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
170 'target image does not match source after mirroring')
172 def test_small_buffer2(self
):
173 self
.assert_no_active_block_jobs()
175 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,size=%d'
176 % (TestSingleDrive
.image_len
, TestSingleDrive
.image_len
), target_img
)
177 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
178 buf_size
=65536, mode
='existing', target
=target_img
)
179 self
.assert_qmp(result
, 'return', {})
181 self
.complete_and_wait()
182 result
= self
.vm
.qmp('query-block')
183 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
185 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
186 'target image does not match source after mirroring')
188 def test_large_cluster(self
):
189 self
.assert_no_active_block_jobs()
191 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
192 % (TestSingleDrive
.image_len
, backing_img
), target_img
)
193 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
194 mode
='existing', target
=target_img
)
195 self
.assert_qmp(result
, 'return', {})
197 self
.complete_and_wait()
198 result
= self
.vm
.qmp('query-block')
199 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
201 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
202 'target image does not match source after mirroring')
204 def test_medium_not_found(self
):
205 result
= self
.vm
.qmp('drive-mirror', device
='ide1-cd0', sync
='full',
207 self
.assert_qmp(result
, 'error/class', 'GenericError')
209 def test_image_not_found(self
):
210 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
211 mode
='existing', target
=target_img
)
212 self
.assert_qmp(result
, 'error/class', 'GenericError')
214 def test_device_not_found(self
):
215 result
= self
.vm
.qmp('drive-mirror', device
='nonexistent', sync
='full',
217 self
.assert_qmp(result
, 'error/class', 'DeviceNotFound')
219 class TestMirrorNoBacking(ImageMirroringTestCase
):
220 image_len
= 2 * 1024 * 1024 # MB
222 def complete_and_wait(self
, drive
='drive0', wait_ready
=True):
223 iotests
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
224 return ImageMirroringTestCase
.complete_and_wait(self
, drive
, wait_ready
)
226 def compare_images(self
, img1
, img2
):
227 iotests
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
228 return iotests
.compare_images(img1
, img2
)
231 iotests
.create_image(backing_img
, TestMirrorNoBacking
.image_len
)
232 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
233 self
.vm
= iotests
.VM().add_drive(test_img
)
239 os
.remove(backing_img
)
240 os
.remove(target_backing_img
)
241 os
.remove(target_img
)
243 def test_complete(self
):
244 self
.assert_no_active_block_jobs()
246 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
247 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
248 mode
='existing', target
=target_img
)
249 self
.assert_qmp(result
, 'return', {})
251 self
.complete_and_wait()
252 result
= self
.vm
.qmp('query-block')
253 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
255 self
.assertTrue(self
.compare_images(test_img
, target_img
),
256 'target image does not match source after mirroring')
258 def test_cancel(self
):
259 self
.assert_no_active_block_jobs()
261 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
262 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
263 mode
='existing', target
=target_img
)
264 self
.assert_qmp(result
, 'return', {})
266 self
.wait_ready_and_cancel()
267 result
= self
.vm
.qmp('query-block')
268 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
270 self
.assertTrue(self
.compare_images(test_img
, target_img
),
271 'target image does not match source after mirroring')
273 def test_large_cluster(self
):
274 self
.assert_no_active_block_jobs()
276 # qemu-img create fails if the image is not there
277 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'size=%d'
278 %(TestMirrorNoBacking
.image_len
), target_backing_img
)
279 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
280 % (TestMirrorNoBacking
.image_len
, target_backing_img
), target_img
)
281 os
.remove(target_backing_img
)
283 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
284 mode
='existing', target
=target_img
)
285 self
.assert_qmp(result
, 'return', {})
287 self
.complete_and_wait()
288 result
= self
.vm
.qmp('query-block')
289 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
291 self
.assertTrue(self
.compare_images(test_img
, target_img
),
292 'target image does not match source after mirroring')
294 class TestMirrorResized(ImageMirroringTestCase
):
295 backing_len
= 1 * 1024 * 1024 # MB
296 image_len
= 2 * 1024 * 1024 # MB
299 iotests
.create_image(backing_img
, TestMirrorResized
.backing_len
)
300 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
301 qemu_img('resize', test_img
, '2M')
302 self
.vm
= iotests
.VM().add_drive(test_img
)
308 os
.remove(backing_img
)
310 os
.remove(target_img
)
314 def test_complete_top(self
):
315 self
.assert_no_active_block_jobs()
317 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
319 self
.assert_qmp(result
, 'return', {})
321 self
.complete_and_wait()
322 result
= self
.vm
.qmp('query-block')
323 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
325 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
326 'target image does not match source after mirroring')
328 def test_complete_full(self
):
329 self
.assert_no_active_block_jobs()
331 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
333 self
.assert_qmp(result
, 'return', {})
335 self
.complete_and_wait()
336 result
= self
.vm
.qmp('query-block')
337 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
339 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
340 'target image does not match source after mirroring')
342 class TestReadErrors(ImageMirroringTestCase
):
343 image_len
= 2 * 1024 * 1024 # MB
345 # this should be a multiple of twice the default granularity
346 # so that we hit this offset first in state 1
347 MIRROR_GRANULARITY
= 1024 * 1024
349 def create_blkdebug_file(self
, name
, event
, errno
):
350 file = open(name
, 'w')
369 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
373 self
.blkdebug_file
= backing_img
+ ".blkdebug"
374 iotests
.create_image(backing_img
, TestReadErrors
.image_len
)
375 self
.create_blkdebug_file(self
.blkdebug_file
, "read_aio", 5)
376 qemu_img('create', '-f', iotests
.imgfmt
,
377 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
378 % (self
.blkdebug_file
, backing_img
),
380 # Write something for tests that use sync='top'
381 qemu_io('-c', 'write %d 512' % (self
.MIRROR_GRANULARITY
+ 65536),
383 self
.vm
= iotests
.VM().add_drive(test_img
)
389 os
.remove(backing_img
)
390 os
.remove(self
.blkdebug_file
)
392 def test_report_read(self
):
393 self
.assert_no_active_block_jobs()
395 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
397 self
.assert_qmp(result
, 'return', {})
402 for event
in self
.vm
.get_qmp_events(wait
=True):
403 if event
['event'] == 'BLOCK_JOB_ERROR':
404 self
.assert_qmp(event
, 'data/device', 'drive0')
405 self
.assert_qmp(event
, 'data/operation', 'read')
407 elif event
['event'] == 'BLOCK_JOB_READY':
408 self
.assertTrue(False, 'job completed unexpectedly')
409 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
410 self
.assertTrue(error
, 'job completed unexpectedly')
411 self
.assert_qmp(event
, 'data/type', 'mirror')
412 self
.assert_qmp(event
, 'data/device', 'drive0')
413 self
.assert_qmp(event
, 'data/error', 'Input/output error')
414 self
.assert_qmp(event
, 'data/len', self
.image_len
)
417 self
.assert_no_active_block_jobs()
420 def test_ignore_read(self
):
421 self
.assert_no_active_block_jobs()
423 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
424 target
=target_img
, on_source_error
='ignore')
425 self
.assert_qmp(result
, 'return', {})
427 event
= self
.vm
.get_qmp_event(wait
=True)
428 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
429 self
.assert_qmp(event
, 'data/device', 'drive0')
430 self
.assert_qmp(event
, 'data/operation', 'read')
431 result
= self
.vm
.qmp('query-block-jobs')
432 self
.assert_qmp(result
, 'return[0]/paused', False)
433 self
.complete_and_wait()
436 def test_large_cluster(self
):
437 self
.assert_no_active_block_jobs()
439 # Test COW into the target image. The first half of the
440 # cluster at MIRROR_GRANULARITY has to be copied from
441 # backing_img, even though sync='top'.
442 qemu_img('create', '-f', iotests
.imgfmt
, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img
)
443 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
444 on_source_error
='ignore',
445 mode
='existing', target
=target_img
)
446 self
.assert_qmp(result
, 'return', {})
448 event
= self
.vm
.get_qmp_event(wait
=True)
449 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
450 self
.assert_qmp(event
, 'data/device', 'drive0')
451 self
.assert_qmp(event
, 'data/operation', 'read')
452 result
= self
.vm
.qmp('query-block-jobs')
453 self
.assert_qmp(result
, 'return[0]/paused', False)
454 self
.complete_and_wait()
457 # Detach blkdebug to compare images successfully
458 qemu_img('rebase', '-f', iotests
.imgfmt
, '-u', '-b', backing_img
, test_img
)
459 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
460 'target image does not match source after mirroring')
462 def test_stop_read(self
):
463 self
.assert_no_active_block_jobs()
465 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
466 target
=target_img
, on_source_error
='stop')
467 self
.assert_qmp(result
, 'return', {})
472 for event
in self
.vm
.get_qmp_events(wait
=True):
473 if event
['event'] == 'BLOCK_JOB_ERROR':
474 self
.assert_qmp(event
, 'data/device', 'drive0')
475 self
.assert_qmp(event
, 'data/operation', 'read')
477 result
= self
.vm
.qmp('query-block-jobs')
478 self
.assert_qmp(result
, 'return[0]/paused', True)
479 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
481 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
482 self
.assert_qmp(result
, 'return', {})
484 elif event
['event'] == 'BLOCK_JOB_READY':
485 self
.assertTrue(error
, 'job completed unexpectedly')
486 self
.assert_qmp(event
, 'data/device', 'drive0')
489 result
= self
.vm
.qmp('query-block-jobs')
490 self
.assert_qmp(result
, 'return[0]/paused', False)
491 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
493 self
.complete_and_wait(wait_ready
=False)
494 self
.assert_no_active_block_jobs()
497 class TestWriteErrors(ImageMirroringTestCase
):
498 image_len
= 2 * 1024 * 1024 # MB
500 # this should be a multiple of twice the default granularity
501 # so that we hit this offset first in state 1
502 MIRROR_GRANULARITY
= 1024 * 1024
504 def create_blkdebug_file(self
, name
, event
, errno
):
505 file = open(name
, 'w')
524 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
528 self
.blkdebug_file
= target_img
+ ".blkdebug"
529 iotests
.create_image(backing_img
, TestWriteErrors
.image_len
)
530 self
.create_blkdebug_file(self
.blkdebug_file
, "write_aio", 5)
531 qemu_img('create', '-f', iotests
.imgfmt
, '-obacking_file=%s' %(backing_img), test_img
)
532 self
.vm
= iotests
.VM().add_drive(test_img
)
533 self
.target_img
= 'blkdebug:%s:%s' % (self
.blkdebug_file
, target_img
)
534 qemu_img('create', '-f', iotests
.imgfmt
, '-osize=%d' %(TestWriteErrors
.image_len
), target_img
)
540 os
.remove(backing_img
)
541 os
.remove(self
.blkdebug_file
)
543 def test_report_write(self
):
544 self
.assert_no_active_block_jobs()
546 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
547 mode
='existing', target
=self
.target_img
)
548 self
.assert_qmp(result
, 'return', {})
553 for event
in self
.vm
.get_qmp_events(wait
=True):
554 if event
['event'] == 'BLOCK_JOB_ERROR':
555 self
.assert_qmp(event
, 'data/device', 'drive0')
556 self
.assert_qmp(event
, 'data/operation', 'write')
558 elif event
['event'] == 'BLOCK_JOB_READY':
559 self
.assertTrue(False, 'job completed unexpectedly')
560 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
561 self
.assertTrue(error
, 'job completed unexpectedly')
562 self
.assert_qmp(event
, 'data/type', 'mirror')
563 self
.assert_qmp(event
, 'data/device', 'drive0')
564 self
.assert_qmp(event
, 'data/error', 'Input/output error')
565 self
.assert_qmp(event
, 'data/len', self
.image_len
)
568 self
.assert_no_active_block_jobs()
571 def test_ignore_write(self
):
572 self
.assert_no_active_block_jobs()
574 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
575 mode
='existing', target
=self
.target_img
,
576 on_target_error
='ignore')
577 self
.assert_qmp(result
, 'return', {})
579 event
= self
.vm
.get_qmp_event(wait
=True)
580 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
581 self
.assert_qmp(event
, 'data/device', 'drive0')
582 self
.assert_qmp(event
, 'data/operation', 'write')
583 result
= self
.vm
.qmp('query-block-jobs')
584 self
.assert_qmp(result
, 'return[0]/paused', False)
585 self
.complete_and_wait()
588 def test_stop_write(self
):
589 self
.assert_no_active_block_jobs()
591 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
592 mode
='existing', target
=self
.target_img
,
593 on_target_error
='stop')
594 self
.assert_qmp(result
, 'return', {})
599 for event
in self
.vm
.get_qmp_events(wait
=True):
600 if event
['event'] == 'BLOCK_JOB_ERROR':
601 self
.assert_qmp(event
, 'data/device', 'drive0')
602 self
.assert_qmp(event
, 'data/operation', 'write')
604 result
= self
.vm
.qmp('query-block-jobs')
605 self
.assert_qmp(result
, 'return[0]/paused', True)
606 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
608 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
609 self
.assert_qmp(result
, 'return', {})
611 result
= self
.vm
.qmp('query-block-jobs')
612 self
.assert_qmp(result
, 'return[0]/paused', False)
613 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
615 elif event
['event'] == 'BLOCK_JOB_READY':
616 self
.assertTrue(error
, 'job completed unexpectedly')
617 self
.assert_qmp(event
, 'data/device', 'drive0')
620 self
.complete_and_wait(wait_ready
=False)
621 self
.assert_no_active_block_jobs()
624 class TestSetSpeed(ImageMirroringTestCase
):
625 image_len
= 80 * 1024 * 1024 # MB
628 qemu_img('create', backing_img
, str(TestSetSpeed
.image_len
))
629 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
630 self
.vm
= iotests
.VM().add_drive(test_img
)
636 os
.remove(backing_img
)
637 os
.remove(target_img
)
639 def test_set_speed(self
):
640 self
.assert_no_active_block_jobs()
642 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
644 self
.assert_qmp(result
, 'return', {})
647 result
= self
.vm
.qmp('query-block-jobs')
648 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
649 self
.assert_qmp(result
, 'return[0]/speed', 0)
651 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=8 * 1024 * 1024)
652 self
.assert_qmp(result
, 'return', {})
654 # Ensure the speed we set was accepted
655 result
= self
.vm
.qmp('query-block-jobs')
656 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
657 self
.assert_qmp(result
, 'return[0]/speed', 8 * 1024 * 1024)
659 self
.wait_ready_and_cancel()
661 # Check setting speed in drive-mirror works
662 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
663 target
=target_img
, speed
=4*1024*1024)
664 self
.assert_qmp(result
, 'return', {})
666 result
= self
.vm
.qmp('query-block-jobs')
667 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
668 self
.assert_qmp(result
, 'return[0]/speed', 4 * 1024 * 1024)
670 self
.wait_ready_and_cancel()
672 def test_set_speed_invalid(self
):
673 self
.assert_no_active_block_jobs()
675 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
676 target
=target_img
, speed
=-1)
677 self
.assert_qmp(result
, 'error/class', 'GenericError')
679 self
.assert_no_active_block_jobs()
681 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
683 self
.assert_qmp(result
, 'return', {})
685 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=-1)
686 self
.assert_qmp(result
, 'error/class', 'GenericError')
688 self
.wait_ready_and_cancel()
690 if __name__
== '__main__':
691 iotests
.main(supported_fmts
=['qcow2', 'qed'])