xref: /qemu/tests/qemu-iotests/118 (revision d4eb5038)
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_device('virtio-scsi-pci')
281        self.vm.add_device('%s,drive=drive0,id=%s' %
282                           (interface_to_device_name(self.interface),
283                            self.device_name))
284        self.vm.launch()
285
286    def tearDown(self):
287        self.vm.shutdown()
288        os.remove(old_img)
289        os.remove(new_img)
290
291    def test_insert_on_filled(self):
292        self.vm.cmd('blockdev-add',
293                    node_name='new',
294                    driver=iotests.imgfmt,
295                    file={'filename': new_img,
296                          'driver': 'file'})
297
298        self.vm.cmd('blockdev-open-tray', id=self.device_name)
299
300        self.wait_for_open()
301
302        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
303                                                       node_name='new')
304        self.assert_qmp(result, 'error/class', 'GenericError')
305
306class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
307    was_empty = True
308
309    def setUp(self):
310        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
311        self.vm = iotests.VM()
312        if self.use_drive:
313            self.vm.add_drive(None, 'media=%s' % self.media, 'none')
314        if self.interface == 'scsi':
315            self.vm.add_device('virtio-scsi-pci')
316        self.vm.add_device('%s,%sid=%s' %
317                           (interface_to_device_name(self.interface),
318                            'drive=drive0,' if self.use_drive else '',
319                            self.device_name))
320        self.vm.launch()
321
322    def tearDown(self):
323        self.vm.shutdown()
324        os.remove(new_img)
325
326    def test_remove_on_empty(self):
327        self.vm.cmd('blockdev-open-tray', id=self.device_name)
328
329        self.wait_for_open()
330
331        # Should be a no-op
332        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
333
334# Do this in a function to avoid leaking variables like case into the global
335# name space (otherwise tests would be run for the abstract base classes)
336def create_basic_test_classes():
337    for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True),
338                                               ('cdrom', 'scsi', True),
339                                               ('disk', 'floppy', False) ]:
340
341        for case in [ TestInitiallyFilled, TestInitiallyEmpty ]:
342            for use_drive in [ True, False ]:
343                attr = { 'media': media,
344                         'interface': interface,
345                         'has_real_tray': has_real_tray,
346                         'use_drive': use_drive }
347
348                name = '%s_%s_%s_%s' % (case.__name__, media, interface,
349                                        'drive' if use_drive else 'blockdev')
350                globals()[name] = type(name, (case, ), attr)
351
352create_basic_test_classes()
353
354class TestChangeReadOnly(ChangeBaseClass):
355    device_name = 'qdev0'
356
357    def setUp(self):
358        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
359        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
360        self.vm = iotests.VM()
361
362    def tearDown(self):
363        self.vm.shutdown()
364        os.chmod(old_img, 0o666)
365        os.chmod(new_img, 0o666)
366        os.remove(old_img)
367        os.remove(new_img)
368
369    def test_ro_ro_retain(self):
370        os.chmod(old_img, 0o444)
371        os.chmod(new_img, 0o444)
372        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
373        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
374        self.vm.launch()
375
376        result = self.vm.qmp('query-block')
377        self.assert_qmp(result, 'return[0]/inserted/ro', True)
378        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
379
380        self.vm.cmd('blockdev-change-medium', id=self.device_name,
381                                              filename=new_img,
382                                              format=iotests.imgfmt,
383                                              read_only_mode='retain')
384
385        result = self.vm.qmp('query-block')
386        self.assert_qmp(result, 'return[0]/inserted/ro', True)
387        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
388
389    def test_ro_rw_retain(self):
390        os.chmod(old_img, 0o444)
391        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
392        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
393        self.vm.launch()
394
395        result = self.vm.qmp('query-block')
396        self.assert_qmp(result, 'return[0]/inserted/ro', True)
397        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
398
399        self.vm.cmd('blockdev-change-medium', id=self.device_name,
400                                              filename=new_img,
401                                              format=iotests.imgfmt,
402                                              read_only_mode='retain')
403
404        result = self.vm.qmp('query-block')
405        self.assert_qmp(result, 'return[0]/inserted/ro', True)
406        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
407
408    @iotests.skip_if_user_is_root
409    def test_rw_ro_retain(self):
410        os.chmod(new_img, 0o444)
411        self.vm.add_drive(old_img, 'media=disk', 'none')
412        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
413        self.vm.launch()
414
415        result = self.vm.qmp('query-block')
416        self.assert_qmp(result, 'return[0]/inserted/ro', False)
417        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
418
419        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
420                                                       filename=new_img,
421                                                       format=iotests.imgfmt,
422                                                       read_only_mode='retain')
423        self.assert_qmp(result, 'error/class', 'GenericError')
424
425        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
426
427        result = self.vm.qmp('query-block')
428        self.assert_qmp(result, 'return[0]/inserted/ro', False)
429        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
430
431    def test_ro_rw(self):
432        os.chmod(old_img, 0o444)
433        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
434        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
435        self.vm.launch()
436
437        result = self.vm.qmp('query-block')
438        self.assert_qmp(result, 'return[0]/inserted/ro', True)
439        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
440
441        self.vm.cmd('blockdev-change-medium',
442                    id=self.device_name,
443                    filename=new_img,
444                    format=iotests.imgfmt,
445                    read_only_mode='read-write')
446
447        result = self.vm.qmp('query-block')
448        self.assert_qmp(result, 'return[0]/inserted/ro', False)
449        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
450
451    def test_rw_ro(self):
452        os.chmod(new_img, 0o444)
453        self.vm.add_drive(old_img, 'media=disk', 'none')
454        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
455        self.vm.launch()
456
457        result = self.vm.qmp('query-block')
458        self.assert_qmp(result, 'return[0]/inserted/ro', False)
459        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
460
461        self.vm.cmd('blockdev-change-medium',
462                    id=self.device_name,
463                    filename=new_img,
464                    format=iotests.imgfmt,
465                    read_only_mode='read-only')
466
467        result = self.vm.qmp('query-block')
468        self.assert_qmp(result, 'return[0]/inserted/ro', True)
469        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
470
471    def test_make_rw_ro(self):
472        self.vm.add_drive(old_img, 'media=disk', 'none')
473        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
474        self.vm.launch()
475
476        result = self.vm.qmp('query-block')
477        self.assert_qmp(result, 'return[0]/inserted/ro', False)
478        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
479
480        self.vm.cmd('blockdev-change-medium',
481                    id=self.device_name,
482                    filename=new_img,
483                    format=iotests.imgfmt,
484                    read_only_mode='read-only')
485
486        result = self.vm.qmp('query-block')
487        self.assert_qmp(result, 'return[0]/inserted/ro', True)
488        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
489
490    @iotests.skip_if_user_is_root
491    def test_make_ro_rw(self):
492        os.chmod(new_img, 0o444)
493        self.vm.add_drive(old_img, 'media=disk', 'none')
494        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
495        self.vm.launch()
496
497        result = self.vm.qmp('query-block')
498        self.assert_qmp(result, 'return[0]/inserted/ro', False)
499        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
500
501        result = self.vm.qmp('blockdev-change-medium',
502                             id=self.device_name,
503                             filename=new_img,
504                             format=iotests.imgfmt,
505                             read_only_mode='read-write')
506        self.assert_qmp(result, 'error/class', 'GenericError')
507
508        result = self.vm.qmp('query-block')
509        self.assert_qmp(result, 'return[0]/inserted/ro', False)
510        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
511
512    def test_make_rw_ro_by_retain(self):
513        os.chmod(old_img, 0o444)
514        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
515        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
516        self.vm.launch()
517
518        result = self.vm.qmp('query-block')
519        self.assert_qmp(result, 'return[0]/inserted/ro', True)
520        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
521
522        self.vm.cmd('blockdev-change-medium', id=self.device_name,
523                                              filename=new_img,
524                                              format=iotests.imgfmt,
525                                              read_only_mode='retain')
526
527        result = self.vm.qmp('query-block')
528        self.assert_qmp(result, 'return[0]/inserted/ro', True)
529        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
530
531    @iotests.skip_if_user_is_root
532    def test_make_ro_rw_by_retain(self):
533        os.chmod(new_img, 0o444)
534        self.vm.add_drive(old_img, 'media=disk', 'none')
535        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
536        self.vm.launch()
537
538        result = self.vm.qmp('query-block')
539        self.assert_qmp(result, 'return[0]/inserted/ro', False)
540        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
541
542        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
543                                                       filename=new_img,
544                                                       format=iotests.imgfmt,
545                                                       read_only_mode='retain')
546        self.assert_qmp(result, 'error/class', 'GenericError')
547
548        result = self.vm.qmp('query-block')
549        self.assert_qmp(result, 'return[0]/inserted/ro', False)
550        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
551
552    def test_rw_ro_cycle(self):
553        os.chmod(new_img, 0o444)
554        self.vm.add_drive(old_img, 'media=disk', 'none')
555        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
556        self.vm.launch()
557
558        result = self.vm.qmp('query-block')
559        self.assert_qmp(result, 'return[0]/inserted/ro', False)
560        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
561
562        self.vm.cmd('blockdev-add',
563                    node_name='new',
564                    driver=iotests.imgfmt,
565                    read_only=True,
566                    file={'filename': new_img,
567                           'driver': 'file'})
568
569        result = self.vm.qmp('query-block')
570        self.assert_qmp(result, 'return[0]/inserted/ro', False)
571        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
572
573        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
574
575        result = self.vm.qmp('query-block')
576        self.assert_qmp_absent(result, 'return[0]/inserted')
577
578        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
579                                              node_name='new')
580
581        result = self.vm.qmp('query-block')
582        self.assert_qmp(result, 'return[0]/inserted/ro', True)
583        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
584
585        result = self.vm.qmp('query-block')
586        self.assert_qmp(result, 'return[0]/inserted/ro', True)
587        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
588
589GeneralChangeTestsBaseClass = None
590TestInitiallyFilled = None
591TestInitiallyEmpty = None
592
593
594class TestBlockJobsAfterCycle(ChangeBaseClass):
595    device_name = 'qdev0'
596
597    def setUp(self):
598        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
599
600        self.vm = iotests.VM()
601        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
602        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
603        self.vm.launch()
604
605        result = self.vm.qmp('query-block')
606        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
607
608        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
609        # is not necessary
610        self.vm.cmd('blockdev-remove-medium', id=self.device_name)
611
612        result = self.vm.qmp('query-block')
613        self.assert_qmp_absent(result, 'return[0]/inserted')
614
615        self.vm.cmd('blockdev-add',
616                    node_name='node0',
617                    driver=iotests.imgfmt,
618                    file={'filename': old_img,
619                          'driver': 'file'})
620
621        self.vm.cmd('blockdev-insert-medium', id=self.device_name,
622                                              node_name='node0')
623
624        result = self.vm.qmp('query-block')
625        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
626
627    def tearDown(self):
628        self.vm.shutdown()
629        os.remove(old_img)
630        try:
631            os.remove(new_img)
632        except OSError:
633            pass
634
635    # We need backing file support
636    @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw',
637                               'vhdx'))
638    def test_snapshot_and_commit(self):
639        self.vm.cmd('blockdev-snapshot-sync', device='drive0',
640                                              snapshot_file=new_img,
641                                              format=iotests.imgfmt)
642
643        result = self.vm.qmp('query-block')
644        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
645        self.assert_qmp(result,
646                        'return[0]/inserted/image/backing-image/filename',
647                        old_img)
648
649        self.vm.cmd('block-commit', device='drive0')
650
651        self.vm.event_wait(name='BLOCK_JOB_READY')
652
653        result = self.vm.qmp('query-block-jobs')
654        self.assert_qmp(result, 'return[0]/device', 'drive0')
655
656        self.vm.cmd('block-job-complete', device='drive0')
657
658        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
659
660
661if __name__ == '__main__':
662    if iotests.qemu_default_machine != 'pc':
663        # We need floppy and IDE CD-ROM
664        iotests.notrun('not suitable for this machine type: %s' %
665                       iotests.qemu_default_machine)
666    # Need to support image creation
667    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
668                                 'vmdk', 'raw', 'vhdx', 'qed'],
669                 supported_protocols=['file'])
670