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