xref: /openbmc/qemu/tests/qemu-iotests/118 (revision 3be57622)
1#!/usr/bin/env python3
2# group: rw
3#
4# Test case for media change monitor commands
5#
6# Copyright (C) 2015 Red Hat, Inc.
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20#
21
22import os
23import stat
24import time
25import iotests
26from iotests import qemu_img
27
28old_img = os.path.join(iotests.test_dir, 'test0.img')
29new_img = os.path.join(iotests.test_dir, 'test1.img')
30
31def interface_to_device_name(interface):
32    if interface == 'ide':
33        return 'ide-cd'
34    elif interface == 'floppy':
35        return 'floppy'
36    elif interface == 'scsi':
37        return 'scsi-cd'
38    else:
39        return None
40
41class ChangeBaseClass(iotests.QMPTestCase):
42    has_opened = False
43    has_closed = False
44
45    device_name = 'qdev0'
46    use_drive = False
47
48    def process_events(self):
49        for event in self.vm.get_qmp_events(wait=False):
50            if (event['event'] == 'DEVICE_TRAY_MOVED' and
51                (event['data']['device'] == 'drive0' or
52                 event['data']['id'] == self.device_name)):
53                if event['data']['tray-open'] == False:
54                    self.has_closed = True
55                else:
56                    self.has_opened = True
57
58    def wait_for_open(self):
59        if not self.has_real_tray:
60            return
61
62        with iotests.Timeout(3, 'Timeout while waiting for the tray to open'):
63            while not self.has_opened:
64                self.process_events()
65
66    def wait_for_close(self):
67        if not self.has_real_tray:
68            return
69
70        with iotests.Timeout(3, 'Timeout while waiting for the tray to close'):
71            while not self.has_closed:
72                self.process_events()
73
74class GeneralChangeTestsBaseClass(ChangeBaseClass):
75
76    def test_blockdev_change_medium(self):
77        self.vm.cmd('blockdev-change-medium',
78                    id=self.device_name, filename=new_img,
79                    format=iotests.imgfmt)
80
81        self.wait_for_open()
82        self.wait_for_close()
83
84        result = self.vm.qmp('query-block')
85        if self.has_real_tray:
86            self.assert_qmp(result, 'return[0]/tray_open', False)
87        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
88
89    def test_eject(self):
90        self.vm.cmd('eject', id=self.device_name, force=True)
91
92        self.wait_for_open()
93
94        result = self.vm.qmp('query-block')
95        if self.has_real_tray:
96            self.assert_qmp(result, 'return[0]/tray_open', True)
97        self.assert_qmp_absent(result, 'return[0]/inserted')
98
99    def test_tray_eject_change(self):
100        self.vm.cmd('eject', id=self.device_name, force=True)
101
102        self.wait_for_open()
103
104        result = self.vm.qmp('query-block')
105        if self.has_real_tray:
106            self.assert_qmp(result, 'return[0]/tray_open', True)
107        self.assert_qmp_absent(result, 'return[0]/inserted')
108
109        self.vm.cmd('blockdev-change-medium', id=self.device_name,
110                    filename=new_img, format=iotests.imgfmt)
111
112        self.wait_for_close()
113
114        result = self.vm.qmp('query-block')
115        if self.has_real_tray:
116            self.assert_qmp(result, 'return[0]/tray_open', False)
117        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
118
119    def test_tray_open_close(self):
120        self.vm.cmd('blockdev-open-tray',
121                    id=self.device_name, force=True)
122
123        self.wait_for_open()
124
125        result = self.vm.qmp('query-block')
126        if self.has_real_tray:
127            self.assert_qmp(result, 'return[0]/tray_open', True)
128        if self.was_empty == True:
129            self.assert_qmp_absent(result, 'return[0]/inserted')
130        else:
131            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
132
133        self.vm.cmd('blockdev-close-tray', id=self.device_name)
134
135        if self.has_real_tray or not self.was_empty:
136            self.wait_for_close()
137
138        result = self.vm.qmp('query-block')
139        if self.has_real_tray:
140            self.assert_qmp(result, 'return[0]/tray_open', False)
141        if self.was_empty == True:
142            self.assert_qmp_absent(result, 'return[0]/inserted')
143        else:
144            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
145
146    def test_tray_eject_close(self):
147        self.vm.cmd('eject', id=self.device_name, force=True)
148
149        self.wait_for_open()
150
151        result = self.vm.qmp('query-block')
152        if self.has_real_tray:
153            self.assert_qmp(result, 'return[0]/tray_open', True)
154        self.assert_qmp_absent(result, 'return[0]/inserted')
155
156        self.vm.cmd('blockdev-close-tray', id=self.device_name)
157
158        self.wait_for_close()
159
160        result = self.vm.qmp('query-block')
161        if self.has_real_tray:
162            self.assert_qmp(result, 'return[0]/tray_open', False)
163        self.assert_qmp_absent(result, 'return[0]/inserted')
164
165    def test_tray_open_change(self):
166        self.vm.cmd('blockdev-open-tray', id=self.device_name,
167                                          force=True)
168
169        self.wait_for_open()
170
171        result = self.vm.qmp('query-block')
172        if self.has_real_tray:
173            self.assert_qmp(result, 'return[0]/tray_open', True)
174        if self.was_empty == True:
175            self.assert_qmp_absent(result, 'return[0]/inserted')
176        else:
177            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
178
179        self.vm.cmd('blockdev-change-medium', id=self.device_name,
180                                              filename=new_img,
181                                              format=iotests.imgfmt)
182
183        self.wait_for_close()
184
185        result = self.vm.qmp('query-block')
186        if self.has_real_tray:
187            self.assert_qmp(result, 'return[0]/tray_open', False)
188        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
189
190    def test_cycle(self, read_only_node=False):
191        self.vm.cmd('blockdev-add',
192                    node_name='new',
193                    driver=iotests.imgfmt,
194                    read_only=read_only_node,
195                    file={'filename': new_img,
196                           'driver': 'file'})
197
198        self.vm.cmd('blockdev-open-tray',
199                    id=self.device_name, force=True)
200
201        self.wait_for_open()
202
203        result = self.vm.qmp('query-block')
204        if self.has_real_tray:
205            self.assert_qmp(result, 'return[0]/tray_open', True)
206        if self.was_empty == True:
207            self.assert_qmp_absent(result, 'return[0]/inserted')
208        else:
209            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
210
211        self.vm.cmd('blockdev-remove-medium',
212                    id=self.device_name)
213
214        result = self.vm.qmp('query-block')
215        if self.has_real_tray:
216            self.assert_qmp(result, 'return[0]/tray_open', True)
217        self.assert_qmp_absent(result, 'return[0]/inserted')
218
219        self.vm.cmd('blockdev-insert-medium',
220                    id=self.device_name, node_name='new')
221
222        result = self.vm.qmp('query-block')
223        if self.has_real_tray:
224            self.assert_qmp(result, 'return[0]/tray_open', True)
225        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
226
227        self.vm.cmd('blockdev-close-tray', id=self.device_name)
228
229        self.wait_for_close()
230
231        result = self.vm.qmp('query-block')
232        if self.has_real_tray:
233            self.assert_qmp(result, 'return[0]/tray_open', False)
234        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
235
236    def test_cycle_read_only_media(self):
237        self.test_cycle(True)
238
239    def test_close_on_closed(self):
240        # Should be a no-op
241        self.vm.cmd('blockdev-close-tray', id=self.device_name)
242        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
243
244    def test_remove_on_closed(self):
245        if not self.has_real_tray:
246            return
247
248        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
249        self.assert_qmp(result, 'error/class', 'GenericError')
250
251    def test_insert_on_closed(self):
252        if not self.has_real_tray:
253            return
254
255        self.vm.cmd('blockdev-add',
256                    node_name='new',
257                    driver=iotests.imgfmt,
258                    file={'filename': new_img,
259                          'driver': 'file'})
260
261        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
262                                                       node_name='new')
263        self.assert_qmp(result, 'error/class', 'GenericError')
264
265class TestInitiallyFilled(GeneralChangeTestsBaseClass):
266    was_empty = False
267
268    def setUp(self):
269        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
270        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
271        self.vm = iotests.VM()
272        if self.use_drive:
273            self.vm.add_drive(old_img, 'media=%s' % self.media, 'none')
274        else:
275            self.vm.add_blockdev([ 'node-name=drive0',
276                                   'driver=%s' % iotests.imgfmt,
277                                   'file.driver=file',
278                                   'file.filename=%s' % old_img ])
279        if self.interface == 'scsi':
280            self.vm.add_object('iothread,id=iothread0')
281            self.vm.add_device('virtio-scsi-pci,iothread=iothread0')
282        self.vm.add_device('%s,drive=drive0,id=%s' %
283                           (interface_to_device_name(self.interface),
284                            self.device_name))
285        self.vm.launch()
286
287    def tearDown(self):
288        self.vm.shutdown()
289        os.remove(old_img)
290        os.remove(new_img)
291
292    def test_insert_on_filled(self):
293        self.vm.cmd('blockdev-add',
294                    node_name='new',
295                    driver=iotests.imgfmt,
296                    file={'filename': new_img,
297                          'driver': 'file'})
298
299        self.vm.cmd('blockdev-open-tray', id=self.device_name)
300
301        self.wait_for_open()
302
303        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
304                                                       node_name='new')
305        self.assert_qmp(result, 'error/class', 'GenericError')
306
307class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
308    was_empty = True
309
310    def setUp(self):
311        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
312        self.vm = iotests.VM()
313        if self.use_drive:
314            self.vm.add_drive(None, 'media=%s' % self.media, 'none')
315        if self.interface == 'scsi':
316            self.vm.add_object('iothread,id=iothread0')
317            self.vm.add_device('virtio-scsi-pci,iothread=iothread0')
318        self.vm.add_device('%s,%sid=%s' %
319                           (interface_to_device_name(self.interface),
320                            'drive=drive0,' if self.use_drive else '',
321                            self.device_name))
322        self.vm.launch()
323
324    def tearDown(self):
325        self.vm.shutdown()
326        os.remove(new_img)
327
328    def test_remove_on_empty(self):
329        self.vm.cmd('blockdev-open-tray', id=self.device_name)
330
331        self.wait_for_open()
332
333        # Should be a no-op
334        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
335
336# Do this in a function to avoid leaking variables like case into the global
337# name space (otherwise tests would be run for the abstract base classes)
338def create_basic_test_classes():
339    for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True),
340                                               ('cdrom', 'scsi', True),
341                                               ('disk', 'floppy', False) ]:
342
343        for case in [ TestInitiallyFilled, TestInitiallyEmpty ]:
344            for use_drive in [ True, False ]:
345                attr = { 'media': media,
346                         'interface': interface,
347                         'has_real_tray': has_real_tray,
348                         'use_drive': use_drive }
349
350                name = '%s_%s_%s_%s' % (case.__name__, media, interface,
351                                        'drive' if use_drive else 'blockdev')
352                globals()[name] = type(name, (case, ), attr)
353
354create_basic_test_classes()
355
356class TestChangeReadOnly(ChangeBaseClass):
357    device_name = 'qdev0'
358
359    def setUp(self):
360        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
361        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
362        self.vm = iotests.VM()
363
364    def tearDown(self):
365        self.vm.shutdown()
366        os.chmod(old_img, 0o666)
367        os.chmod(new_img, 0o666)
368        os.remove(old_img)
369        os.remove(new_img)
370
371    def test_ro_ro_retain(self):
372        os.chmod(old_img, 0o444)
373        os.chmod(new_img, 0o444)
374        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
375        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
376        self.vm.launch()
377
378        result = self.vm.qmp('query-block')
379        self.assert_qmp(result, 'return[0]/inserted/ro', True)
380        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
381
382        self.vm.cmd('blockdev-change-medium', id=self.device_name,
383                                              filename=new_img,
384                                              format=iotests.imgfmt,
385                                              read_only_mode='retain')
386
387        result = self.vm.qmp('query-block')
388        self.assert_qmp(result, 'return[0]/inserted/ro', True)
389        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
390
391    def test_ro_rw_retain(self):
392        os.chmod(old_img, 0o444)
393        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
394        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
395        self.vm.launch()
396
397        result = self.vm.qmp('query-block')
398        self.assert_qmp(result, 'return[0]/inserted/ro', True)
399        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
400
401        self.vm.cmd('blockdev-change-medium', id=self.device_name,
402                                              filename=new_img,
403                                              format=iotests.imgfmt,
404                                              read_only_mode='retain')
405
406        result = self.vm.qmp('query-block')
407        self.assert_qmp(result, 'return[0]/inserted/ro', True)
408        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
409
410    @iotests.skip_if_user_is_root
411    def test_rw_ro_retain(self):
412        os.chmod(new_img, 0o444)
413        self.vm.add_drive(old_img, 'media=disk', 'none')
414        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
415        self.vm.launch()
416
417        result = self.vm.qmp('query-block')
418        self.assert_qmp(result, 'return[0]/inserted/ro', False)
419        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
420
421        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
422                                                       filename=new_img,
423                                                       format=iotests.imgfmt,
424                                                       read_only_mode='retain')
425        self.assert_qmp(result, 'error/class', 'GenericError')
426
427        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
428
429        result = self.vm.qmp('query-block')
430        self.assert_qmp(result, 'return[0]/inserted/ro', False)
431        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
432
433    def test_ro_rw(self):
434        os.chmod(old_img, 0o444)
435        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
436        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
437        self.vm.launch()
438
439        result = self.vm.qmp('query-block')
440        self.assert_qmp(result, 'return[0]/inserted/ro', True)
441        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
442
443        self.vm.cmd('blockdev-change-medium',
444                    id=self.device_name,
445                    filename=new_img,
446                    format=iotests.imgfmt,
447                    read_only_mode='read-write')
448
449        result = self.vm.qmp('query-block')
450        self.assert_qmp(result, 'return[0]/inserted/ro', False)
451        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
452
453    def test_rw_ro(self):
454        os.chmod(new_img, 0o444)
455        self.vm.add_drive(old_img, 'media=disk', 'none')
456        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
457        self.vm.launch()
458
459        result = self.vm.qmp('query-block')
460        self.assert_qmp(result, 'return[0]/inserted/ro', False)
461        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
462
463        self.vm.cmd('blockdev-change-medium',
464                    id=self.device_name,
465                    filename=new_img,
466                    format=iotests.imgfmt,
467                    read_only_mode='read-only')
468
469        result = self.vm.qmp('query-block')
470        self.assert_qmp(result, 'return[0]/inserted/ro', True)
471        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
472
473    def test_make_rw_ro(self):
474        self.vm.add_drive(old_img, 'media=disk', 'none')
475        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
476        self.vm.launch()
477
478        result = self.vm.qmp('query-block')
479        self.assert_qmp(result, 'return[0]/inserted/ro', False)
480        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
481
482        self.vm.cmd('blockdev-change-medium',
483                    id=self.device_name,
484                    filename=new_img,
485                    format=iotests.imgfmt,
486                    read_only_mode='read-only')
487
488        result = self.vm.qmp('query-block')
489        self.assert_qmp(result, 'return[0]/inserted/ro', True)
490        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
491
492    @iotests.skip_if_user_is_root
493    def test_make_ro_rw(self):
494        os.chmod(new_img, 0o444)
495        self.vm.add_drive(old_img, 'media=disk', 'none')
496        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
497        self.vm.launch()
498
499        result = self.vm.qmp('query-block')
500        self.assert_qmp(result, 'return[0]/inserted/ro', False)
501        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
502
503        result = self.vm.qmp('blockdev-change-medium',
504                             id=self.device_name,
505                             filename=new_img,
506                             format=iotests.imgfmt,
507                             read_only_mode='read-write')
508        self.assert_qmp(result, 'error/class', 'GenericError')
509
510        result = self.vm.qmp('query-block')
511        self.assert_qmp(result, 'return[0]/inserted/ro', False)
512        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
513
514    def test_make_rw_ro_by_retain(self):
515        os.chmod(old_img, 0o444)
516        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
517        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
518        self.vm.launch()
519
520        result = self.vm.qmp('query-block')
521        self.assert_qmp(result, 'return[0]/inserted/ro', True)
522        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
523
524        self.vm.cmd('blockdev-change-medium', id=self.device_name,
525                                              filename=new_img,
526                                              format=iotests.imgfmt,
527                                              read_only_mode='retain')
528
529        result = self.vm.qmp('query-block')
530        self.assert_qmp(result, 'return[0]/inserted/ro', True)
531        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
532
533    @iotests.skip_if_user_is_root
534    def test_make_ro_rw_by_retain(self):
535        os.chmod(new_img, 0o444)
536        self.vm.add_drive(old_img, 'media=disk', 'none')
537        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
538        self.vm.launch()
539
540        result = self.vm.qmp('query-block')
541        self.assert_qmp(result, 'return[0]/inserted/ro', False)
542        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
543
544        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
545                                                       filename=new_img,
546                                                       format=iotests.imgfmt,
547                                                       read_only_mode='retain')
548        self.assert_qmp(result, 'error/class', 'GenericError')
549
550        result = self.vm.qmp('query-block')
551        self.assert_qmp(result, 'return[0]/inserted/ro', False)
552        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
553
554    def test_rw_ro_cycle(self):
555        os.chmod(new_img, 0o444)
556        self.vm.add_drive(old_img, 'media=disk', 'none')
557        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
558        self.vm.launch()
559
560        result = self.vm.qmp('query-block')
561        self.assert_qmp(result, 'return[0]/inserted/ro', False)
562        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
563
564        self.vm.cmd('blockdev-add',
565                    node_name='new',
566                    driver=iotests.imgfmt,
567                    read_only=True,
568                    file={'filename': new_img,
569                           'driver': 'file'})
570
571        result = self.vm.qmp('query-block')
572        self.assert_qmp(result, 'return[0]/inserted/ro', False)
573        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
574
575        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
576
577        result = self.vm.qmp('query-block')
578        self.assert_qmp_absent(result, 'return[0]/inserted')
579
580        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
581                                              node_name='new')
582
583        result = self.vm.qmp('query-block')
584        self.assert_qmp(result, 'return[0]/inserted/ro', True)
585        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
586
587        result = self.vm.qmp('query-block')
588        self.assert_qmp(result, 'return[0]/inserted/ro', True)
589        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
590
591GeneralChangeTestsBaseClass = None
592TestInitiallyFilled = None
593TestInitiallyEmpty = None
594
595
596class TestBlockJobsAfterCycle(ChangeBaseClass):
597    device_name = 'qdev0'
598
599    def setUp(self):
600        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
601
602        self.vm = iotests.VM()
603        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
604        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
605        self.vm.launch()
606
607        result = self.vm.qmp('query-block')
608        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
609
610        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
611        # is not necessary
612        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
613
614        result = self.vm.qmp('query-block')
615        self.assert_qmp_absent(result, 'return[0]/inserted')
616
617        self.vm.cmd('blockdev-add',
618                    node_name='node0',
619                    driver=iotests.imgfmt,
620                    file={'filename': old_img,
621                          'driver': 'file'})
622
623        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
624                                              node_name='node0')
625
626        result = self.vm.qmp('query-block')
627        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
628
629    def tearDown(self):
630        self.vm.shutdown()
631        os.remove(old_img)
632        try:
633            os.remove(new_img)
634        except OSError:
635            pass
636
637    # We need backing file support
638    @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw',
639                               'vhdx'))
640    def test_snapshot_and_commit(self):
641        self.vm.cmd('blockdev-snapshot-sync', device='drive0',
642                                              snapshot_file=new_img,
643                                              format=iotests.imgfmt)
644
645        result = self.vm.qmp('query-block')
646        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
647        self.assert_qmp(result,
648                        'return[0]/inserted/image/backing-image/filename',
649                        old_img)
650
651        self.vm.cmd('block-commit', device='drive0')
652
653        self.vm.event_wait(name='BLOCK_JOB_READY')
654
655        result = self.vm.qmp('query-block-jobs')
656        self.assert_qmp(result, 'return[0]/device', 'drive0')
657
658        self.vm.cmd('block-job-complete', device='drive0')
659
660        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
661
662
663if __name__ == '__main__':
664    if iotests.qemu_default_machine != 'pc':
665        # We need floppy and IDE CD-ROM
666        iotests.notrun('not suitable for this machine type: %s' %
667                       iotests.qemu_default_machine)
668    # Need to support image creation
669    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
670                                 'vmdk', 'raw', 'vhdx', 'qed'],
671                 supported_protocols=['file'])
672