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