cirrus: fix off-by-one in cirrus_bitblt_rop_bkwd_transp_*_16
[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'])