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