xref: /openbmc/qemu/tests/qemu-iotests/118 (revision ebe15582)
1#!/usr/bin/env python
2#
3# Test case for the QMP 'change' command and all other associated
4# 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_change(self):
77        # 'change' requires a drive name, so skip the test for blockdev
78        if not self.use_drive:
79            return
80
81        result = self.vm.qmp('change', device='drive0', target=new_img,
82                                       arg=iotests.imgfmt)
83        self.assert_qmp(result, 'return', {})
84
85        self.wait_for_open()
86        self.wait_for_close()
87
88        result = self.vm.qmp('query-block')
89        if self.has_real_tray:
90            self.assert_qmp(result, 'return[0]/tray_open', False)
91        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
92
93    def test_blockdev_change_medium(self):
94        result = self.vm.qmp('blockdev-change-medium',
95                             id=self.device_name, filename=new_img,
96                             format=iotests.imgfmt)
97
98        self.assert_qmp(result, 'return', {})
99
100        self.wait_for_open()
101        self.wait_for_close()
102
103        result = self.vm.qmp('query-block')
104        if self.has_real_tray:
105            self.assert_qmp(result, 'return[0]/tray_open', False)
106        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
107
108    def test_eject(self):
109        result = self.vm.qmp('eject', id=self.device_name, force=True)
110        self.assert_qmp(result, 'return', {})
111
112        self.wait_for_open()
113
114        result = self.vm.qmp('query-block')
115        if self.has_real_tray:
116            self.assert_qmp(result, 'return[0]/tray_open', True)
117        self.assert_qmp_absent(result, 'return[0]/inserted')
118
119    def test_tray_eject_change(self):
120        result = self.vm.qmp('eject', id=self.device_name, force=True)
121        self.assert_qmp(result, 'return', {})
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        self.assert_qmp_absent(result, 'return[0]/inserted')
129
130        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
131                             filename=new_img, format=iotests.imgfmt)
132        self.assert_qmp(result, 'return', {})
133
134        self.wait_for_close()
135
136        result = self.vm.qmp('query-block')
137        if self.has_real_tray:
138            self.assert_qmp(result, 'return[0]/tray_open', False)
139        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
140
141    def test_tray_open_close(self):
142        result = self.vm.qmp('blockdev-open-tray',
143                             id=self.device_name, force=True)
144        self.assert_qmp(result, 'return', {})
145
146        self.wait_for_open()
147
148        result = self.vm.qmp('query-block')
149        if self.has_real_tray:
150            self.assert_qmp(result, 'return[0]/tray_open', True)
151        if self.was_empty == True:
152            self.assert_qmp_absent(result, 'return[0]/inserted')
153        else:
154            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
155
156        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
157        self.assert_qmp(result, 'return', {})
158
159        if self.has_real_tray or not self.was_empty:
160            self.wait_for_close()
161
162        result = self.vm.qmp('query-block')
163        if self.has_real_tray:
164            self.assert_qmp(result, 'return[0]/tray_open', False)
165        if self.was_empty == True:
166            self.assert_qmp_absent(result, 'return[0]/inserted')
167        else:
168            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
169
170    def test_tray_eject_close(self):
171        result = self.vm.qmp('eject', id=self.device_name, force=True)
172        self.assert_qmp(result, 'return', {})
173
174        self.wait_for_open()
175
176        result = self.vm.qmp('query-block')
177        if self.has_real_tray:
178            self.assert_qmp(result, 'return[0]/tray_open', True)
179        self.assert_qmp_absent(result, 'return[0]/inserted')
180
181        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
182        self.assert_qmp(result, 'return', {})
183
184        self.wait_for_close()
185
186        result = self.vm.qmp('query-block')
187        if self.has_real_tray:
188            self.assert_qmp(result, 'return[0]/tray_open', False)
189        self.assert_qmp_absent(result, 'return[0]/inserted')
190
191    def test_tray_open_change(self):
192        result = self.vm.qmp('blockdev-open-tray', id=self.device_name,
193                                                   force=True)
194        self.assert_qmp(result, 'return', {})
195
196        self.wait_for_open()
197
198        result = self.vm.qmp('query-block')
199        if self.has_real_tray:
200            self.assert_qmp(result, 'return[0]/tray_open', True)
201        if self.was_empty == True:
202            self.assert_qmp_absent(result, 'return[0]/inserted')
203        else:
204            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
205
206        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
207                                                       filename=new_img,
208                                                       format=iotests.imgfmt)
209        self.assert_qmp(result, 'return', {})
210
211        self.wait_for_close()
212
213        result = self.vm.qmp('query-block')
214        if self.has_real_tray:
215            self.assert_qmp(result, 'return[0]/tray_open', False)
216        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
217
218    def test_cycle(self, read_only_node=False):
219        result = self.vm.qmp('blockdev-add',
220                             node_name='new',
221                             driver=iotests.imgfmt,
222                             read_only=read_only_node,
223                             file={'filename': new_img,
224                                    'driver': 'file'})
225        self.assert_qmp(result, 'return', {})
226
227        result = self.vm.qmp('blockdev-open-tray',
228                             id=self.device_name, force=True)
229        self.assert_qmp(result, 'return', {})
230
231        self.wait_for_open()
232
233        result = self.vm.qmp('query-block')
234        if self.has_real_tray:
235            self.assert_qmp(result, 'return[0]/tray_open', True)
236        if self.was_empty == True:
237            self.assert_qmp_absent(result, 'return[0]/inserted')
238        else:
239            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
240
241        result = self.vm.qmp('blockdev-remove-medium',
242                             id=self.device_name)
243        self.assert_qmp(result, 'return', {})
244
245        result = self.vm.qmp('query-block')
246        if self.has_real_tray:
247            self.assert_qmp(result, 'return[0]/tray_open', True)
248        self.assert_qmp_absent(result, 'return[0]/inserted')
249
250        result = self.vm.qmp('blockdev-insert-medium',
251                             id=self.device_name, node_name='new')
252        self.assert_qmp(result, 'return', {})
253
254        result = self.vm.qmp('query-block')
255        if self.has_real_tray:
256            self.assert_qmp(result, 'return[0]/tray_open', True)
257        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
258
259        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
260        self.assert_qmp(result, 'return', {})
261
262        self.wait_for_close()
263
264        result = self.vm.qmp('query-block')
265        if self.has_real_tray:
266            self.assert_qmp(result, 'return[0]/tray_open', False)
267        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
268
269    def test_cycle_read_only_media(self):
270        self.test_cycle(True)
271
272    def test_close_on_closed(self):
273        result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
274        # Should be a no-op
275        self.assert_qmp(result, 'return', {})
276        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
277
278    def test_remove_on_closed(self):
279        if not self.has_real_tray:
280            return
281
282        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
283        self.assert_qmp(result, 'error/class', 'GenericError')
284
285    def test_insert_on_closed(self):
286        if not self.has_real_tray:
287            return
288
289        result = self.vm.qmp('blockdev-add',
290                             node_name='new',
291                             driver=iotests.imgfmt,
292                             file={'filename': new_img,
293                                   'driver': 'file'})
294        self.assert_qmp(result, 'return', {})
295
296        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
297                                                       node_name='new')
298        self.assert_qmp(result, 'error/class', 'GenericError')
299
300class TestInitiallyFilled(GeneralChangeTestsBaseClass):
301    was_empty = False
302
303    def setUp(self):
304        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
305        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
306        self.vm = iotests.VM()
307        if self.use_drive:
308            self.vm.add_drive(old_img, 'media=%s' % self.media, 'none')
309        else:
310            self.vm.add_blockdev([ 'node-name=drive0',
311                                   'driver=%s' % iotests.imgfmt,
312                                   'file.driver=file',
313                                   'file.filename=%s' % old_img ])
314        if self.interface == 'scsi':
315            self.vm.add_device('virtio-scsi-pci')
316        self.vm.add_device('%s,drive=drive0,id=%s' %
317                           (interface_to_device_name(self.interface),
318                            self.device_name))
319        self.vm.launch()
320
321    def tearDown(self):
322        self.vm.shutdown()
323        os.remove(old_img)
324        os.remove(new_img)
325
326    def test_insert_on_filled(self):
327        result = self.vm.qmp('blockdev-add',
328                             node_name='new',
329                             driver=iotests.imgfmt,
330                             file={'filename': new_img,
331                                   'driver': 'file'})
332        self.assert_qmp(result, 'return', {})
333
334        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
335        self.assert_qmp(result, 'return', {})
336
337        self.wait_for_open()
338
339        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
340                                                       node_name='new')
341        self.assert_qmp(result, 'error/class', 'GenericError')
342
343class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
344    was_empty = True
345
346    def setUp(self):
347        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
348        self.vm = iotests.VM()
349        if self.use_drive:
350            self.vm.add_drive(None, 'media=%s' % self.media, 'none')
351        if self.interface == 'scsi':
352            self.vm.add_device('virtio-scsi-pci')
353        self.vm.add_device('%s,%sid=%s' %
354                           (interface_to_device_name(self.interface),
355                            'drive=drive0,' if self.use_drive else '',
356                            self.device_name))
357        self.vm.launch()
358
359    def tearDown(self):
360        self.vm.shutdown()
361        os.remove(new_img)
362
363    def test_remove_on_empty(self):
364        result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
365        self.assert_qmp(result, 'return', {})
366
367        self.wait_for_open()
368
369        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
370        # Should be a no-op
371        self.assert_qmp(result, 'return', {})
372
373# Do this in a function to avoid leaking variables like case into the global
374# name space (otherwise tests would be run for the abstract base classes)
375def create_basic_test_classes():
376    for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True),
377                                               ('cdrom', 'scsi', True),
378                                               ('disk', 'floppy', False) ]:
379
380        for case in [ TestInitiallyFilled, TestInitiallyEmpty ]:
381            for use_drive in [ True, False ]:
382                attr = { 'media': media,
383                         'interface': interface,
384                         'has_real_tray': has_real_tray,
385                         'use_drive': use_drive }
386
387                name = '%s_%s_%s_%s' % (case.__name__, media, interface,
388                                        'drive' if use_drive else 'blockdev')
389                globals()[name] = type(name, (case, ), attr)
390
391create_basic_test_classes()
392
393class TestChangeReadOnly(ChangeBaseClass):
394    device_name = 'qdev0'
395
396    def setUp(self):
397        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
398        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
399        self.vm = iotests.VM()
400
401    def tearDown(self):
402        self.vm.shutdown()
403        os.chmod(old_img, 0o666)
404        os.chmod(new_img, 0o666)
405        os.remove(old_img)
406        os.remove(new_img)
407
408    def test_ro_ro_retain(self):
409        os.chmod(old_img, 0o444)
410        os.chmod(new_img, 0o444)
411        self.vm.add_drive(old_img, 'media=disk,read-only=on', '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', True)
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, 'return', {})
424
425        result = self.vm.qmp('query-block')
426        self.assert_qmp(result, 'return[0]/inserted/ro', True)
427        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
428
429    def test_ro_rw_retain(self):
430        os.chmod(old_img, 0o444)
431        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
432        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
433        self.vm.launch()
434
435        result = self.vm.qmp('query-block')
436        self.assert_qmp(result, 'return[0]/inserted/ro', True)
437        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
438
439        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
440                                                       filename=new_img,
441                                                       format=iotests.imgfmt,
442                                                       read_only_mode='retain')
443        self.assert_qmp(result, 'return', {})
444
445        result = self.vm.qmp('query-block')
446        self.assert_qmp(result, 'return[0]/inserted/ro', True)
447        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
448
449    def test_rw_ro_retain(self):
450        os.chmod(new_img, 0o444)
451        self.vm.add_drive(old_img, 'media=disk', 'none')
452        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
453        self.vm.launch()
454
455        result = self.vm.qmp('query-block')
456        self.assert_qmp(result, 'return[0]/inserted/ro', False)
457        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
458
459        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
460                                                       filename=new_img,
461                                                       format=iotests.imgfmt,
462                                                       read_only_mode='retain')
463        self.assert_qmp(result, 'error/class', 'GenericError')
464
465        self.assertEqual(self.vm.get_qmp_events(wait=False), [])
466
467        result = self.vm.qmp('query-block')
468        self.assert_qmp(result, 'return[0]/inserted/ro', False)
469        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
470
471    def test_ro_rw(self):
472        os.chmod(old_img, 0o444)
473        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
474        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
475        self.vm.launch()
476
477        result = self.vm.qmp('query-block')
478        self.assert_qmp(result, 'return[0]/inserted/ro', True)
479        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
480
481        result = self.vm.qmp('blockdev-change-medium',
482                             id=self.device_name,
483                             filename=new_img,
484                             format=iotests.imgfmt,
485                             read_only_mode='read-write')
486        self.assert_qmp(result, 'return', {})
487
488        result = self.vm.qmp('query-block')
489        self.assert_qmp(result, 'return[0]/inserted/ro', False)
490        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
491
492    def test_rw_ro(self):
493        os.chmod(new_img, 0o444)
494        self.vm.add_drive(old_img, 'media=disk', 'none')
495        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
496        self.vm.launch()
497
498        result = self.vm.qmp('query-block')
499        self.assert_qmp(result, 'return[0]/inserted/ro', False)
500        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
501
502        result = self.vm.qmp('blockdev-change-medium',
503                             id=self.device_name,
504                             filename=new_img,
505                             format=iotests.imgfmt,
506                             read_only_mode='read-only')
507        self.assert_qmp(result, 'return', {})
508
509        result = self.vm.qmp('query-block')
510        self.assert_qmp(result, 'return[0]/inserted/ro', True)
511        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
512
513    def test_make_rw_ro(self):
514        self.vm.add_drive(old_img, 'media=disk', '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', False)
520        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
521
522        result = self.vm.qmp('blockdev-change-medium',
523                             id=self.device_name,
524                             filename=new_img,
525                             format=iotests.imgfmt,
526                             read_only_mode='read-only')
527        self.assert_qmp(result, 'return', {})
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    def test_make_ro_rw(self):
534        os.chmod(new_img, 0o444)
535        self.vm.add_drive(old_img, 'media=disk', 'none')
536        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
537        self.vm.launch()
538
539        result = self.vm.qmp('query-block')
540        self.assert_qmp(result, 'return[0]/inserted/ro', False)
541        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
542
543        result = self.vm.qmp('blockdev-change-medium',
544                             id=self.device_name,
545                             filename=new_img,
546                             format=iotests.imgfmt,
547                             read_only_mode='read-write')
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_make_rw_ro_by_retain(self):
555        os.chmod(old_img, 0o444)
556        self.vm.add_drive(old_img, 'media=disk,read-only=on', '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', True)
562        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
563
564        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
565                                                       filename=new_img,
566                                                       format=iotests.imgfmt,
567                                                       read_only_mode='retain')
568        self.assert_qmp(result, 'return', {})
569
570        result = self.vm.qmp('query-block')
571        self.assert_qmp(result, 'return[0]/inserted/ro', True)
572        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
573
574    def test_make_ro_rw_by_retain(self):
575        os.chmod(new_img, 0o444)
576        self.vm.add_drive(old_img, 'media=disk', 'none')
577        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
578        self.vm.launch()
579
580        result = self.vm.qmp('query-block')
581        self.assert_qmp(result, 'return[0]/inserted/ro', False)
582        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
583
584        result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
585                                                       filename=new_img,
586                                                       format=iotests.imgfmt,
587                                                       read_only_mode='retain')
588        self.assert_qmp(result, 'error/class', 'GenericError')
589
590        result = self.vm.qmp('query-block')
591        self.assert_qmp(result, 'return[0]/inserted/ro', False)
592        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
593
594    def test_rw_ro_cycle(self):
595        os.chmod(new_img, 0o444)
596        self.vm.add_drive(old_img, 'media=disk', 'none')
597        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
598        self.vm.launch()
599
600        result = self.vm.qmp('query-block')
601        self.assert_qmp(result, 'return[0]/inserted/ro', False)
602        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
603
604        result = self.vm.qmp('blockdev-add',
605                             node_name='new',
606                             driver=iotests.imgfmt,
607                             read_only=True,
608                             file={'filename': new_img,
609                                    'driver': 'file'})
610        self.assert_qmp(result, 'return', {})
611
612        result = self.vm.qmp('query-block')
613        self.assert_qmp(result, 'return[0]/inserted/ro', False)
614        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
615
616        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
617        self.assert_qmp(result, 'return', {})
618
619        result = self.vm.qmp('query-block')
620        self.assert_qmp_absent(result, 'return[0]/inserted')
621
622        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
623                                                       node_name='new')
624        self.assert_qmp(result, 'return', {})
625
626        result = self.vm.qmp('query-block')
627        self.assert_qmp(result, 'return[0]/inserted/ro', True)
628        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
629
630        result = self.vm.qmp('query-block')
631        self.assert_qmp(result, 'return[0]/inserted/ro', True)
632        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
633
634GeneralChangeTestsBaseClass = None
635TestInitiallyFilled = None
636TestInitiallyEmpty = None
637
638
639class TestBlockJobsAfterCycle(ChangeBaseClass):
640    device_name = 'qdev0'
641
642    def setUp(self):
643        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
644
645        self.vm = iotests.VM()
646        self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
647        self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
648        self.vm.launch()
649
650        result = self.vm.qmp('query-block')
651        self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
652
653        # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
654        # is not necessary
655        result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
656        self.assert_qmp(result, 'return', {})
657
658        result = self.vm.qmp('query-block')
659        self.assert_qmp_absent(result, 'return[0]/inserted')
660
661        result = self.vm.qmp('blockdev-add',
662                             node_name='node0',
663                             driver=iotests.imgfmt,
664                             file={'filename': old_img,
665                                   'driver': 'file'})
666        self.assert_qmp(result, 'return', {})
667
668        result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
669                                                       node_name='node0')
670        self.assert_qmp(result, 'return', {})
671
672        result = self.vm.qmp('query-block')
673        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
674
675    def tearDown(self):
676        self.vm.shutdown()
677        os.remove(old_img)
678        try:
679            os.remove(new_img)
680        except OSError:
681            pass
682
683    def test_snapshot_and_commit(self):
684        # We need backing file support
685        if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
686            return
687
688        result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
689                                                       snapshot_file=new_img,
690                                                       format=iotests.imgfmt)
691        self.assert_qmp(result, 'return', {})
692
693        result = self.vm.qmp('query-block')
694        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
695        self.assert_qmp(result,
696                        'return[0]/inserted/image/backing-image/filename',
697                        old_img)
698
699        result = self.vm.qmp('block-commit', device='drive0')
700        self.assert_qmp(result, 'return', {})
701
702        self.vm.event_wait(name='BLOCK_JOB_READY')
703
704        result = self.vm.qmp('query-block-jobs')
705        self.assert_qmp(result, 'return[0]/device', 'drive0')
706
707        result = self.vm.qmp('block-job-complete', device='drive0')
708        self.assert_qmp(result, 'return', {})
709
710        self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
711
712
713if __name__ == '__main__':
714    if iotests.qemu_default_machine != 'pc':
715        # We need floppy and IDE CD-ROM
716        iotests.notrun('not suitable for this machine type: %s' %
717                       iotests.qemu_default_machine)
718    # Need to support image creation
719    iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
720                                 'vmdk', 'raw', 'vhdx', 'qed'],
721                 supported_protocols=['file'])
722