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 TestMirrorResized(ImageMirroringTestCase
):
348 backing_len
= 1 * 1024 * 1024 # MB
349 image_len
= 2 * 1024 * 1024 # MB
352 self
.create_image(backing_img
, TestMirrorResized
.backing_len
)
353 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
354 qemu_img('resize', test_img
, '2M')
355 self
.vm
= iotests
.VM().add_drive(test_img
)
361 os
.remove(backing_img
)
363 os
.remove(target_img
)
367 def test_complete_top(self
):
368 self
.assert_no_active_mirrors()
370 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
372 self
.assert_qmp(result
, 'return', {})
374 self
.complete_and_wait()
375 result
= self
.vm
.qmp('query-block')
376 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
378 self
.assertTrue(self
.compare_images(test_img
, target_img
),
379 'target image does not match source after mirroring')
381 def test_complete_full(self
):
382 self
.assert_no_active_mirrors()
384 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
386 self
.assert_qmp(result
, 'return', {})
388 self
.complete_and_wait()
389 result
= self
.vm
.qmp('query-block')
390 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
392 self
.assertTrue(self
.compare_images(test_img
, target_img
),
393 'target image does not match source after mirroring')
395 class TestReadErrors(ImageMirroringTestCase
):
396 image_len
= 2 * 1024 * 1024 # MB
398 # this should be a multiple of twice the default granularity
399 # so that we hit this offset first in state 1
400 MIRROR_GRANULARITY
= 1024 * 1024
402 def create_blkdebug_file(self
, name
, event
, errno
):
403 file = open(name
, 'w')
422 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
426 self
.blkdebug_file
= backing_img
+ ".blkdebug"
427 self
.create_image(backing_img
, TestReadErrors
.image_len
)
428 self
.create_blkdebug_file(self
.blkdebug_file
, "read_aio", 5)
429 qemu_img('create', '-f', iotests
.imgfmt
,
430 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
431 % (self
.blkdebug_file
, backing_img
),
433 # Write something for tests that use sync='top'
434 qemu_io('-c', 'write %d 512' % (self
.MIRROR_GRANULARITY
+ 65536),
436 self
.vm
= iotests
.VM().add_drive(test_img
)
442 os
.remove(backing_img
)
443 os
.remove(self
.blkdebug_file
)
445 def test_report_read(self
):
446 self
.assert_no_active_mirrors()
448 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
450 self
.assert_qmp(result
, 'return', {})
455 for event
in self
.vm
.get_qmp_events(wait
=True):
456 if event
['event'] == 'BLOCK_JOB_ERROR':
457 self
.assert_qmp(event
, 'data/device', 'drive0')
458 self
.assert_qmp(event
, 'data/operation', 'read')
460 elif event
['event'] == 'BLOCK_JOB_READY':
461 self
.assertTrue(False, 'job completed unexpectedly')
462 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
463 self
.assertTrue(error
, 'job completed unexpectedly')
464 self
.assert_qmp(event
, 'data/type', 'mirror')
465 self
.assert_qmp(event
, 'data/device', 'drive0')
466 self
.assert_qmp(event
, 'data/error', 'Input/output error')
467 self
.assert_qmp(event
, 'data/len', self
.image_len
)
470 self
.assert_no_active_mirrors()
473 def test_ignore_read(self
):
474 self
.assert_no_active_mirrors()
476 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
477 target
=target_img
, on_source_error
='ignore')
478 self
.assert_qmp(result
, 'return', {})
480 event
= self
.vm
.get_qmp_event(wait
=True)
481 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
482 self
.assert_qmp(event
, 'data/device', 'drive0')
483 self
.assert_qmp(event
, 'data/operation', 'read')
484 result
= self
.vm
.qmp('query-block-jobs')
485 self
.assert_qmp(result
, 'return[0]/paused', False)
486 self
.complete_and_wait()
489 def test_large_cluster(self
):
490 self
.assert_no_active_mirrors()
492 # Test COW into the target image. The first half of the
493 # cluster at MIRROR_GRANULARITY has to be copied from
494 # backing_img, even though sync='top'.
495 qemu_img('create', '-f', iotests
.imgfmt
, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img
)
496 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
497 on_source_error
='ignore',
498 mode
='existing', target
=target_img
)
499 self
.assert_qmp(result
, 'return', {})
501 event
= self
.vm
.get_qmp_event(wait
=True)
502 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
503 self
.assert_qmp(event
, 'data/device', 'drive0')
504 self
.assert_qmp(event
, 'data/operation', 'read')
505 result
= self
.vm
.qmp('query-block-jobs')
506 self
.assert_qmp(result
, 'return[0]/paused', False)
507 self
.complete_and_wait()
510 # Detach blkdebug to compare images successfully
511 qemu_img('rebase', '-f', iotests
.imgfmt
, '-u', '-b', backing_img
, test_img
)
512 self
.assertTrue(self
.compare_images(test_img
, target_img
),
513 'target image does not match source after mirroring')
515 def test_stop_read(self
):
516 self
.assert_no_active_mirrors()
518 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
519 target
=target_img
, on_source_error
='stop')
520 self
.assert_qmp(result
, 'return', {})
525 for event
in self
.vm
.get_qmp_events(wait
=True):
526 if event
['event'] == 'BLOCK_JOB_ERROR':
527 self
.assert_qmp(event
, 'data/device', 'drive0')
528 self
.assert_qmp(event
, 'data/operation', 'read')
530 result
= self
.vm
.qmp('query-block-jobs')
531 self
.assert_qmp(result
, 'return[0]/paused', True)
532 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
534 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
535 self
.assert_qmp(result
, 'return', {})
537 elif event
['event'] == 'BLOCK_JOB_READY':
538 self
.assertTrue(error
, 'job completed unexpectedly')
539 self
.assert_qmp(event
, 'data/device', 'drive0')
542 result
= self
.vm
.qmp('query-block-jobs')
543 self
.assert_qmp(result
, 'return[0]/paused', False)
544 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
546 self
.complete_and_wait(wait_ready
=False)
547 self
.assert_no_active_mirrors()
550 class TestWriteErrors(ImageMirroringTestCase
):
551 image_len
= 2 * 1024 * 1024 # MB
553 # this should be a multiple of twice the default granularity
554 # so that we hit this offset first in state 1
555 MIRROR_GRANULARITY
= 1024 * 1024
557 def create_blkdebug_file(self
, name
, event
, errno
):
558 file = open(name
, 'w')
577 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
581 self
.blkdebug_file
= target_img
+ ".blkdebug"
582 self
.create_image(backing_img
, TestWriteErrors
.image_len
)
583 self
.create_blkdebug_file(self
.blkdebug_file
, "write_aio", 5)
584 qemu_img('create', '-f', iotests
.imgfmt
, '-obacking_file=%s' %(backing_img), test_img
)
585 self
.vm
= iotests
.VM().add_drive(test_img
)
586 self
.target_img
= 'blkdebug:%s:%s' % (self
.blkdebug_file
, target_img
)
587 qemu_img('create', '-f', iotests
.imgfmt
, '-osize=%d' %(TestWriteErrors
.image_len
), target_img
)
593 os
.remove(backing_img
)
594 os
.remove(self
.blkdebug_file
)
596 def test_report_write(self
):
597 self
.assert_no_active_mirrors()
599 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
600 mode
='existing', target
=self
.target_img
)
601 self
.assert_qmp(result
, 'return', {})
606 for event
in self
.vm
.get_qmp_events(wait
=True):
607 if event
['event'] == 'BLOCK_JOB_ERROR':
608 self
.assert_qmp(event
, 'data/device', 'drive0')
609 self
.assert_qmp(event
, 'data/operation', 'write')
611 elif event
['event'] == 'BLOCK_JOB_READY':
612 self
.assertTrue(False, 'job completed unexpectedly')
613 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
614 self
.assertTrue(error
, 'job completed unexpectedly')
615 self
.assert_qmp(event
, 'data/type', 'mirror')
616 self
.assert_qmp(event
, 'data/device', 'drive0')
617 self
.assert_qmp(event
, 'data/error', 'Input/output error')
618 self
.assert_qmp(event
, 'data/len', self
.image_len
)
621 self
.assert_no_active_mirrors()
624 def test_ignore_write(self
):
625 self
.assert_no_active_mirrors()
627 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
628 mode
='existing', target
=self
.target_img
,
629 on_target_error
='ignore')
630 self
.assert_qmp(result
, 'return', {})
632 event
= self
.vm
.get_qmp_event(wait
=True)
633 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
634 self
.assert_qmp(event
, 'data/device', 'drive0')
635 self
.assert_qmp(event
, 'data/operation', 'write')
636 result
= self
.vm
.qmp('query-block-jobs')
637 self
.assert_qmp(result
, 'return[0]/paused', False)
638 self
.complete_and_wait()
641 def test_stop_write(self
):
642 self
.assert_no_active_mirrors()
644 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
645 mode
='existing', target
=self
.target_img
,
646 on_target_error
='stop')
647 self
.assert_qmp(result
, 'return', {})
652 for event
in self
.vm
.get_qmp_events(wait
=True):
653 if event
['event'] == 'BLOCK_JOB_ERROR':
654 self
.assert_qmp(event
, 'data/device', 'drive0')
655 self
.assert_qmp(event
, 'data/operation', 'write')
657 result
= self
.vm
.qmp('query-block-jobs')
658 self
.assert_qmp(result
, 'return[0]/paused', True)
659 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
661 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
662 self
.assert_qmp(result
, 'return', {})
664 result
= self
.vm
.qmp('query-block-jobs')
665 self
.assert_qmp(result
, 'return[0]/paused', False)
666 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
668 elif event
['event'] == 'BLOCK_JOB_READY':
669 self
.assertTrue(error
, 'job completed unexpectedly')
670 self
.assert_qmp(event
, 'data/device', 'drive0')
673 self
.complete_and_wait(wait_ready
=False)
674 self
.assert_no_active_mirrors()
677 class TestSetSpeed(ImageMirroringTestCase
):
678 image_len
= 80 * 1024 * 1024 # MB
681 qemu_img('create', backing_img
, str(TestSetSpeed
.image_len
))
682 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
683 self
.vm
= iotests
.VM().add_drive(test_img
)
689 os
.remove(backing_img
)
690 os
.remove(target_img
)
692 def test_set_speed(self
):
693 self
.assert_no_active_mirrors()
695 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
697 self
.assert_qmp(result
, 'return', {})
700 result
= self
.vm
.qmp('query-block-jobs')
701 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
702 self
.assert_qmp(result
, 'return[0]/speed', 0)
704 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=8 * 1024 * 1024)
705 self
.assert_qmp(result
, 'return', {})
707 # Ensure the speed we set was accepted
708 result
= self
.vm
.qmp('query-block-jobs')
709 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
710 self
.assert_qmp(result
, 'return[0]/speed', 8 * 1024 * 1024)
712 self
.cancel_and_wait()
714 # Check setting speed in drive-mirror works
715 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
716 target
=target_img
, speed
=4*1024*1024)
717 self
.assert_qmp(result
, 'return', {})
719 result
= self
.vm
.qmp('query-block-jobs')
720 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
721 self
.assert_qmp(result
, 'return[0]/speed', 4 * 1024 * 1024)
723 self
.cancel_and_wait()
725 def test_set_speed_invalid(self
):
726 self
.assert_no_active_mirrors()
728 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
729 target
=target_img
, speed
=-1)
730 self
.assert_qmp(result
, 'error/class', 'GenericError')
732 self
.assert_no_active_mirrors()
734 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
736 self
.assert_qmp(result
, 'return', {})
738 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=-1)
739 self
.assert_qmp(result
, 'error/class', 'GenericError')
741 self
.cancel_and_wait()
743 if __name__
== '__main__':
744 iotests
.main(supported_fmts
=['qcow2', 'qed'])