Merge remote-tracking branch 'qemu-project/master'
[qemu/ar7.git] / tests / qemu-iotests / 055
blobd8372b55988b51834dff8eaac61a7503d7525d11
1 #!/usr/bin/env python3
2 # group: rw
4 # Tests for drive-backup and blockdev-backup
6 # Copyright (C) 2013, 2014 Red Hat, Inc.
8 # Based on 041.
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 import time
25 import os
26 import iotests
27 from iotests import qemu_img, qemu_io
29 test_img = os.path.join(iotests.test_dir, 'test.img')
30 target_img = os.path.join(iotests.test_dir, 'target.img')
31 blockdev_target_img = os.path.join(iotests.test_dir, 'blockdev-target.img')
33 image_len = 64 * 1024 * 1024 # MB
35 def setUpModule():
36     qemu_img('create', '-f', iotests.imgfmt, test_img, str(image_len))
37     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x11 0 64k', test_img)
38     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x00 64k 128k', test_img)
39     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x22 162k 32k', test_img)
40     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xd5 1M 32k', test_img)
41     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0xdc 32M 124k', test_img)
42     qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x33 67043328 64k', test_img)
44 def tearDownModule():
45     os.remove(test_img)
48 class TestSingleDrive(iotests.QMPTestCase):
49     def setUp(self):
50         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
52         self.vm = iotests.VM()
53         self.vm.add_drive('blkdebug::' + test_img, 'node-name=source')
54         self.vm.add_drive(blockdev_target_img, 'node-name=target',
55                           interface="none")
56         if iotests.qemu_default_machine == 'pc':
57             self.vm.add_drive(None, 'media=cdrom', 'ide')
58         self.vm.launch()
60     def tearDown(self):
61         self.vm.shutdown()
62         os.remove(blockdev_target_img)
63         try:
64             os.remove(target_img)
65         except OSError:
66             pass
68     def do_test_cancel(self, cmd, target):
69         self.assert_no_active_block_jobs()
71         self.vm.pause_drive('drive0')
72         self.vm.cmd(cmd, device='drive0', target=target, sync='full')
74         event = self.cancel_and_wait(resume=True)
75         self.assert_qmp(event, 'data/type', 'backup')
77     def test_cancel_drive_backup(self):
78         self.do_test_cancel('drive-backup', target_img)
80     def test_cancel_blockdev_backup(self):
81         self.do_test_cancel('blockdev-backup', 'drive1')
83     def do_test_pause(self, cmd, target, image):
84         self.assert_no_active_block_jobs()
86         self.vm.pause_drive('drive0')
87         self.vm.cmd(cmd, device='drive0',
88                     target=target, sync='full')
90         self.pause_job('drive0', wait=False)
91         self.vm.resume_drive('drive0')
92         self.pause_wait('drive0')
94         result = self.vm.qmp('query-block-jobs')
95         offset = self.dictpath(result, 'return[0]/offset')
97         time.sleep(0.5)
98         result = self.vm.qmp('query-block-jobs')
99         self.assert_qmp(result, 'return[0]/offset', offset)
101         self.vm.cmd('block-job-resume', device='drive0')
103         self.wait_until_completed()
105         self.vm.shutdown()
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 do_test_resize_blockdev_backup(self, device, node):
116         def pre_finalize():
117             result = self.vm.qmp('block_resize', device=device, size=65536)
118             self.assert_qmp(result, 'error/class', 'GenericError')
120             result = self.vm.qmp('block_resize', node_name=node, size=65536)
121             self.assert_qmp(result, 'error/class', 'GenericError')
123         self.vm.cmd('blockdev-backup', job_id='job0', device='drive0',
124                     target='drive1', sync='full', auto_finalize=False,
125                     auto_dismiss=False)
127         self.vm.run_job('job0', auto_finalize=False, pre_finalize=pre_finalize)
129     def test_source_resize_blockdev_backup(self):
130         self.do_test_resize_blockdev_backup('drive0', 'source')
132     def test_target_resize_blockdev_backup(self):
133         self.do_test_resize_blockdev_backup('drive1', 'target')
135     def do_test_target_size(self, size):
136         self.vm.cmd('block_resize', device='drive1', size=size)
138         result = self.vm.qmp('blockdev-backup', job_id='job0', device='drive0',
139                              target='drive1', sync='full')
140         self.assert_qmp(result, 'error/class', 'GenericError')
142     def test_small_target(self):
143         self.do_test_target_size(image_len // 2)
145     def test_large_target(self):
146         self.do_test_target_size(image_len * 2)
148     def test_medium_not_found(self):
149         if iotests.qemu_default_machine != 'pc':
150             return
152         result = self.vm.qmp('drive-backup', device='drive2', # CD-ROM
153                              target=target_img, sync='full')
154         self.assert_qmp(result, 'error/class', 'GenericError')
156     def test_medium_not_found_blockdev_backup(self):
157         if iotests.qemu_default_machine != 'pc':
158             return
160         result = self.vm.qmp('blockdev-backup', device='drive2', # CD-ROM
161                              target='drive1', sync='full')
162         self.assert_qmp(result, 'error/class', 'GenericError')
164     def test_image_not_found(self):
165         result = self.vm.qmp('drive-backup', device='drive0',
166                              target=target_img, sync='full', mode='existing')
167         self.assert_qmp(result, 'error/class', 'GenericError')
169     def test_invalid_format(self):
170         result = self.vm.qmp('drive-backup', device='drive0',
171                              target=target_img, sync='full',
172                              format='spaghetti-noodles')
173         self.assert_qmp(result, 'error/class', 'GenericError')
175     def do_test_device_not_found(self, cmd, **args):
176         result = self.vm.qmp(cmd, **args)
177         self.assert_qmp(result, 'error/class', 'GenericError')
179     def test_device_not_found(self):
180         self.do_test_device_not_found('drive-backup', device='nonexistent',
181                                       target=target_img, sync='full')
183         self.do_test_device_not_found('blockdev-backup', device='nonexistent',
184                                       target='drive0', sync='full')
186         self.do_test_device_not_found('blockdev-backup', device='drive0',
187                                       target='nonexistent', sync='full')
189         self.do_test_device_not_found('blockdev-backup', device='nonexistent',
190                                       target='nonexistent', sync='full')
192     def test_target_is_source(self):
193         result = self.vm.qmp('blockdev-backup', device='drive0',
194                              target='drive0', sync='full')
195         self.assert_qmp(result, 'error/class', 'GenericError')
197 class TestSetSpeed(iotests.QMPTestCase):
198     def setUp(self):
199         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
201         self.vm = iotests.VM().add_drive('blkdebug::' + test_img)
202         self.vm.add_drive(blockdev_target_img, interface="none")
203         self.vm.launch()
205     def tearDown(self):
206         self.vm.shutdown()
207         os.remove(blockdev_target_img)
208         try:
209             os.remove(target_img)
210         except OSError:
211             pass
213     def do_test_set_speed(self, cmd, target):
214         self.assert_no_active_block_jobs()
216         self.vm.pause_drive('drive0')
217         self.vm.cmd(cmd, device='drive0', target=target, sync='full')
219         # Default speed is 0
220         result = self.vm.qmp('query-block-jobs')
221         self.assert_qmp(result, 'return[0]/device', 'drive0')
222         self.assert_qmp(result, 'return[0]/speed', 0)
224         self.vm.cmd('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
226         # Ensure the speed we set was accepted
227         result = self.vm.qmp('query-block-jobs')
228         self.assert_qmp(result, 'return[0]/device', 'drive0')
229         self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
231         event = self.cancel_and_wait(resume=True)
232         self.assert_qmp(event, 'data/type', 'backup')
234         # Check setting speed option works
235         self.vm.pause_drive('drive0')
236         self.vm.cmd(cmd, device='drive0',
237                     target=target, sync='full', speed=4*1024*1024)
239         result = self.vm.qmp('query-block-jobs')
240         self.assert_qmp(result, 'return[0]/device', 'drive0')
241         self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
243         event = self.cancel_and_wait(resume=True)
244         self.assert_qmp(event, 'data/type', 'backup')
246     def test_set_speed_drive_backup(self):
247         self.do_test_set_speed('drive-backup', target_img)
249     def test_set_speed_blockdev_backup(self):
250         self.do_test_set_speed('blockdev-backup', 'drive1')
252     def do_test_set_speed_invalid(self, cmd, target):
253         self.assert_no_active_block_jobs()
255         result = self.vm.qmp(cmd, device='drive0',
256                              target=target, sync='full', speed=-1)
257         self.assert_qmp(result, 'error/class', 'GenericError')
259         self.assert_no_active_block_jobs()
261         self.vm.pause_drive('drive0')
262         self.vm.cmd(cmd, device='drive0',
263                     target=target, sync='full')
265         result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
266         self.assert_qmp(result, 'error/class', 'GenericError')
268         event = self.cancel_and_wait(resume=True)
269         self.assert_qmp(event, 'data/type', 'backup')
271     def test_set_speed_invalid_drive_backup(self):
272         self.do_test_set_speed_invalid('drive-backup', target_img)
274     def test_set_speed_invalid_blockdev_backup(self):
275         self.do_test_set_speed_invalid('blockdev-backup',  'drive1')
277 # Note: We cannot use pause_drive() here, or the transaction command
278 #       would stall.  Instead, we limit the block job speed here.
279 class TestSingleTransaction(iotests.QMPTestCase):
280     def setUp(self):
281         qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(image_len))
283         self.vm = iotests.VM().add_drive(test_img)
284         self.vm.add_drive(blockdev_target_img, interface="none")
285         if iotests.qemu_default_machine == 'pc':
286             self.vm.add_drive(None, 'media=cdrom', 'ide')
287         self.vm.launch()
289     def tearDown(self):
290         self.vm.shutdown()
291         os.remove(blockdev_target_img)
292         try:
293             os.remove(target_img)
294         except OSError:
295             pass
297     def do_test_cancel(self, cmd, target):
298         self.assert_no_active_block_jobs()
300         self.vm.cmd('transaction', actions=[{
301                 'type': cmd,
302                 'data': { 'device': 'drive0',
303                           'target': target,
304                           'sync': 'full',
305                           'speed': 64 * 1024 },
306             }
307         ])
309         event = self.cancel_and_wait()
310         self.assert_qmp(event, 'data/type', 'backup')
312     def test_cancel_drive_backup(self):
313         self.do_test_cancel('drive-backup', target_img)
315     def test_cancel_blockdev_backup(self):
316         self.do_test_cancel('blockdev-backup', 'drive1')
318     def do_test_pause(self, cmd, target, image):
319         self.assert_no_active_block_jobs()
321         self.vm.cmd('transaction', actions=[{
322                 'type': cmd,
323                 'data': { 'device': 'drive0',
324                           'target': target,
325                           'sync': 'full',
326                           'speed': 64 * 1024 },
327             }
328         ])
330         self.pause_job('drive0', wait=False)
332         self.vm.cmd('block-job-set-speed', device='drive0', speed=0)
334         self.pause_wait('drive0')
336         result = self.vm.qmp('query-block-jobs')
337         offset = self.dictpath(result, 'return[0]/offset')
339         time.sleep(0.5)
340         result = self.vm.qmp('query-block-jobs')
341         self.assert_qmp(result, 'return[0]/offset', offset)
343         self.vm.cmd('block-job-resume', device='drive0')
345         self.wait_until_completed()
347         self.vm.shutdown()
348         self.assertTrue(iotests.compare_images(test_img, image),
349                         'target image does not match source after backup')
351     def test_pause_drive_backup(self):
352         self.do_test_pause('drive-backup', target_img, target_img)
354     def test_pause_blockdev_backup(self):
355         self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
357     def do_test_medium_not_found(self, cmd, target):
358         if iotests.qemu_default_machine != 'pc':
359             return
361         result = self.vm.qmp('transaction', actions=[{
362                 'type': cmd,
363                 'data': { 'device': 'drive2', # CD-ROM
364                           'target': target,
365                           'sync': 'full' },
366             }
367         ])
368         self.assert_qmp(result, 'error/class', 'GenericError')
370     def test_medium_not_found_drive_backup(self):
371         self.do_test_medium_not_found('drive-backup', target_img)
373     def test_medium_not_found_blockdev_backup(self):
374         self.do_test_medium_not_found('blockdev-backup', 'drive1')
376     def test_image_not_found(self):
377         result = self.vm.qmp('transaction', actions=[{
378                 'type': 'drive-backup',
379                 'data': { 'device': 'drive0',
380                           'mode': 'existing',
381                           'target': target_img,
382                           'sync': 'full' },
383             }
384         ])
385         self.assert_qmp(result, 'error/class', 'GenericError')
387     def test_device_not_found(self):
388         result = self.vm.qmp('transaction', actions=[{
389                 'type': 'drive-backup',
390                 'data': { 'device': 'nonexistent',
391                           'mode': 'existing',
392                           'target': target_img,
393                           'sync': 'full' },
394             }
395         ])
396         self.assert_qmp(result, 'error/class', 'GenericError')
398         result = self.vm.qmp('transaction', actions=[{
399                 'type': 'blockdev-backup',
400                 'data': { 'device': 'nonexistent',
401                           'target': 'drive1',
402                           'sync': 'full' },
403             }
404         ])
405         self.assert_qmp(result, 'error/class', 'GenericError')
407         result = self.vm.qmp('transaction', actions=[{
408                 'type': 'blockdev-backup',
409                 'data': { 'device': 'drive0',
410                           'target': 'nonexistent',
411                           'sync': 'full' },
412             }
413         ])
414         self.assert_qmp(result, 'error/class', 'GenericError')
416         result = self.vm.qmp('transaction', actions=[{
417                 'type': 'blockdev-backup',
418                 'data': { 'device': 'nonexistent',
419                           'target': 'nonexistent',
420                           'sync': 'full' },
421             }
422         ])
423         self.assert_qmp(result, 'error/class', 'GenericError')
425     def test_target_is_source(self):
426         result = self.vm.qmp('transaction', actions=[{
427                 'type': 'blockdev-backup',
428                 'data': { 'device': 'drive0',
429                           'target': 'drive0',
430                           'sync': 'full' },
431             }
432         ])
433         self.assert_qmp(result, 'error/class', 'GenericError')
435     def test_abort(self):
436         result = self.vm.qmp('transaction', actions=[{
437                 'type': 'drive-backup',
438                 'data': { 'device': 'nonexistent',
439                           'mode': 'existing',
440                           'target': target_img,
441                           'sync': 'full' },
442             }, {
443                 'type': 'Abort',
444                 'data': {},
445             }
446         ])
447         self.assert_qmp(result, 'error/class', 'GenericError')
448         self.assert_no_active_block_jobs()
450         result = self.vm.qmp('transaction', actions=[{
451                 'type': 'blockdev-backup',
452                 'data': { 'device': 'nonexistent',
453                           'target': 'drive1',
454                           'sync': 'full' },
455             }, {
456                 'type': 'Abort',
457                 'data': {},
458             }
459         ])
460         self.assert_qmp(result, 'error/class', 'GenericError')
461         self.assert_no_active_block_jobs()
463         result = self.vm.qmp('transaction', actions=[{
464                 'type': 'blockdev-backup',
465                 'data': { 'device': 'drive0',
466                           'target': 'nonexistent',
467                           'sync': 'full' },
468             }, {
469                 'type': 'Abort',
470                 'data': {},
471             }
472         ])
473         self.assert_qmp(result, 'error/class', 'GenericError')
474         self.assert_no_active_block_jobs()
477 class TestCompressedToQcow2(iotests.QMPTestCase):
478     image_len = 64 * 1024 * 1024 # MB
479     target_fmt = {'type': 'qcow2', 'args': (), 'drive-opts': ''}
481     def tearDown(self):
482         self.vm.shutdown()
483         os.remove(blockdev_target_img)
484         try:
485             os.remove(target_img)
486         except OSError:
487             pass
489     def do_prepare_drives(self, attach_target):
490         self.vm = iotests.VM().add_drive('blkdebug::' + test_img,
491                                          opts=self.target_fmt['drive-opts'])
493         qemu_img('create', '-f', self.target_fmt['type'], blockdev_target_img,
494                  str(self.image_len), *self.target_fmt['args'])
495         if attach_target:
496             self.vm.add_drive(blockdev_target_img,
497                               img_format=self.target_fmt['type'],
498                               interface="none",
499                               opts=self.target_fmt['drive-opts'])
501         self.vm.launch()
503     def do_test_compress_complete(self, cmd, attach_target, **args):
504         self.do_prepare_drives(attach_target)
506         self.assert_no_active_block_jobs()
508         self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args)
510         self.wait_until_completed()
512         self.vm.shutdown()
513         self.assertTrue(iotests.compare_images(test_img, blockdev_target_img,
514                                                iotests.imgfmt,
515                                                self.target_fmt['type']),
516                         'target image does not match source after backup')
518     def test_complete_compress_drive_backup(self):
519         self.do_test_compress_complete('drive-backup', False,
520                                        target=blockdev_target_img,
521                                        mode='existing')
523     def test_complete_compress_blockdev_backup(self):
524         self.do_test_compress_complete('blockdev-backup',
525                                        True, target='drive1')
527     def do_test_compress_cancel(self, cmd, attach_target, **args):
528         self.do_prepare_drives(attach_target)
530         self.assert_no_active_block_jobs()
532         self.vm.pause_drive('drive0')
533         self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args)
535         event = self.cancel_and_wait(resume=True)
536         self.assert_qmp(event, 'data/type', 'backup')
538         self.vm.shutdown()
540     def test_compress_cancel_drive_backup(self):
541         self.do_test_compress_cancel('drive-backup', False,
542                                      target=blockdev_target_img,
543                                      mode='existing')
545     def test_compress_cancel_blockdev_backup(self):
546         self.do_test_compress_cancel('blockdev-backup', True,
547                                      target='drive1')
549     def do_test_compress_pause(self, cmd, attach_target, **args):
550         self.do_prepare_drives(attach_target)
552         self.assert_no_active_block_jobs()
554         self.vm.pause_drive('drive0')
555         self.vm.cmd(cmd, device='drive0', sync='full', compress=True, **args)
557         self.pause_job('drive0', wait=False)
558         self.vm.resume_drive('drive0')
559         self.pause_wait('drive0')
561         result = self.vm.qmp('query-block-jobs')
562         offset = self.dictpath(result, 'return[0]/offset')
564         time.sleep(0.5)
565         result = self.vm.qmp('query-block-jobs')
566         self.assert_qmp(result, 'return[0]/offset', offset)
568         self.vm.cmd('block-job-resume', device='drive0')
570         self.wait_until_completed()
572         self.vm.shutdown()
573         self.assertTrue(iotests.compare_images(test_img, blockdev_target_img,
574                                                iotests.imgfmt,
575                                                self.target_fmt['type']),
576                         'target image does not match source after backup')
578     def test_compress_pause_drive_backup(self):
579         self.do_test_compress_pause('drive-backup', False,
580                                     target=blockdev_target_img,
581                                     mode='existing')
583     def test_compress_pause_blockdev_backup(self):
584         self.do_test_compress_pause('blockdev-backup', True,
585                                     target='drive1')
588 class TestCompressedToVmdk(TestCompressedToQcow2):
589     target_fmt = {'type': 'vmdk', 'args': ('-o', 'subformat=streamOptimized'),
590                   'drive-opts': 'cache.no-flush=on'}
592     @iotests.skip_if_unsupported(['vmdk'])
593     def setUp(self):
594         pass
597 if __name__ == '__main__':
598     iotests.main(supported_fmts=['raw', 'qcow2'],
599                  supported_protocols=['file'])