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