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', {})
60 event
= self
.wait_until_completed()
61 self
.assert_qmp(event
, 'data/type', 'mirror')
63 class TestSingleDrive(ImageMirroringTestCase
):
64 image_len
= 1 * 1024 * 1024 # MB
67 iotests
.create_image(backing_img
, TestSingleDrive
.image_len
)
68 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
69 self
.vm
= iotests
.VM().add_drive(test_img
)
75 os
.remove(backing_img
)
81 def test_complete(self
):
82 self
.assert_no_active_block_jobs()
84 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
86 self
.assert_qmp(result
, 'return', {})
88 self
.complete_and_wait()
89 result
= self
.vm
.qmp('query-block')
90 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
92 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
93 'target image does not match source after mirroring')
95 def test_cancel(self
):
96 self
.assert_no_active_block_jobs()
98 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
100 self
.assert_qmp(result
, 'return', {})
102 self
.cancel_and_wait(force
=True)
103 result
= self
.vm
.qmp('query-block')
104 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
107 def test_cancel_after_ready(self
):
108 self
.assert_no_active_block_jobs()
110 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
112 self
.assert_qmp(result
, 'return', {})
114 self
.wait_ready_and_cancel()
115 result
= self
.vm
.qmp('query-block')
116 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
118 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
119 'target image does not match source after mirroring')
121 def test_pause(self
):
122 self
.assert_no_active_block_jobs()
124 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
126 self
.assert_qmp(result
, 'return', {})
128 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
129 self
.assert_qmp(result
, 'return', {})
132 result
= self
.vm
.qmp('query-block-jobs')
133 offset
= self
.dictpath(result
, 'return[0]/offset')
136 result
= self
.vm
.qmp('query-block-jobs')
137 self
.assert_qmp(result
, 'return[0]/offset', offset
)
139 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
140 self
.assert_qmp(result
, 'return', {})
142 self
.complete_and_wait()
144 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
145 'target image does not match source after mirroring')
147 def test_small_buffer(self
):
148 self
.assert_no_active_block_jobs()
150 # A small buffer is rounded up automatically
151 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
152 buf_size
=4096, target
=target_img
)
153 self
.assert_qmp(result
, 'return', {})
155 self
.complete_and_wait()
156 result
= self
.vm
.qmp('query-block')
157 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
159 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
160 'target image does not match source after mirroring')
162 def test_small_buffer2(self
):
163 self
.assert_no_active_block_jobs()
165 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,size=%d'
166 % (TestSingleDrive
.image_len
, TestSingleDrive
.image_len
), target_img
)
167 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
168 buf_size
=65536, mode
='existing', target
=target_img
)
169 self
.assert_qmp(result
, 'return', {})
171 self
.complete_and_wait()
172 result
= self
.vm
.qmp('query-block')
173 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
175 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
176 'target image does not match source after mirroring')
178 def test_large_cluster(self
):
179 self
.assert_no_active_block_jobs()
181 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
182 % (TestSingleDrive
.image_len
, backing_img
), target_img
)
183 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
184 mode
='existing', target
=target_img
)
185 self
.assert_qmp(result
, 'return', {})
187 self
.complete_and_wait()
188 result
= self
.vm
.qmp('query-block')
189 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
191 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
192 'target image does not match source after mirroring')
194 def test_medium_not_found(self
):
195 result
= self
.vm
.qmp('drive-mirror', device
='ide1-cd0', sync
='full',
197 self
.assert_qmp(result
, 'error/class', 'GenericError')
199 def test_image_not_found(self
):
200 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
201 mode
='existing', target
=target_img
)
202 self
.assert_qmp(result
, 'error/class', 'GenericError')
204 def test_device_not_found(self
):
205 result
= self
.vm
.qmp('drive-mirror', device
='nonexistent', sync
='full',
207 self
.assert_qmp(result
, 'error/class', 'DeviceNotFound')
209 class TestMirrorNoBacking(ImageMirroringTestCase
):
210 image_len
= 2 * 1024 * 1024 # MB
212 def complete_and_wait(self
, drive
='drive0', wait_ready
=True):
213 iotests
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
214 return ImageMirroringTestCase
.complete_and_wait(self
, drive
, wait_ready
)
216 def compare_images(self
, img1
, img2
):
217 iotests
.create_image(target_backing_img
, TestMirrorNoBacking
.image_len
)
218 return iotests
.compare_images(img1
, img2
)
221 iotests
.create_image(backing_img
, TestMirrorNoBacking
.image_len
)
222 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
223 self
.vm
= iotests
.VM().add_drive(test_img
)
229 os
.remove(backing_img
)
230 os
.remove(target_backing_img
)
231 os
.remove(target_img
)
233 def test_complete(self
):
234 self
.assert_no_active_block_jobs()
236 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
237 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
238 mode
='existing', target
=target_img
)
239 self
.assert_qmp(result
, 'return', {})
241 self
.complete_and_wait()
242 result
= self
.vm
.qmp('query-block')
243 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
245 self
.assertTrue(self
.compare_images(test_img
, target_img
),
246 'target image does not match source after mirroring')
248 def test_cancel(self
):
249 self
.assert_no_active_block_jobs()
251 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, target_img
)
252 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
253 mode
='existing', target
=target_img
)
254 self
.assert_qmp(result
, 'return', {})
256 self
.wait_ready_and_cancel()
257 result
= self
.vm
.qmp('query-block')
258 self
.assert_qmp(result
, 'return[0]/inserted/file', test_img
)
260 self
.assertTrue(self
.compare_images(test_img
, target_img
),
261 'target image does not match source after mirroring')
263 def test_large_cluster(self
):
264 self
.assert_no_active_block_jobs()
266 # qemu-img create fails if the image is not there
267 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'size=%d'
268 %(TestMirrorNoBacking
.image_len
), target_backing_img
)
269 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'cluster_size=%d,backing_file=%s'
270 % (TestMirrorNoBacking
.image_len
, target_backing_img
), target_img
)
271 os
.remove(target_backing_img
)
273 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
274 mode
='existing', target
=target_img
)
275 self
.assert_qmp(result
, 'return', {})
277 self
.complete_and_wait()
278 result
= self
.vm
.qmp('query-block')
279 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
281 self
.assertTrue(self
.compare_images(test_img
, target_img
),
282 'target image does not match source after mirroring')
284 class TestMirrorResized(ImageMirroringTestCase
):
285 backing_len
= 1 * 1024 * 1024 # MB
286 image_len
= 2 * 1024 * 1024 # MB
289 iotests
.create_image(backing_img
, TestMirrorResized
.backing_len
)
290 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
291 qemu_img('resize', test_img
, '2M')
292 self
.vm
= iotests
.VM().add_drive(test_img
)
298 os
.remove(backing_img
)
300 os
.remove(target_img
)
304 def test_complete_top(self
):
305 self
.assert_no_active_block_jobs()
307 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
309 self
.assert_qmp(result
, 'return', {})
311 self
.complete_and_wait()
312 result
= self
.vm
.qmp('query-block')
313 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
315 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
316 'target image does not match source after mirroring')
318 def test_complete_full(self
):
319 self
.assert_no_active_block_jobs()
321 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
323 self
.assert_qmp(result
, 'return', {})
325 self
.complete_and_wait()
326 result
= self
.vm
.qmp('query-block')
327 self
.assert_qmp(result
, 'return[0]/inserted/file', target_img
)
329 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
330 'target image does not match source after mirroring')
332 class TestReadErrors(ImageMirroringTestCase
):
333 image_len
= 2 * 1024 * 1024 # MB
335 # this should be a multiple of twice the default granularity
336 # so that we hit this offset first in state 1
337 MIRROR_GRANULARITY
= 1024 * 1024
339 def create_blkdebug_file(self
, name
, event
, errno
):
340 file = open(name
, 'w')
359 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
363 self
.blkdebug_file
= backing_img
+ ".blkdebug"
364 iotests
.create_image(backing_img
, TestReadErrors
.image_len
)
365 self
.create_blkdebug_file(self
.blkdebug_file
, "read_aio", 5)
366 qemu_img('create', '-f', iotests
.imgfmt
,
367 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
368 % (self
.blkdebug_file
, backing_img
),
370 # Write something for tests that use sync='top'
371 qemu_io('-c', 'write %d 512' % (self
.MIRROR_GRANULARITY
+ 65536),
373 self
.vm
= iotests
.VM().add_drive(test_img
)
379 os
.remove(backing_img
)
380 os
.remove(self
.blkdebug_file
)
382 def test_report_read(self
):
383 self
.assert_no_active_block_jobs()
385 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
387 self
.assert_qmp(result
, 'return', {})
392 for event
in self
.vm
.get_qmp_events(wait
=True):
393 if event
['event'] == 'BLOCK_JOB_ERROR':
394 self
.assert_qmp(event
, 'data/device', 'drive0')
395 self
.assert_qmp(event
, 'data/operation', 'read')
397 elif event
['event'] == 'BLOCK_JOB_READY':
398 self
.assertTrue(False, 'job completed unexpectedly')
399 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
400 self
.assertTrue(error
, 'job completed unexpectedly')
401 self
.assert_qmp(event
, 'data/type', 'mirror')
402 self
.assert_qmp(event
, 'data/device', 'drive0')
403 self
.assert_qmp(event
, 'data/error', 'Input/output error')
404 self
.assert_qmp(event
, 'data/len', self
.image_len
)
407 self
.assert_no_active_block_jobs()
410 def test_ignore_read(self
):
411 self
.assert_no_active_block_jobs()
413 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
414 target
=target_img
, on_source_error
='ignore')
415 self
.assert_qmp(result
, 'return', {})
417 event
= self
.vm
.get_qmp_event(wait
=True)
418 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
419 self
.assert_qmp(event
, 'data/device', 'drive0')
420 self
.assert_qmp(event
, 'data/operation', 'read')
421 result
= self
.vm
.qmp('query-block-jobs')
422 self
.assert_qmp(result
, 'return[0]/paused', False)
423 self
.complete_and_wait()
426 def test_large_cluster(self
):
427 self
.assert_no_active_block_jobs()
429 # Test COW into the target image. The first half of the
430 # cluster at MIRROR_GRANULARITY has to be copied from
431 # backing_img, even though sync='top'.
432 qemu_img('create', '-f', iotests
.imgfmt
, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img
)
433 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='top',
434 on_source_error
='ignore',
435 mode
='existing', target
=target_img
)
436 self
.assert_qmp(result
, 'return', {})
438 event
= self
.vm
.get_qmp_event(wait
=True)
439 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
440 self
.assert_qmp(event
, 'data/device', 'drive0')
441 self
.assert_qmp(event
, 'data/operation', 'read')
442 result
= self
.vm
.qmp('query-block-jobs')
443 self
.assert_qmp(result
, 'return[0]/paused', False)
444 self
.complete_and_wait()
447 # Detach blkdebug to compare images successfully
448 qemu_img('rebase', '-f', iotests
.imgfmt
, '-u', '-b', backing_img
, test_img
)
449 self
.assertTrue(iotests
.compare_images(test_img
, target_img
),
450 'target image does not match source after mirroring')
452 def test_stop_read(self
):
453 self
.assert_no_active_block_jobs()
455 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
456 target
=target_img
, on_source_error
='stop')
457 self
.assert_qmp(result
, 'return', {})
462 for event
in self
.vm
.get_qmp_events(wait
=True):
463 if event
['event'] == 'BLOCK_JOB_ERROR':
464 self
.assert_qmp(event
, 'data/device', 'drive0')
465 self
.assert_qmp(event
, 'data/operation', 'read')
467 result
= self
.vm
.qmp('query-block-jobs')
468 self
.assert_qmp(result
, 'return[0]/paused', True)
469 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
471 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
472 self
.assert_qmp(result
, 'return', {})
474 elif event
['event'] == 'BLOCK_JOB_READY':
475 self
.assertTrue(error
, 'job completed unexpectedly')
476 self
.assert_qmp(event
, 'data/device', 'drive0')
479 result
= self
.vm
.qmp('query-block-jobs')
480 self
.assert_qmp(result
, 'return[0]/paused', False)
481 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
483 self
.complete_and_wait(wait_ready
=False)
484 self
.assert_no_active_block_jobs()
487 class TestWriteErrors(ImageMirroringTestCase
):
488 image_len
= 2 * 1024 * 1024 # MB
490 # this should be a multiple of twice the default granularity
491 # so that we hit this offset first in state 1
492 MIRROR_GRANULARITY
= 1024 * 1024
494 def create_blkdebug_file(self
, name
, event
, errno
):
495 file = open(name
, 'w')
514 ''' % (event
, errno
, self
.MIRROR_GRANULARITY
/ 512, event
, event
))
518 self
.blkdebug_file
= target_img
+ ".blkdebug"
519 iotests
.create_image(backing_img
, TestWriteErrors
.image_len
)
520 self
.create_blkdebug_file(self
.blkdebug_file
, "write_aio", 5)
521 qemu_img('create', '-f', iotests
.imgfmt
, '-obacking_file=%s' %(backing_img), test_img
)
522 self
.vm
= iotests
.VM().add_drive(test_img
)
523 self
.target_img
= 'blkdebug:%s:%s' % (self
.blkdebug_file
, target_img
)
524 qemu_img('create', '-f', iotests
.imgfmt
, '-osize=%d' %(TestWriteErrors
.image_len
), target_img
)
530 os
.remove(backing_img
)
531 os
.remove(self
.blkdebug_file
)
533 def test_report_write(self
):
534 self
.assert_no_active_block_jobs()
536 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
537 mode
='existing', target
=self
.target_img
)
538 self
.assert_qmp(result
, 'return', {})
543 for event
in self
.vm
.get_qmp_events(wait
=True):
544 if event
['event'] == 'BLOCK_JOB_ERROR':
545 self
.assert_qmp(event
, 'data/device', 'drive0')
546 self
.assert_qmp(event
, 'data/operation', 'write')
548 elif event
['event'] == 'BLOCK_JOB_READY':
549 self
.assertTrue(False, 'job completed unexpectedly')
550 elif event
['event'] == 'BLOCK_JOB_COMPLETED':
551 self
.assertTrue(error
, 'job completed unexpectedly')
552 self
.assert_qmp(event
, 'data/type', 'mirror')
553 self
.assert_qmp(event
, 'data/device', 'drive0')
554 self
.assert_qmp(event
, 'data/error', 'Input/output error')
555 self
.assert_qmp(event
, 'data/len', self
.image_len
)
558 self
.assert_no_active_block_jobs()
561 def test_ignore_write(self
):
562 self
.assert_no_active_block_jobs()
564 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
565 mode
='existing', target
=self
.target_img
,
566 on_target_error
='ignore')
567 self
.assert_qmp(result
, 'return', {})
569 event
= self
.vm
.get_qmp_event(wait
=True)
570 self
.assertEquals(event
['event'], 'BLOCK_JOB_ERROR')
571 self
.assert_qmp(event
, 'data/device', 'drive0')
572 self
.assert_qmp(event
, 'data/operation', 'write')
573 result
= self
.vm
.qmp('query-block-jobs')
574 self
.assert_qmp(result
, 'return[0]/paused', False)
575 self
.complete_and_wait()
578 def test_stop_write(self
):
579 self
.assert_no_active_block_jobs()
581 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
582 mode
='existing', target
=self
.target_img
,
583 on_target_error
='stop')
584 self
.assert_qmp(result
, 'return', {})
589 for event
in self
.vm
.get_qmp_events(wait
=True):
590 if event
['event'] == 'BLOCK_JOB_ERROR':
591 self
.assert_qmp(event
, 'data/device', 'drive0')
592 self
.assert_qmp(event
, 'data/operation', 'write')
594 result
= self
.vm
.qmp('query-block-jobs')
595 self
.assert_qmp(result
, 'return[0]/paused', True)
596 self
.assert_qmp(result
, 'return[0]/io-status', 'failed')
598 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
599 self
.assert_qmp(result
, 'return', {})
601 result
= self
.vm
.qmp('query-block-jobs')
602 self
.assert_qmp(result
, 'return[0]/paused', False)
603 self
.assert_qmp(result
, 'return[0]/io-status', 'ok')
605 elif event
['event'] == 'BLOCK_JOB_READY':
606 self
.assertTrue(error
, 'job completed unexpectedly')
607 self
.assert_qmp(event
, 'data/device', 'drive0')
610 self
.complete_and_wait(wait_ready
=False)
611 self
.assert_no_active_block_jobs()
614 class TestSetSpeed(ImageMirroringTestCase
):
615 image_len
= 80 * 1024 * 1024 # MB
618 qemu_img('create', backing_img
, str(TestSetSpeed
.image_len
))
619 qemu_img('create', '-f', iotests
.imgfmt
, '-o', 'backing_file=%s' % backing_img
, test_img
)
620 self
.vm
= iotests
.VM().add_drive(test_img
)
626 os
.remove(backing_img
)
627 os
.remove(target_img
)
629 def test_set_speed(self
):
630 self
.assert_no_active_block_jobs()
632 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
634 self
.assert_qmp(result
, 'return', {})
637 result
= self
.vm
.qmp('query-block-jobs')
638 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
639 self
.assert_qmp(result
, 'return[0]/speed', 0)
641 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=8 * 1024 * 1024)
642 self
.assert_qmp(result
, 'return', {})
644 # Ensure the speed we set was accepted
645 result
= self
.vm
.qmp('query-block-jobs')
646 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
647 self
.assert_qmp(result
, 'return[0]/speed', 8 * 1024 * 1024)
649 self
.wait_ready_and_cancel()
651 # Check setting speed in drive-mirror works
652 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
653 target
=target_img
, speed
=4*1024*1024)
654 self
.assert_qmp(result
, 'return', {})
656 result
= self
.vm
.qmp('query-block-jobs')
657 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
658 self
.assert_qmp(result
, 'return[0]/speed', 4 * 1024 * 1024)
660 self
.wait_ready_and_cancel()
662 def test_set_speed_invalid(self
):
663 self
.assert_no_active_block_jobs()
665 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
666 target
=target_img
, speed
=-1)
667 self
.assert_qmp(result
, 'error/class', 'GenericError')
669 self
.assert_no_active_block_jobs()
671 result
= self
.vm
.qmp('drive-mirror', device
='drive0', sync
='full',
673 self
.assert_qmp(result
, 'return', {})
675 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=-1)
676 self
.assert_qmp(result
, 'error/class', 'GenericError')
678 self
.wait_ready_and_cancel()
680 class TestUnbackedSource(ImageMirroringTestCase
):
681 image_len
= 2 * 1024 * 1024 # MB
684 qemu_img('create', '-f', iotests
.imgfmt
, test_img
,
685 str(TestUnbackedSource
.image_len
))
686 self
.vm
= iotests
.VM().add_drive(test_img
)
692 os
.remove(target_img
)
694 def test_absolute_paths_full(self
):
695 self
.assert_no_active_block_jobs()
696 result
= self
.vm
.qmp('drive-mirror', device
='drive0',
697 sync
='full', target
=target_img
,
698 mode
='absolute-paths')
699 self
.assert_qmp(result
, 'return', {})
700 self
.complete_and_wait()
701 self
.assert_no_active_block_jobs()
703 def test_absolute_paths_top(self
):
704 self
.assert_no_active_block_jobs()
705 result
= self
.vm
.qmp('drive-mirror', device
='drive0',
706 sync
='top', target
=target_img
,
707 mode
='absolute-paths')
708 self
.assert_qmp(result
, 'return', {})
709 self
.complete_and_wait()
710 self
.assert_no_active_block_jobs()
712 def test_absolute_paths_none(self
):
713 self
.assert_no_active_block_jobs()
714 result
= self
.vm
.qmp('drive-mirror', device
='drive0',
715 sync
='none', target
=target_img
,
716 mode
='absolute-paths')
717 self
.assert_qmp(result
, 'return', {})
718 self
.complete_and_wait()
719 self
.assert_no_active_block_jobs()
721 if __name__
== '__main__':
722 iotests
.main(supported_fmts
=['qcow2', 'qed'])