]>
git.proxmox.com Git - mirror_qemu.git/blob - tests/qemu-iotests/055
3 # Tests for drive-backup and blockdev-backup
5 # Copyright (C) 2013, 2014 Red Hat, Inc.
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 from iotests
import qemu_img
, qemu_io
28 test_img
= os
.path
.join(iotests
.test_dir
, 'test.img')
29 target_img
= os
.path
.join(iotests
.test_dir
, 'target.img')
30 blockdev_target_img
= os
.path
.join(iotests
.test_dir
, 'blockdev-target.img')
32 image_len
= 64 * 1024 * 1024 # MB
35 qemu_img('create', '-f', iotests
.imgfmt
, test_img
, str(image_len
))
36 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0x11 0 64k', test_img
)
37 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0x00 64k 128k', test_img
)
38 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0x22 162k 32k', test_img
)
39 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0xd5 1M 32k', test_img
)
40 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0xdc 32M 124k', test_img
)
41 qemu_io('-f', iotests
.imgfmt
, '-c', 'write -P0x33 67043328 64k', test_img
)
47 class TestSingleDrive(iotests
.QMPTestCase
):
49 qemu_img('create', '-f', iotests
.imgfmt
, blockdev_target_img
, str(image_len
))
51 self
.vm
= iotests
.VM().add_drive(test_img
)
52 self
.vm
.add_drive(blockdev_target_img
, interface
="none")
53 if iotests
.qemu_default_machine
== 'pc':
54 self
.vm
.add_drive(None, 'media=cdrom', 'ide')
59 os
.remove(blockdev_target_img
)
65 def do_test_cancel(self
, cmd
, target
):
66 self
.assert_no_active_block_jobs()
68 result
= self
.vm
.qmp(cmd
, device
='drive0', target
=target
, sync
='full')
69 self
.assert_qmp(result
, 'return', {})
71 event
= self
.cancel_and_wait()
72 self
.assert_qmp(event
, 'data/type', 'backup')
74 def test_cancel_drive_backup(self
):
75 self
.do_test_cancel('drive-backup', target_img
)
77 def test_cancel_blockdev_backup(self
):
78 self
.do_test_cancel('blockdev-backup', 'drive1')
80 def do_test_pause(self
, cmd
, target
, image
):
81 self
.assert_no_active_block_jobs()
83 self
.vm
.pause_drive('drive0')
84 result
= self
.vm
.qmp(cmd
, device
='drive0',
85 target
=target
, sync
='full')
86 self
.assert_qmp(result
, 'return', {})
88 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
89 self
.assert_qmp(result
, 'return', {})
91 self
.vm
.resume_drive('drive0')
93 result
= self
.vm
.qmp('query-block-jobs')
94 offset
= self
.dictpath(result
, 'return[0]/offset')
97 result
= self
.vm
.qmp('query-block-jobs')
98 self
.assert_qmp(result
, 'return[0]/offset', offset
)
100 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
101 self
.assert_qmp(result
, 'return', {})
103 self
.wait_until_completed()
106 self
.assertTrue(iotests
.compare_images(test_img
, image
),
107 'target image does not match source after backup')
109 def test_pause_drive_backup(self
):
110 self
.do_test_pause('drive-backup', target_img
, target_img
)
112 def test_pause_blockdev_backup(self
):
113 self
.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img
)
115 def test_medium_not_found(self
):
116 if iotests
.qemu_default_machine
!= 'pc':
119 result
= self
.vm
.qmp('drive-backup', device
='drive2', # CD-ROM
120 target
=target_img
, sync
='full')
121 self
.assert_qmp(result
, 'error/class', 'GenericError')
123 def test_medium_not_found_blockdev_backup(self
):
124 if iotests
.qemu_default_machine
!= 'pc':
127 result
= self
.vm
.qmp('blockdev-backup', device
='drive2', # CD-ROM
128 target
='drive1', sync
='full')
129 self
.assert_qmp(result
, 'error/class', 'GenericError')
131 def test_image_not_found(self
):
132 result
= self
.vm
.qmp('drive-backup', device
='drive0',
133 target
=target_img
, sync
='full', mode
='existing')
134 self
.assert_qmp(result
, 'error/class', 'GenericError')
136 def test_invalid_format(self
):
137 result
= self
.vm
.qmp('drive-backup', device
='drive0',
138 target
=target_img
, sync
='full',
139 format
='spaghetti-noodles')
140 self
.assert_qmp(result
, 'error/class', 'GenericError')
142 def do_test_device_not_found(self
, cmd
, **args
):
143 result
= self
.vm
.qmp(cmd
, **args
)
144 self
.assert_qmp(result
, 'error/class', 'GenericError')
146 def test_device_not_found(self
):
147 self
.do_test_device_not_found('drive-backup', device
='nonexistent',
148 target
=target_img
, sync
='full')
150 self
.do_test_device_not_found('blockdev-backup', device
='nonexistent',
151 target
='drive0', sync
='full')
153 self
.do_test_device_not_found('blockdev-backup', device
='drive0',
154 target
='nonexistent', sync
='full')
156 self
.do_test_device_not_found('blockdev-backup', device
='nonexistent',
157 target
='nonexistent', sync
='full')
159 def test_target_is_source(self
):
160 result
= self
.vm
.qmp('blockdev-backup', device
='drive0',
161 target
='drive0', sync
='full')
162 self
.assert_qmp(result
, 'error/class', 'GenericError')
164 class TestSetSpeed(iotests
.QMPTestCase
):
166 qemu_img('create', '-f', iotests
.imgfmt
, blockdev_target_img
, str(image_len
))
168 self
.vm
= iotests
.VM().add_drive(test_img
)
169 self
.vm
.add_drive(blockdev_target_img
, interface
="none")
174 os
.remove(blockdev_target_img
)
176 os
.remove(target_img
)
180 def do_test_set_speed(self
, cmd
, target
):
181 self
.assert_no_active_block_jobs()
183 self
.vm
.pause_drive('drive0')
184 result
= self
.vm
.qmp(cmd
, device
='drive0', target
=target
, sync
='full')
185 self
.assert_qmp(result
, 'return', {})
188 result
= self
.vm
.qmp('query-block-jobs')
189 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
190 self
.assert_qmp(result
, 'return[0]/speed', 0)
192 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=8 * 1024 * 1024)
193 self
.assert_qmp(result
, 'return', {})
195 # Ensure the speed we set was accepted
196 result
= self
.vm
.qmp('query-block-jobs')
197 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
198 self
.assert_qmp(result
, 'return[0]/speed', 8 * 1024 * 1024)
200 event
= self
.cancel_and_wait(resume
=True)
201 self
.assert_qmp(event
, 'data/type', 'backup')
203 # Check setting speed option works
204 self
.vm
.pause_drive('drive0')
205 result
= self
.vm
.qmp(cmd
, device
='drive0',
206 target
=target
, sync
='full', speed
=4*1024*1024)
207 self
.assert_qmp(result
, 'return', {})
209 result
= self
.vm
.qmp('query-block-jobs')
210 self
.assert_qmp(result
, 'return[0]/device', 'drive0')
211 self
.assert_qmp(result
, 'return[0]/speed', 4 * 1024 * 1024)
213 event
= self
.cancel_and_wait(resume
=True)
214 self
.assert_qmp(event
, 'data/type', 'backup')
216 def test_set_speed_drive_backup(self
):
217 self
.do_test_set_speed('drive-backup', target_img
)
219 def test_set_speed_blockdev_backup(self
):
220 self
.do_test_set_speed('blockdev-backup', 'drive1')
222 def do_test_set_speed_invalid(self
, cmd
, target
):
223 self
.assert_no_active_block_jobs()
225 result
= self
.vm
.qmp(cmd
, device
='drive0',
226 target
=target
, sync
='full', speed
=-1)
227 self
.assert_qmp(result
, 'error/class', 'GenericError')
229 self
.assert_no_active_block_jobs()
231 self
.vm
.pause_drive('drive0')
232 result
= self
.vm
.qmp(cmd
, device
='drive0',
233 target
=target
, sync
='full')
234 self
.assert_qmp(result
, 'return', {})
236 result
= self
.vm
.qmp('block-job-set-speed', device
='drive0', speed
=-1)
237 self
.assert_qmp(result
, 'error/class', 'GenericError')
239 event
= self
.cancel_and_wait(resume
=True)
240 self
.assert_qmp(event
, 'data/type', 'backup')
242 def test_set_speed_invalid_drive_backup(self
):
243 self
.do_test_set_speed_invalid('drive-backup', target_img
)
245 def test_set_speed_invalid_blockdev_backup(self
):
246 self
.do_test_set_speed_invalid('blockdev-backup', 'drive1')
248 class TestSingleTransaction(iotests
.QMPTestCase
):
250 qemu_img('create', '-f', iotests
.imgfmt
, blockdev_target_img
, str(image_len
))
252 self
.vm
= iotests
.VM().add_drive(test_img
)
253 self
.vm
.add_drive(blockdev_target_img
, interface
="none")
254 if iotests
.qemu_default_machine
== 'pc':
255 self
.vm
.add_drive(None, 'media=cdrom', 'ide')
260 os
.remove(blockdev_target_img
)
262 os
.remove(target_img
)
266 def do_test_cancel(self
, cmd
, target
):
267 self
.assert_no_active_block_jobs()
269 result
= self
.vm
.qmp('transaction', actions
=[{
271 'data': { 'device': 'drive0',
277 self
.assert_qmp(result
, 'return', {})
279 event
= self
.cancel_and_wait()
280 self
.assert_qmp(event
, 'data/type', 'backup')
282 def test_cancel_drive_backup(self
):
283 self
.do_test_cancel('drive-backup', target_img
)
285 def test_cancel_blockdev_backup(self
):
286 self
.do_test_cancel('blockdev-backup', 'drive1')
288 def do_test_pause(self
, cmd
, target
, image
):
289 self
.assert_no_active_block_jobs()
291 self
.vm
.pause_drive('drive0')
292 result
= self
.vm
.qmp('transaction', actions
=[{
294 'data': { 'device': 'drive0',
299 self
.assert_qmp(result
, 'return', {})
301 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
302 self
.assert_qmp(result
, 'return', {})
304 self
.vm
.resume_drive('drive0')
306 result
= self
.vm
.qmp('query-block-jobs')
307 offset
= self
.dictpath(result
, 'return[0]/offset')
310 result
= self
.vm
.qmp('query-block-jobs')
311 self
.assert_qmp(result
, 'return[0]/offset', offset
)
313 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
314 self
.assert_qmp(result
, 'return', {})
316 self
.wait_until_completed()
319 self
.assertTrue(iotests
.compare_images(test_img
, image
),
320 'target image does not match source after backup')
322 def test_pause_drive_backup(self
):
323 self
.do_test_pause('drive-backup', target_img
, target_img
)
325 def test_pause_blockdev_backup(self
):
326 self
.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img
)
328 def do_test_medium_not_found(self
, cmd
, target
):
329 if iotests
.qemu_default_machine
!= 'pc':
332 result
= self
.vm
.qmp('transaction', actions
=[{
334 'data': { 'device': 'drive2', # CD-ROM
339 self
.assert_qmp(result
, 'error/class', 'GenericError')
341 def test_medium_not_found_drive_backup(self
):
342 self
.do_test_medium_not_found('drive-backup', target_img
)
344 def test_medium_not_found_blockdev_backup(self
):
345 self
.do_test_medium_not_found('blockdev-backup', 'drive1')
347 def test_image_not_found(self
):
348 result
= self
.vm
.qmp('transaction', actions
=[{
349 'type': 'drive-backup',
350 'data': { 'device': 'drive0',
352 'target': target_img
,
356 self
.assert_qmp(result
, 'error/class', 'GenericError')
358 def test_device_not_found(self
):
359 result
= self
.vm
.qmp('transaction', actions
=[{
360 'type': 'drive-backup',
361 'data': { 'device': 'nonexistent',
363 'target': target_img
,
367 self
.assert_qmp(result
, 'error/class', 'GenericError')
369 result
= self
.vm
.qmp('transaction', actions
=[{
370 'type': 'blockdev-backup',
371 'data': { 'device': 'nonexistent',
376 self
.assert_qmp(result
, 'error/class', 'GenericError')
378 result
= self
.vm
.qmp('transaction', actions
=[{
379 'type': 'blockdev-backup',
380 'data': { 'device': 'drive0',
381 'target': 'nonexistent',
385 self
.assert_qmp(result
, 'error/class', 'GenericError')
387 result
= self
.vm
.qmp('transaction', actions
=[{
388 'type': 'blockdev-backup',
389 'data': { 'device': 'nonexistent',
390 'target': 'nonexistent',
394 self
.assert_qmp(result
, 'error/class', 'GenericError')
396 def test_target_is_source(self
):
397 result
= self
.vm
.qmp('transaction', actions
=[{
398 'type': 'blockdev-backup',
399 'data': { 'device': 'drive0',
404 self
.assert_qmp(result
, 'error/class', 'GenericError')
406 def test_abort(self
):
407 result
= self
.vm
.qmp('transaction', actions
=[{
408 'type': 'drive-backup',
409 'data': { 'device': 'nonexistent',
411 'target': target_img
,
418 self
.assert_qmp(result
, 'error/class', 'GenericError')
419 self
.assert_no_active_block_jobs()
421 result
= self
.vm
.qmp('transaction', actions
=[{
422 'type': 'blockdev-backup',
423 'data': { 'device': 'nonexistent',
431 self
.assert_qmp(result
, 'error/class', 'GenericError')
432 self
.assert_no_active_block_jobs()
434 result
= self
.vm
.qmp('transaction', actions
=[{
435 'type': 'blockdev-backup',
436 'data': { 'device': 'drive0',
437 'target': 'nonexistent',
444 self
.assert_qmp(result
, 'error/class', 'GenericError')
445 self
.assert_no_active_block_jobs()
448 class TestDriveCompression(iotests
.QMPTestCase
):
449 image_len
= 64 * 1024 * 1024 # MB
450 fmt_supports_compression
= [{'type': 'qcow2', 'args': ()},
451 {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized')}]
455 os
.remove(blockdev_target_img
)
457 os
.remove(target_img
)
461 def do_prepare_drives(self
, fmt
, args
):
462 self
.vm
= iotests
.VM().add_drive(test_img
)
464 qemu_img('create', '-f', fmt
, blockdev_target_img
,
465 str(TestDriveCompression
.image_len
), *args
)
466 self
.vm
.add_drive(blockdev_target_img
, format
=fmt
, interface
="none")
470 def do_test_compress_complete(self
, cmd
, format
, **args
):
471 self
.do_prepare_drives(format
['type'], format
['args'])
473 self
.assert_no_active_block_jobs()
475 result
= self
.vm
.qmp(cmd
, device
='drive0', sync
='full', compress
=True, **args
)
476 self
.assert_qmp(result
, 'return', {})
478 self
.wait_until_completed()
481 self
.assertTrue(iotests
.compare_images(test_img
, blockdev_target_img
,
482 iotests
.imgfmt
, format
['type']),
483 'target image does not match source after backup')
485 def test_complete_compress_drive_backup(self
):
486 for format
in TestDriveCompression
.fmt_supports_compression
:
487 self
.do_test_compress_complete('drive-backup', format
,
488 target
=blockdev_target_img
, mode
='existing')
490 def test_complete_compress_blockdev_backup(self
):
491 for format
in TestDriveCompression
.fmt_supports_compression
:
492 self
.do_test_compress_complete('blockdev-backup', format
, target
='drive1')
494 def do_test_compress_cancel(self
, cmd
, format
, **args
):
495 self
.do_prepare_drives(format
['type'], format
['args'])
497 self
.assert_no_active_block_jobs()
499 result
= self
.vm
.qmp(cmd
, device
='drive0', sync
='full', compress
=True, **args
)
500 self
.assert_qmp(result
, 'return', {})
502 event
= self
.cancel_and_wait()
503 self
.assert_qmp(event
, 'data/type', 'backup')
507 def test_compress_cancel_drive_backup(self
):
508 for format
in TestDriveCompression
.fmt_supports_compression
:
509 self
.do_test_compress_cancel('drive-backup', format
,
510 target
=blockdev_target_img
, mode
='existing')
512 def test_compress_cancel_blockdev_backup(self
):
513 for format
in TestDriveCompression
.fmt_supports_compression
:
514 self
.do_test_compress_cancel('blockdev-backup', format
, target
='drive1')
516 def do_test_compress_pause(self
, cmd
, format
, **args
):
517 self
.do_prepare_drives(format
['type'], format
['args'])
519 self
.assert_no_active_block_jobs()
521 self
.vm
.pause_drive('drive0')
522 result
= self
.vm
.qmp(cmd
, device
='drive0', sync
='full', compress
=True, **args
)
523 self
.assert_qmp(result
, 'return', {})
525 result
= self
.vm
.qmp('block-job-pause', device
='drive0')
526 self
.assert_qmp(result
, 'return', {})
528 self
.vm
.resume_drive('drive0')
530 result
= self
.vm
.qmp('query-block-jobs')
531 offset
= self
.dictpath(result
, 'return[0]/offset')
534 result
= self
.vm
.qmp('query-block-jobs')
535 self
.assert_qmp(result
, 'return[0]/offset', offset
)
537 result
= self
.vm
.qmp('block-job-resume', device
='drive0')
538 self
.assert_qmp(result
, 'return', {})
540 self
.wait_until_completed()
543 self
.assertTrue(iotests
.compare_images(test_img
, blockdev_target_img
,
544 iotests
.imgfmt
, format
['type']),
545 'target image does not match source after backup')
547 def test_compress_pause_drive_backup(self
):
548 for format
in TestDriveCompression
.fmt_supports_compression
:
549 self
.do_test_compress_pause('drive-backup', format
,
550 target
=blockdev_target_img
, mode
='existing')
552 def test_compress_pause_blockdev_backup(self
):
553 for format
in TestDriveCompression
.fmt_supports_compression
:
554 self
.do_test_compress_pause('blockdev-backup', format
, target
='drive1')
556 if __name__
== '__main__':
557 iotests
.main(supported_fmts
=['raw', 'qcow2'])