]> git.proxmox.com Git - mirror_qemu.git/blob - tests/qemu-iotests/055
Merge branch 'icount-update' into HEAD
[mirror_qemu.git] / tests / qemu-iotests / 055
1 #!/usr/bin/env python
2 #
3 # Tests for drive-backup and blockdev-backup
4 #
5 # Copyright (C) 2013, 2014 Red Hat, Inc.
6 #
7 # Based on 041.
8 #
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.
13 #
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.
18 #
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/>.
21 #
22
23 import time
24 import os
25 import iotests
26 from iotests import qemu_img, qemu_io
27
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')
31
32 image_len = 64 * 1024 * 1024 # MB
33
34 def setUpModule():
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)
42
43 def tearDownModule():
44 os.remove(test_img)
45
46
47 class TestSingleDrive(iotests.QMPTestCase):
48 def setUp(self):
49 qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
50
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')
55 self.vm.launch()
56
57 def tearDown(self):
58 self.vm.shutdown()
59 os.remove(blockdev_target_img)
60 try:
61 os.remove(target_img)
62 except OSError:
63 pass
64
65 def do_test_cancel(self, cmd, target):
66 self.assert_no_active_block_jobs()
67
68 result = self.vm.qmp(cmd, device='drive0', target=target, sync='full')
69 self.assert_qmp(result, 'return', {})
70
71 event = self.cancel_and_wait()
72 self.assert_qmp(event, 'data/type', 'backup')
73
74 def test_cancel_drive_backup(self):
75 self.do_test_cancel('drive-backup', target_img)
76
77 def test_cancel_blockdev_backup(self):
78 self.do_test_cancel('blockdev-backup', 'drive1')
79
80 def do_test_pause(self, cmd, target, image):
81 self.assert_no_active_block_jobs()
82
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', {})
87
88 result = self.vm.qmp('block-job-pause', device='drive0')
89 self.assert_qmp(result, 'return', {})
90
91 self.vm.resume_drive('drive0')
92 time.sleep(1)
93 result = self.vm.qmp('query-block-jobs')
94 offset = self.dictpath(result, 'return[0]/offset')
95
96 time.sleep(1)
97 result = self.vm.qmp('query-block-jobs')
98 self.assert_qmp(result, 'return[0]/offset', offset)
99
100 result = self.vm.qmp('block-job-resume', device='drive0')
101 self.assert_qmp(result, 'return', {})
102
103 self.wait_until_completed()
104
105 self.vm.shutdown()
106 self.assertTrue(iotests.compare_images(test_img, image),
107 'target image does not match source after backup')
108
109 def test_pause_drive_backup(self):
110 self.do_test_pause('drive-backup', target_img, target_img)
111
112 def test_pause_blockdev_backup(self):
113 self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
114
115 def test_medium_not_found(self):
116 if iotests.qemu_default_machine != 'pc':
117 return
118
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')
122
123 def test_medium_not_found_blockdev_backup(self):
124 if iotests.qemu_default_machine != 'pc':
125 return
126
127 result = self.vm.qmp('blockdev-backup', device='drive2', # CD-ROM
128 target='drive1', sync='full')
129 self.assert_qmp(result, 'error/class', 'GenericError')
130
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')
135
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')
141
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')
145
146 def test_device_not_found(self):
147 self.do_test_device_not_found('drive-backup', device='nonexistent',
148 target=target_img, sync='full')
149
150 self.do_test_device_not_found('blockdev-backup', device='nonexistent',
151 target='drive0', sync='full')
152
153 self.do_test_device_not_found('blockdev-backup', device='drive0',
154 target='nonexistent', sync='full')
155
156 self.do_test_device_not_found('blockdev-backup', device='nonexistent',
157 target='nonexistent', sync='full')
158
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')
163
164 class TestSetSpeed(iotests.QMPTestCase):
165 def setUp(self):
166 qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
167
168 self.vm = iotests.VM().add_drive(test_img)
169 self.vm.add_drive(blockdev_target_img, interface="none")
170 self.vm.launch()
171
172 def tearDown(self):
173 self.vm.shutdown()
174 os.remove(blockdev_target_img)
175 try:
176 os.remove(target_img)
177 except OSError:
178 pass
179
180 def do_test_set_speed(self, cmd, target):
181 self.assert_no_active_block_jobs()
182
183 self.vm.pause_drive('drive0')
184 result = self.vm.qmp(cmd, device='drive0', target=target, sync='full')
185 self.assert_qmp(result, 'return', {})
186
187 # Default speed is 0
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)
191
192 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
193 self.assert_qmp(result, 'return', {})
194
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)
199
200 event = self.cancel_and_wait(resume=True)
201 self.assert_qmp(event, 'data/type', 'backup')
202
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', {})
208
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)
212
213 event = self.cancel_and_wait(resume=True)
214 self.assert_qmp(event, 'data/type', 'backup')
215
216 def test_set_speed_drive_backup(self):
217 self.do_test_set_speed('drive-backup', target_img)
218
219 def test_set_speed_blockdev_backup(self):
220 self.do_test_set_speed('blockdev-backup', 'drive1')
221
222 def do_test_set_speed_invalid(self, cmd, target):
223 self.assert_no_active_block_jobs()
224
225 result = self.vm.qmp(cmd, device='drive0',
226 target=target, sync='full', speed=-1)
227 self.assert_qmp(result, 'error/class', 'GenericError')
228
229 self.assert_no_active_block_jobs()
230
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', {})
235
236 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
237 self.assert_qmp(result, 'error/class', 'GenericError')
238
239 event = self.cancel_and_wait(resume=True)
240 self.assert_qmp(event, 'data/type', 'backup')
241
242 def test_set_speed_invalid_drive_backup(self):
243 self.do_test_set_speed_invalid('drive-backup', target_img)
244
245 def test_set_speed_invalid_blockdev_backup(self):
246 self.do_test_set_speed_invalid('blockdev-backup', 'drive1')
247
248 class TestSingleTransaction(iotests.QMPTestCase):
249 def setUp(self):
250 qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
251
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')
256 self.vm.launch()
257
258 def tearDown(self):
259 self.vm.shutdown()
260 os.remove(blockdev_target_img)
261 try:
262 os.remove(target_img)
263 except OSError:
264 pass
265
266 def do_test_cancel(self, cmd, target):
267 self.assert_no_active_block_jobs()
268
269 result = self.vm.qmp('transaction', actions=[{
270 'type': cmd,
271 'data': { 'device': 'drive0',
272 'target': target,
273 'sync': 'full' },
274 }
275 ])
276
277 self.assert_qmp(result, 'return', {})
278
279 event = self.cancel_and_wait()
280 self.assert_qmp(event, 'data/type', 'backup')
281
282 def test_cancel_drive_backup(self):
283 self.do_test_cancel('drive-backup', target_img)
284
285 def test_cancel_blockdev_backup(self):
286 self.do_test_cancel('blockdev-backup', 'drive1')
287
288 def do_test_pause(self, cmd, target, image):
289 self.assert_no_active_block_jobs()
290
291 self.vm.pause_drive('drive0')
292 result = self.vm.qmp('transaction', actions=[{
293 'type': cmd,
294 'data': { 'device': 'drive0',
295 'target': target,
296 'sync': 'full' },
297 }
298 ])
299 self.assert_qmp(result, 'return', {})
300
301 result = self.vm.qmp('block-job-pause', device='drive0')
302 self.assert_qmp(result, 'return', {})
303
304 self.vm.resume_drive('drive0')
305 time.sleep(1)
306 result = self.vm.qmp('query-block-jobs')
307 offset = self.dictpath(result, 'return[0]/offset')
308
309 time.sleep(1)
310 result = self.vm.qmp('query-block-jobs')
311 self.assert_qmp(result, 'return[0]/offset', offset)
312
313 result = self.vm.qmp('block-job-resume', device='drive0')
314 self.assert_qmp(result, 'return', {})
315
316 self.wait_until_completed()
317
318 self.vm.shutdown()
319 self.assertTrue(iotests.compare_images(test_img, image),
320 'target image does not match source after backup')
321
322 def test_pause_drive_backup(self):
323 self.do_test_pause('drive-backup', target_img, target_img)
324
325 def test_pause_blockdev_backup(self):
326 self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
327
328 def do_test_medium_not_found(self, cmd, target):
329 if iotests.qemu_default_machine != 'pc':
330 return
331
332 result = self.vm.qmp('transaction', actions=[{
333 'type': cmd,
334 'data': { 'device': 'drive2', # CD-ROM
335 'target': target,
336 'sync': 'full' },
337 }
338 ])
339 self.assert_qmp(result, 'error/class', 'GenericError')
340
341 def test_medium_not_found_drive_backup(self):
342 self.do_test_medium_not_found('drive-backup', target_img)
343
344 def test_medium_not_found_blockdev_backup(self):
345 self.do_test_medium_not_found('blockdev-backup', 'drive1')
346
347 def test_image_not_found(self):
348 result = self.vm.qmp('transaction', actions=[{
349 'type': 'drive-backup',
350 'data': { 'device': 'drive0',
351 'mode': 'existing',
352 'target': target_img,
353 'sync': 'full' },
354 }
355 ])
356 self.assert_qmp(result, 'error/class', 'GenericError')
357
358 def test_device_not_found(self):
359 result = self.vm.qmp('transaction', actions=[{
360 'type': 'drive-backup',
361 'data': { 'device': 'nonexistent',
362 'mode': 'existing',
363 'target': target_img,
364 'sync': 'full' },
365 }
366 ])
367 self.assert_qmp(result, 'error/class', 'GenericError')
368
369 result = self.vm.qmp('transaction', actions=[{
370 'type': 'blockdev-backup',
371 'data': { 'device': 'nonexistent',
372 'target': 'drive1',
373 'sync': 'full' },
374 }
375 ])
376 self.assert_qmp(result, 'error/class', 'GenericError')
377
378 result = self.vm.qmp('transaction', actions=[{
379 'type': 'blockdev-backup',
380 'data': { 'device': 'drive0',
381 'target': 'nonexistent',
382 'sync': 'full' },
383 }
384 ])
385 self.assert_qmp(result, 'error/class', 'GenericError')
386
387 result = self.vm.qmp('transaction', actions=[{
388 'type': 'blockdev-backup',
389 'data': { 'device': 'nonexistent',
390 'target': 'nonexistent',
391 'sync': 'full' },
392 }
393 ])
394 self.assert_qmp(result, 'error/class', 'GenericError')
395
396 def test_target_is_source(self):
397 result = self.vm.qmp('transaction', actions=[{
398 'type': 'blockdev-backup',
399 'data': { 'device': 'drive0',
400 'target': 'drive0',
401 'sync': 'full' },
402 }
403 ])
404 self.assert_qmp(result, 'error/class', 'GenericError')
405
406 def test_abort(self):
407 result = self.vm.qmp('transaction', actions=[{
408 'type': 'drive-backup',
409 'data': { 'device': 'nonexistent',
410 'mode': 'existing',
411 'target': target_img,
412 'sync': 'full' },
413 }, {
414 'type': 'Abort',
415 'data': {},
416 }
417 ])
418 self.assert_qmp(result, 'error/class', 'GenericError')
419 self.assert_no_active_block_jobs()
420
421 result = self.vm.qmp('transaction', actions=[{
422 'type': 'blockdev-backup',
423 'data': { 'device': 'nonexistent',
424 'target': 'drive1',
425 'sync': 'full' },
426 }, {
427 'type': 'Abort',
428 'data': {},
429 }
430 ])
431 self.assert_qmp(result, 'error/class', 'GenericError')
432 self.assert_no_active_block_jobs()
433
434 result = self.vm.qmp('transaction', actions=[{
435 'type': 'blockdev-backup',
436 'data': { 'device': 'drive0',
437 'target': 'nonexistent',
438 'sync': 'full' },
439 }, {
440 'type': 'Abort',
441 'data': {},
442 }
443 ])
444 self.assert_qmp(result, 'error/class', 'GenericError')
445 self.assert_no_active_block_jobs()
446
447
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')}]
452
453 def tearDown(self):
454 self.vm.shutdown()
455 os.remove(blockdev_target_img)
456 try:
457 os.remove(target_img)
458 except OSError:
459 pass
460
461 def do_prepare_drives(self, fmt, args):
462 self.vm = iotests.VM().add_drive(test_img)
463
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")
467
468 self.vm.launch()
469
470 def do_test_compress_complete(self, cmd, format, **args):
471 self.do_prepare_drives(format['type'], format['args'])
472
473 self.assert_no_active_block_jobs()
474
475 result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args)
476 self.assert_qmp(result, 'return', {})
477
478 self.wait_until_completed()
479
480 self.vm.shutdown()
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')
484
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')
489
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')
493
494 def do_test_compress_cancel(self, cmd, format, **args):
495 self.do_prepare_drives(format['type'], format['args'])
496
497 self.assert_no_active_block_jobs()
498
499 result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args)
500 self.assert_qmp(result, 'return', {})
501
502 event = self.cancel_and_wait()
503 self.assert_qmp(event, 'data/type', 'backup')
504
505 self.vm.shutdown()
506
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')
511
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')
515
516 def do_test_compress_pause(self, cmd, format, **args):
517 self.do_prepare_drives(format['type'], format['args'])
518
519 self.assert_no_active_block_jobs()
520
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', {})
524
525 result = self.vm.qmp('block-job-pause', device='drive0')
526 self.assert_qmp(result, 'return', {})
527
528 self.vm.resume_drive('drive0')
529 time.sleep(1)
530 result = self.vm.qmp('query-block-jobs')
531 offset = self.dictpath(result, 'return[0]/offset')
532
533 time.sleep(1)
534 result = self.vm.qmp('query-block-jobs')
535 self.assert_qmp(result, 'return[0]/offset', offset)
536
537 result = self.vm.qmp('block-job-resume', device='drive0')
538 self.assert_qmp(result, 'return', {})
539
540 self.wait_until_completed()
541
542 self.vm.shutdown()
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')
546
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')
551
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')
555
556 if __name__ == '__main__':
557 iotests.main(supported_fmts=['raw', 'qcow2'])