]>
git.proxmox.com Git - qemu.git/blob - tests/qemu-iotests/041
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
27 backing_img
= os
.path
.join(iotests
.test_dir
, 'backing.img')
28 target_backing_img
= os
.path
.join(iotests
.test_dir
, 'target-backing.img')
29 test_img
= os
.path
.join(iotests
.test_dir
, 'test.img')
30 target_img
= os
.path
.join(iotests
.test_dir
, 'target.img')
32 class ImageMirroringTestCase(iotests
.QMPTestCase
):
33 '''Abstract base class for image mirroring test cases'''
35 def assert_no_active_mirrors(self
):
36 result
= self
.vm
.qmp('query-block-jobs')
37 self
.assert_qmp(result
, 'return', [])
39 def cancel_and_wait(self
, drive
='drive0', wait_ready
=True):
40 '''Cancel a block job and wait for it to finish'''
44 for event
in self
.vm
.get_qmp_events(wait
=True):
45 if event
['event'] == 'BLOCK_JOB_READY':
46 self
.assert_qmp(event
, 'data/type', 'mirror')
47 self
.assert_qmp(event
, 'data/device', drive
)
50 result
= self
.vm
.qmp('block-job-cancel', device
=drive
,
52 self
.assert_qmp(result
, 'return', {})
56 for event
in self
.vm
.get_qmp_events(wait
=True):
57 if event
['event'] == 'BLOCK_JOB_COMPLETED' or \
58 event
['event'] == 'BLOCK_JOB_CANCELLED':
59 self
.assert_qmp(event
, 'data/type', 'mirror')
60 self
.assert_qmp(event
, 'data/device', drive
)
62 self
.assertEquals(event
['event'], 'BLOCK_JOB_COMPLETED')
63 self
.assert_qmp(event
, 'data/offset', self
.image_len
)
64 self
.assert_qmp(event
, 'data/len', self
.image_len
)
67 self
.assert_no_active_mirrors()
69 def complete_and_wait(self
, drive
='drive0', wait_ready
=True):
70 '''Complete a block job and wait for it to finish'''
74 for event
in self
.vm
.get_qmp_events(wait
=True):
75 if event
['event'] == 'BLOCK_JOB_READY':
76 self
.assert_qmp(event
, 'data/type', 'mirror')
77 self
.assert_qmp(event
, 'data/device', drive
)
80 result
= self
.vm
.qmp('block-job-complete', device
=drive
)
81 self
.assert_qmp(result
, 'return', {})
85 for event
in self
.vm
.get_qmp_events(wait
=True):
86 if event
['event'] == 'BLOCK_JOB_COMPLETED':
87 self
.assert_qmp(event
, 'data/type', 'mirror')
88 self
.assert_qmp(event
, 'data/device', drive
)
89 self
.assert_qmp_absent(event
, 'data/error')
90 self
.assert_qmp(event
, 'data/offset', self
.image_len
)
91 self
.assert_qmp(event
, 'data/len', self
.image_len
)
94 self
.assert_no_active_mirrors()
96 def create_image(self
, name
, size
):
97 file = open(name
, 'w')
100 sector
= struct
.pack('>l504xl', i
/ 512, i
/ 512)
105 def compare_images(self
, img1
, img2
):
107 qemu_img('convert', '-f', iotests
.imgfmt
, '-O', 'raw', img1
, img1
+ '.raw')
108 qemu_img('convert', '-f', iotests
.imgfmt
, '-O', 'raw', img2
, img2
+ '.raw')
109 file1
= open(img1
+ '.raw', 'r')
110 file2
= open(img2
+ '.raw', 'r')
111 return file1
.read() == file2
.read()
113 if file1
is not None:
115 if file2
is not None:
118 os
.remove(img1
+ '.raw')
122 os
.remove(img2
+ '.raw')
126 class TestSingleDrive(ImageMirroringTestCase
):
127 image_len
= 1 * 1024 * 1024 # MB
130 self
.create_image(backing_img
, TestSingleDrive
.image_len
)
131 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
132 self
.vm
= iotests
.VM().add_drive(test_img
)
138 os
.remove(backing_img
)
140 os
.remove(target_img
)
144 def test_complete(self
):
145 self
.assert_no_active_mirrors()
147 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
149 self
.assert_qmp(result
, 'return', {})
151 self
.complete_and_wait()
152 result
= self
.vm
.qmp('query-block')
153 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
155 self
.assertTrue(self
.compare_images(test_img
, target_img
),
156 'target image does not match source after mirroring')
158 def test_cancel(self
):
159 self
.assert_no_active_mirrors()
161 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
163 self
.assert_qmp(result
, 'return', {})
165 self
.cancel_and_wait(wait_ready
=False)
166 result
= self
.vm
.qmp('query-block')
167 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
170 def test_cancel_after_ready(self
):
171 self
.assert_no_active_mirrors()
173 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
175 self
.assert_qmp(result
, 'return', {})
177 self
.cancel_and_wait()
178 result
= self
.vm
.qmp('query-block')
179 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
181 self
.assertTrue(self
.compare_images(test_img
, target_img
),
182 'target image does not match source after mirroring')
184 def test_pause(self
):
185 self
.assert_no_active_mirrors()
187 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
189 self
.assert_qmp(result
, 'return', {})
191 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
192 self
.assert_qmp(result
, 'return', {})
195 result
= self
.vm
.qmp('query-block-jobs')
196 offset
= self
.dictpath(result
, 'return[0]/offset')
199 result
= self
.vm
.qmp('query-block-jobs')
200 self
.assert_qmp(result
, 'return[0]/offset', offset
)
202 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
203 self
.assert_qmp(result
, 'return', {})
205 self
.complete_and_wait()
207 self
.assertTrue(self
.compare_images(test_img
, target_img
),
208 'target image does not match source after mirroring')
210 def test_small_buffer(self
):
211 self
.assert_no_active_mirrors()
213 # A small buffer is rounded up automatically
214 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
215 buf_size
=4096, target
=target_img
)
216 self
.assert_qmp(result
, 'return', {})
218 self
.complete_and_wait()
219 result
= self
.vm
.qmp('query-block')
220 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
222 self
.assertTrue(self
.compare_images(test_img
, target_img
),
223 'target image does not match source after mirroring')
225 def test_small_buffer2(self
):
226 self
.assert_no_active_mirrors()
228 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,size=%d'
229 % (TestSingleDrive
.image_len
, TestSingleDrive
.image_len
), target_img
)
230 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
231 buf_size
=65536, mode
='existing', target
=target_img
)
232 self
.assert_qmp(result
, 'return', {})
234 self
.complete_and_wait()
235 result
= self
.vm
.qmp('query-block')
236 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
238 self
.assertTrue(self
.compare_images(test_img
, target_img
),
239 'target image does not match source after mirroring')
241 def test_large_cluster(self
):
242 self
.assert_no_active_mirrors()
244 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
245 % (TestSingleDrive
.image_len
, backing_img
), target_img
)
246 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
247 mode
='existing', target
=target_img
)
248 self
.assert_qmp(result
, 'return', {})
250 self
.complete_and_wait()
251 result
= self
.vm
.qmp('query-block')
252 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
254 self
.assertTrue(self
.compare_images(test_img
, target_img
),
255 'target image does not match source after mirroring')
257 def test_medium_not_found(self
):
258 result
= self
.vm
.qmp('drive-mirror', device
='ide1-cd0', sync
='full',
260 self
.assert_qmp(result
, 'error/class', 'GenericError')
262 def test_image_not_found(self
):
263 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
264 mode
='existing', target
=target_img
)
265 self
.assert_qmp(result
, 'error/class', 'GenericError')
267 def test_device_not_found(self
):
268 result
= self
.vm
.qmp('drive-mirror', device
='nonexistent', sync
='full',
270 self
.assert_qmp(result
, 'error/class', 'DeviceNotFound')
272 class TestMirrorNoBacking(ImageMirroringTestCase
):
273 image_len
= 2 * 1024 * 1024 # MB
275 def complete_and_wait(self
, drive
='drive0', wait_ready
=True):
276 self
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
277 return ImageMirroringTestCase
.complete_and_wait(self
, drive
, wait_ready
)
279 def compare_images(self
, img1
, img2
):
280 self
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
281 return ImageMirroringTestCase
.compare_images(self
, img1
, img2
)
284 self
.create_image(backing_img
, TestMirrorNoBacking
.image_len
)
285 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
286 self
.vm
= iotests
.VM().add_drive(test_img
)
292 os
.remove(backing_img
)
293 os
.remove(target_backing_img
)
294 os
.remove(target_img
)
296 def test_complete(self
):
297 self
.assert_no_active_mirrors()
299 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
300 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
301 mode
='existing', target
=target_img
)
302 self
.assert_qmp(result
, 'return', {})
304 self
.complete_and_wait()
305 result
= self
.vm
.qmp('query-block')
306 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
308 self
.assertTrue(self
.compare_images(test_img
, target_img
),
309 'target image does not match source after mirroring')
311 def test_cancel(self
):
312 self
.assert_no_active_mirrors()
314 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
315 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
316 mode
='existing', target
=target_img
)
317 self
.assert_qmp(result
, 'return', {})
319 self
.cancel_and_wait()
320 result
= self
.vm
.qmp('query-block')
321 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
323 self
.assertTrue(self
.compare_images(test_img
, target_img
),
324 'target image does not match source after mirroring')
326 def test_large_cluster(self
):
327 self
.assert_no_active_mirrors()
329 # qemu-img create fails if the image is not there
330 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'size=%d'
331 %(TestMirrorNoBacking
.image_len
), target_backing_img
)
332 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
333 % (TestMirrorNoBacking
.image_len
, target_backing_img
), target_img
)
334 os
.remove(target_backing_img
)
336 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
337 mode
='existing', target
=target_img
)
338 self
.assert_qmp(result
, 'return', {})
340 self
.complete_and_wait()
341 result
= self
.vm
.qmp('query-block')
342 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
344 self
.assertTrue(self
.compare_images(test_img
, target_img
),
345 'target image does not match source after mirroring')
347 class TestReadErrors(ImageMirroringTestCase
):
348 image_len
= 2 * 1024 * 1024 # MB
350 # this should be a multiple of twice the default granularity
351 # so that we hit this offset first in state 1
352 MIRROR_GRANULARITY
= 1024 * 1024
354 def create_blkdebug_file(self
, name
, event
, errno
):
355 file = open(name
, 'w')
374 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
378 self
.blkdebug_file
= backing_img
+ ".blkdebug"
379 self
.create_image(backing_img
, TestReadErrors
.image_len
)
380 self
.create_blkdebug_file(self
.blkdebug_file
, "read_aio", 5)
381 qemu_img('create', '-f', iotests
.imgfmt
,
382 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
383 % (self
.blkdebug_file
, backing_img
),
385 # Write something for tests that use sync='top'
386 qemu_io('-c', 'write %d 512' % (self
.MIRROR_GRANULARITY
+ 65536),
388 self
.vm
= iotests
.VM().add_drive(test_img
)
394 os
.remove(backing_img
)
395 os
.remove(self
.blkdebug_file
)
397 def test_report_read(self
):
398 self
.assert_no_active_mirrors()
400 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
402 self
.assert_qmp(result
, 'return', {})
407 for event
in self
.vm
.get_qmp_events(wait
=True):
408 if event
['event'] == 'BLOCK_JOB_ERROR':
409 self
.assert_qmp(event
, 'data/device', 'drive0')
410 self
.assert_qmp(event
, 'data/operation', 'read')
412 elif event
['event'] == 'BLOCK_JOB_READY':
413 self
.assertTrue(False, 'job completed unexpectedly')
414 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
415 self
.assertTrue(error
, 'job completed unexpectedly')
416 self
.assert_qmp(event
, 'data/type', 'mirror')
417 self
.assert_qmp(event
, 'data/device', 'drive0')
418 self
.assert_qmp(event
, 'data/error', 'Input/output error')
419 self
.assert_qmp(event
, 'data/len', self
.image_len
)
422 self
.assert_no_active_mirrors()
425 def test_ignore_read(self
):
426 self
.assert_no_active_mirrors()
428 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
429 target
=target_img
, on_source_error
='ignore')
430 self
.assert_qmp(result
, 'return', {})
432 event
= self
.vm
.get_qmp_event(wait
=True)
433 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
434 self
.assert_qmp(event
, 'data/device', 'drive0')
435 self
.assert_qmp(event
, 'data/operation', 'read')
436 result
= self
.vm
.qmp('query-block-jobs')
437 self
.assert_qmp(result
, 'return[0]/paused', False)
438 self
.complete_and_wait()
441 def test_large_cluster(self
):
442 self
.assert_no_active_mirrors()
444 # Test COW into the target image. The first half of the
445 # cluster at MIRROR_GRANULARITY has to be copied from
446 # backing_img, even though sync='top'.
447 qemu_img('create', '-f', iotests
.imgfmt
, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img
)
448 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
449 on_source_error
='ignore',
450 mode
='existing', target
=target_img
)
451 self
.assert_qmp(result
, 'return', {})
453 event
= self
.vm
.get_qmp_event(wait
=True)
454 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
455 self
.assert_qmp(event
, 'data/device', 'drive0')
456 self
.assert_qmp(event
, 'data/operation', 'read')
457 result
= self
.vm
.qmp('query-block-jobs')
458 self
.assert_qmp(result
, 'return[0]/paused', False)
459 self
.complete_and_wait()
462 # Detach blkdebug to compare images successfully
463 qemu_img('rebase', '-f', iotests
.imgfmt
, '-u', '-b', backing_img
, test_img
)
464 self
.assertTrue(self
.compare_images(test_img
, target_img
),
465 'target image does not match source after mirroring')
467 def test_stop_read(self
):
468 self
.assert_no_active_mirrors()
470 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
471 target
=target_img
, on_source_error
='stop')
472 self
.assert_qmp(result
, 'return', {})
477 for event
in self
.vm
.get_qmp_events(wait
=True):
478 if event
['event'] == 'BLOCK_JOB_ERROR':
479 self
.assert_qmp(event
, 'data/device', 'drive0')
480 self
.assert_qmp(event
, 'data/operation', 'read')
482 result
= self
.vm
.qmp('query-block-jobs')
483 self
.assert_qmp(result
, 'return[0]/paused', True)
484 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
486 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
487 self
.assert_qmp(result
, 'return', {})
489 elif event
['event'] == 'BLOCK_JOB_READY':
490 self
.assertTrue(error
, 'job completed unexpectedly')
491 self
.assert_qmp(event
, 'data/device', 'drive0')
494 result
= self
.vm
.qmp('query-block-jobs')
495 self
.assert_qmp(result
, 'return[0]/paused', False)
496 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
498 self
.complete_and_wait(wait_ready
=False)
499 self
.assert_no_active_mirrors()
502 class TestWriteErrors(ImageMirroringTestCase
):
503 image_len
= 2 * 1024 * 1024 # MB
505 # this should be a multiple of twice the default granularity
506 # so that we hit this offset first in state 1
507 MIRROR_GRANULARITY
= 1024 * 1024
509 def create_blkdebug_file(self
, name
, event
, errno
):
510 file = open(name
, 'w')
529 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
533 self
.blkdebug_file
= target_img
+ ".blkdebug"
534 self
.create_image(backing_img
, TestWriteErrors
.image_len
)
535 self
.create_blkdebug_file(self
.blkdebug_file
, "write_aio", 5)
536 qemu_img('create', '-f', iotests
.imgfmt
, '-obacking_file=%s' %(backing_img), test_img
)
537 self
.vm
= iotests
.VM().add_drive(test_img
)
538 self
.target_img
= 'blkdebug:%s:%s' % (self
.blkdebug_file
, target_img
)
539 qemu_img('create', '-f', iotests
.imgfmt
, '-osize=%d' %(TestWriteErrors
.image_len
), target_img
)
545 os
.remove(backing_img
)
546 os
.remove(self
.blkdebug_file
)
548 def test_report_write(self
):
549 self
.assert_no_active_mirrors()
551 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
552 mode
='existing', target
=self
.target_img
)
553 self
.assert_qmp(result
, 'return', {})
558 for event
in self
.vm
.get_qmp_events(wait
=True):
559 if event
['event'] == 'BLOCK_JOB_ERROR':
560 self
.assert_qmp(event
, 'data/device', 'drive0')
561 self
.assert_qmp(event
, 'data/operation', 'write')
563 elif event
['event'] == 'BLOCK_JOB_READY':
564 self
.assertTrue(False, 'job completed unexpectedly')
565 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
566 self
.assertTrue(error
, 'job completed unexpectedly')
567 self
.assert_qmp(event
, 'data/type', 'mirror')
568 self
.assert_qmp(event
, 'data/device', 'drive0')
569 self
.assert_qmp(event
, 'data/error', 'Input/output error')
570 self
.assert_qmp(event
, 'data/len', self
.image_len
)
573 self
.assert_no_active_mirrors()
576 def test_ignore_write(self
):
577 self
.assert_no_active_mirrors()
579 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
580 mode
='existing', target
=self
.target_img
,
581 on_target_error
='ignore')
582 self
.assert_qmp(result
, 'return', {})
584 event
= self
.vm
.get_qmp_event(wait
=True)
585 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
586 self
.assert_qmp(event
, 'data/device', 'drive0')
587 self
.assert_qmp(event
, 'data/operation', 'write')
588 result
= self
.vm
.qmp('query-block-jobs')
589 self
.assert_qmp(result
, 'return[0]/paused', False)
590 self
.complete_and_wait()
593 def test_stop_write(self
):
594 self
.assert_no_active_mirrors()
596 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
597 mode
='existing', target
=self
.target_img
,
598 on_target_error
='stop')
599 self
.assert_qmp(result
, 'return', {})
604 for event
in self
.vm
.get_qmp_events(wait
=True):
605 if event
['event'] == 'BLOCK_JOB_ERROR':
606 self
.assert_qmp(event
, 'data/device', 'drive0')
607 self
.assert_qmp(event
, 'data/operation', 'write')
609 result
= self
.vm
.qmp('query-block-jobs')
610 self
.assert_qmp(result
, 'return[0]/paused', True)
611 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
613 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
614 self
.assert_qmp(result
, 'return', {})
616 result
= self
.vm
.qmp('query-block-jobs')
617 self
.assert_qmp(result
, 'return[0]/paused', False)
618 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
620 elif event
['event'] == 'BLOCK_JOB_READY':
621 self
.assertTrue(error
, 'job completed unexpectedly')
622 self
.assert_qmp(event
, 'data/device', 'drive0')
625 self
.complete_and_wait(wait_ready
=False)
626 self
.assert_no_active_mirrors()
629 class TestSetSpeed(ImageMirroringTestCase
):
630 image_len
= 80 * 1024 * 1024 # MB
633 qemu_img('create', backing_img
, str(TestSetSpeed
.image_len
))
634 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
635 self
.vm
= iotests
.VM().add_drive(test_img
)
641 os
.remove(backing_img
)
642 os
.remove(target_img
)
644 def test_set_speed(self
):
645 self
.assert_no_active_mirrors()
647 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
649 self
.assert_qmp(result
, 'return', {})
652 result
= self
.vm
.qmp('query-block-jobs')
653 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
654 self
.assert_qmp(result
, 'return[0]/speed', 0)
656 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=8 * 1024 * 1024)
657 self
.assert_qmp(result
, 'return', {})
659 # Ensure the speed we set was accepted
660 result
= self
.vm
.qmp('query-block-jobs')
661 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
662 self
.assert_qmp(result
, 'return[0]/speed', 8 * 1024 * 1024)
664 self
.cancel_and_wait()
666 # Check setting speed in drive-mirror works
667 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
668 target
=target_img
, speed
=4*1024*1024)
669 self
.assert_qmp(result
, 'return', {})
671 result
= self
.vm
.qmp('query-block-jobs')
672 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
673 self
.assert_qmp(result
, 'return[0]/speed', 4 * 1024 * 1024)
675 self
.cancel_and_wait()
677 def test_set_speed_invalid(self
):
678 self
.assert_no_active_mirrors()
680 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
681 target
=target_img
, speed
=-1)
682 self
.assert_qmp(result
, 'error/class', 'GenericError')
684 self
.assert_no_active_mirrors()
686 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
688 self
.assert_qmp(result
, 'return', {})
690 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=-1)
691 self
.assert_qmp(result
, 'error/class', 'GenericError')
693 self
.cancel_and_wait()
695 if __name__
== '__main__':
696 iotests
.main(supported_fmts
=['qcow2', 'qed'])