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