3 # Test case for the QMP 'change' command and all other associated
6 # Copyright (C) 2015 Red Hat, Inc.
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.
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.
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/>.
26 from iotests import qemu_img
28 old_img = os.path.join(iotests.test_dir, 'test0.img')
29 new_img = os.path.join(iotests.test_dir, 'test1.img')
31 def interface_to_device_name(interface):
32 if interface == 'ide':
34 elif interface == 'floppy':
39 class ChangeBaseClass(iotests.QMPTestCase):
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
50 self.has_opened = True
52 def wait_for_open(self):
53 if not self.has_real_tray:
56 timeout = time.clock() + 3
57 while not self.has_opened and time.clock() < timeout:
59 if not self.has_opened:
60 self.fail('Timeout while waiting for the tray to open')
62 def wait_for_close(self):
63 if not self.has_real_tray:
66 timeout = time.clock() + 3
67 while not self.has_closed and time.clock() < timeout:
69 if not self.has_opened:
70 self.fail('Timeout while waiting for the tray to close')
72 class GeneralChangeTestsBaseClass(ChangeBaseClass):
76 def test_change(self):
77 result = self.vm.qmp('change', device='drive0', target=new_img,
79 self.assert_qmp(result, 'return', {})
84 result = self.vm.qmp('query-block')
85 if self.has_real_tray:
86 self.assert_qmp(result, 'return[0]/tray_open', False)
87 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
89 def test_blockdev_change_medium(self):
90 result = self.vm.qmp('blockdev-change-medium',
91 id=self.device_name, filename=new_img,
92 format=iotests.imgfmt)
94 self.assert_qmp(result, 'return', {})
99 result = self.vm.qmp('query-block')
100 if self.has_real_tray:
101 self.assert_qmp(result, 'return[0]/tray_open', False)
102 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
104 def test_eject(self):
105 result = self.vm.qmp('eject', id=self.device_name, force=True)
106 self.assert_qmp(result, 'return', {})
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')
115 def test_tray_eject_change(self):
116 result = self.vm.qmp('eject', id=self.device_name, force=True)
117 self.assert_qmp(result, 'return', {})
121 result = self.vm.qmp('query-block')
122 if self.has_real_tray:
123 self.assert_qmp(result, 'return[0]/tray_open', True)
124 self.assert_qmp_absent(result, 'return[0]/inserted')
126 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
127 filename=new_img, format=iotests.imgfmt)
128 self.assert_qmp(result, 'return', {})
130 self.wait_for_close()
132 result = self.vm.qmp('query-block')
133 if self.has_real_tray:
134 self.assert_qmp(result, 'return[0]/tray_open', False)
135 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
137 def test_tray_open_close(self):
138 result = self.vm.qmp('blockdev-open-tray',
139 id=self.device_name, force=True)
140 self.assert_qmp(result, 'return', {})
144 result = self.vm.qmp('query-block')
145 if self.has_real_tray:
146 self.assert_qmp(result, 'return[0]/tray_open', True)
147 if self.was_empty == True:
148 self.assert_qmp_absent(result, 'return[0]/inserted')
150 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
152 result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
153 self.assert_qmp(result, 'return', {})
155 if self.has_real_tray or not self.was_empty:
156 self.wait_for_close()
158 result = self.vm.qmp('query-block')
159 if self.has_real_tray:
160 self.assert_qmp(result, 'return[0]/tray_open', False)
161 if self.was_empty == True:
162 self.assert_qmp_absent(result, 'return[0]/inserted')
164 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
166 def test_tray_eject_close(self):
167 result = self.vm.qmp('eject', id=self.device_name, force=True)
168 self.assert_qmp(result, 'return', {})
172 result = self.vm.qmp('query-block')
173 if self.has_real_tray:
174 self.assert_qmp(result, 'return[0]/tray_open', True)
175 self.assert_qmp_absent(result, 'return[0]/inserted')
177 result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
178 self.assert_qmp(result, 'return', {})
180 self.wait_for_close()
182 result = self.vm.qmp('query-block')
183 if self.has_real_tray:
184 self.assert_qmp(result, 'return[0]/tray_open', False)
185 self.assert_qmp_absent(result, 'return[0]/inserted')
187 def test_tray_open_change(self):
188 result = self.vm.qmp('blockdev-open-tray', id=self.device_name,
190 self.assert_qmp(result, 'return', {})
194 result = self.vm.qmp('query-block')
195 if self.has_real_tray:
196 self.assert_qmp(result, 'return[0]/tray_open', True)
197 if self.was_empty == True:
198 self.assert_qmp_absent(result, 'return[0]/inserted')
200 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
202 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
204 format=iotests.imgfmt)
205 self.assert_qmp(result, 'return', {})
207 self.wait_for_close()
209 result = self.vm.qmp('query-block')
210 if self.has_real_tray:
211 self.assert_qmp(result, 'return[0]/tray_open', False)
212 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
214 def test_cycle(self):
215 result = self.vm.qmp('blockdev-add',
217 driver=iotests.imgfmt,
218 file={'filename': new_img,
220 self.assert_qmp(result, 'return', {})
222 result = self.vm.qmp('blockdev-open-tray',
223 id=self.device_name, force=True)
224 self.assert_qmp(result, 'return', {})
228 result = self.vm.qmp('query-block')
229 if self.has_real_tray:
230 self.assert_qmp(result, 'return[0]/tray_open', True)
231 if self.was_empty == True:
232 self.assert_qmp_absent(result, 'return[0]/inserted')
234 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
236 result = self.vm.qmp('blockdev-remove-medium',
238 self.assert_qmp(result, 'return', {})
240 result = self.vm.qmp('query-block')
241 if self.has_real_tray:
242 self.assert_qmp(result, 'return[0]/tray_open', True)
243 self.assert_qmp_absent(result, 'return[0]/inserted')
245 result = self.vm.qmp('blockdev-insert-medium',
246 id=self.device_name, node_name='new')
247 self.assert_qmp(result, 'return', {})
249 result = self.vm.qmp('query-block')
250 if self.has_real_tray:
251 self.assert_qmp(result, 'return[0]/tray_open', True)
252 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
254 result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
255 self.assert_qmp(result, 'return', {})
257 self.wait_for_close()
259 result = self.vm.qmp('query-block')
260 if self.has_real_tray:
261 self.assert_qmp(result, 'return[0]/tray_open', False)
262 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
264 def test_close_on_closed(self):
265 result = self.vm.qmp('blockdev-close-tray', id=self.device_name)
267 self.assert_qmp(result, 'return', {})
268 self.assertEquals(self.vm.get_qmp_events(wait=False), [])
270 def test_remove_on_closed(self):
271 if not self.has_real_tray:
274 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
275 self.assert_qmp(result, 'error/class', 'GenericError')
277 def test_insert_on_closed(self):
278 if not self.has_real_tray:
281 result = self.vm.qmp('blockdev-add',
283 driver=iotests.imgfmt,
284 file={'filename': new_img,
286 self.assert_qmp(result, 'return', {})
288 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
290 self.assert_qmp(result, 'error/class', 'GenericError')
292 class TestInitiallyFilled(GeneralChangeTestsBaseClass):
295 def setUp(self, media, interface):
296 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
297 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
298 self.vm = iotests.VM()
299 self.vm.add_drive(old_img, 'media=%s' % media, 'none')
300 self.vm.add_device('%s,drive=drive0,id=%s' %
301 (interface_to_device_name(interface),
310 def test_insert_on_filled(self):
311 result = self.vm.qmp('blockdev-add',
313 driver=iotests.imgfmt,
314 file={'filename': new_img,
316 self.assert_qmp(result, 'return', {})
318 result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
319 self.assert_qmp(result, 'return', {})
323 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
325 self.assert_qmp(result, 'error/class', 'GenericError')
327 class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
330 def setUp(self, media, interface):
331 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
332 self.vm = iotests.VM().add_drive(None, 'media=%s' % media, 'none')
333 self.vm.add_device('%s,drive=drive0,id=%s' %
334 (interface_to_device_name(interface),
342 def test_remove_on_empty(self):
343 result = self.vm.qmp('blockdev-open-tray', id=self.device_name)
344 self.assert_qmp(result, 'return', {})
348 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
350 self.assert_qmp(result, 'return', {})
352 class TestCDInitiallyFilled(TestInitiallyFilled):
353 TestInitiallyFilled = TestInitiallyFilled
357 self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide')
359 class TestCDInitiallyEmpty(TestInitiallyEmpty):
360 TestInitiallyEmpty = TestInitiallyEmpty
364 self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide')
366 class TestFloppyInitiallyFilled(TestInitiallyFilled):
367 TestInitiallyFilled = TestInitiallyFilled
368 has_real_tray = False
371 self.TestInitiallyFilled.setUp(self, 'disk', 'floppy')
373 class TestFloppyInitiallyEmpty(TestInitiallyEmpty):
374 TestInitiallyEmpty = TestInitiallyEmpty
375 has_real_tray = False
378 self.TestInitiallyEmpty.setUp(self, 'disk', 'floppy')
379 # FDDs not having a real tray and there not being a medium inside the
380 # tray at startup means the tray will be considered open
381 self.has_opened = True
383 class TestChangeReadOnly(ChangeBaseClass):
384 device_name = 'qdev0'
387 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
388 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
389 self.vm = iotests.VM()
393 os.chmod(old_img, 0666)
394 os.chmod(new_img, 0666)
398 def test_ro_ro_retain(self):
399 os.chmod(old_img, 0444)
400 os.chmod(new_img, 0444)
401 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
402 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
405 result = self.vm.qmp('query-block')
406 self.assert_qmp(result, 'return[0]/inserted/ro', True)
407 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
409 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
411 format=iotests.imgfmt,
412 read_only_mode='retain')
413 self.assert_qmp(result, 'return', {})
415 result = self.vm.qmp('query-block')
416 self.assert_qmp(result, 'return[0]/inserted/ro', True)
417 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
419 def test_ro_rw_retain(self):
420 os.chmod(old_img, 0444)
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)
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)
429 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
431 format=iotests.imgfmt,
432 read_only_mode='retain')
433 self.assert_qmp(result, 'return', {})
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)
439 def test_rw_ro_retain(self):
440 os.chmod(new_img, 0444)
441 self.vm.add_drive(old_img, 'media=disk', 'none')
442 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
445 result = self.vm.qmp('query-block')
446 self.assert_qmp(result, 'return[0]/inserted/ro', False)
447 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
449 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
451 format=iotests.imgfmt,
452 read_only_mode='retain')
453 self.assert_qmp(result, 'error/class', 'GenericError')
455 self.assertEquals(self.vm.get_qmp_events(wait=False), [])
457 result = self.vm.qmp('query-block')
458 self.assert_qmp(result, 'return[0]/inserted/ro', False)
459 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
461 def test_ro_rw(self):
462 os.chmod(old_img, 0444)
463 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
464 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
467 result = self.vm.qmp('query-block')
468 self.assert_qmp(result, 'return[0]/inserted/ro', True)
469 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
471 result = self.vm.qmp('blockdev-change-medium',
474 format=iotests.imgfmt,
475 read_only_mode='read-write')
476 self.assert_qmp(result, 'return', {})
478 result = self.vm.qmp('query-block')
479 self.assert_qmp(result, 'return[0]/inserted/ro', False)
480 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
482 def test_rw_ro(self):
483 os.chmod(new_img, 0444)
484 self.vm.add_drive(old_img, 'media=disk', 'none')
485 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
488 result = self.vm.qmp('query-block')
489 self.assert_qmp(result, 'return[0]/inserted/ro', False)
490 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
492 result = self.vm.qmp('blockdev-change-medium',
495 format=iotests.imgfmt,
496 read_only_mode='read-only')
497 self.assert_qmp(result, 'return', {})
499 result = self.vm.qmp('query-block')
500 self.assert_qmp(result, 'return[0]/inserted/ro', True)
501 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
503 def test_make_rw_ro(self):
504 self.vm.add_drive(old_img, 'media=disk', 'none')
505 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
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)
512 result = self.vm.qmp('blockdev-change-medium',
515 format=iotests.imgfmt,
516 read_only_mode='read-only')
517 self.assert_qmp(result, 'return', {})
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)
523 def test_make_ro_rw(self):
524 os.chmod(new_img, 0444)
525 self.vm.add_drive(old_img, 'media=disk', 'none')
526 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
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)
533 result = self.vm.qmp('blockdev-change-medium',
536 format=iotests.imgfmt,
537 read_only_mode='read-write')
538 self.assert_qmp(result, 'error/class', 'GenericError')
540 result = self.vm.qmp('query-block')
541 self.assert_qmp(result, 'return[0]/inserted/ro', False)
542 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
544 def test_make_rw_ro_by_retain(self):
545 os.chmod(old_img, 0444)
546 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none')
547 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
550 result = self.vm.qmp('query-block')
551 self.assert_qmp(result, 'return[0]/inserted/ro', True)
552 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
554 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
556 format=iotests.imgfmt,
557 read_only_mode='retain')
558 self.assert_qmp(result, 'return', {})
560 result = self.vm.qmp('query-block')
561 self.assert_qmp(result, 'return[0]/inserted/ro', True)
562 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
564 def test_make_ro_rw_by_retain(self):
565 os.chmod(new_img, 0444)
566 self.vm.add_drive(old_img, 'media=disk', 'none')
567 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
570 result = self.vm.qmp('query-block')
571 self.assert_qmp(result, 'return[0]/inserted/ro', False)
572 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
574 result = self.vm.qmp('blockdev-change-medium', id=self.device_name,
576 format=iotests.imgfmt,
577 read_only_mode='retain')
578 self.assert_qmp(result, 'error/class', 'GenericError')
580 result = self.vm.qmp('query-block')
581 self.assert_qmp(result, 'return[0]/inserted/ro', False)
582 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
584 def test_rw_ro_cycle(self):
585 os.chmod(new_img, 0444)
586 self.vm.add_drive(old_img, 'media=disk', 'none')
587 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
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)
594 result = self.vm.qmp('blockdev-add',
596 driver=iotests.imgfmt,
598 file={'filename': new_img,
600 self.assert_qmp(result, 'return', {})
602 result = self.vm.qmp('query-block')
603 self.assert_qmp(result, 'return[0]/inserted/ro', False)
604 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
606 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
607 self.assert_qmp(result, 'return', {})
609 result = self.vm.qmp('query-block')
610 self.assert_qmp_absent(result, 'return[0]/inserted')
612 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
614 self.assert_qmp(result, 'return', {})
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)
620 result = self.vm.qmp('query-block')
621 self.assert_qmp(result, 'return[0]/inserted/ro', True)
622 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
624 GeneralChangeTestsBaseClass = None
625 TestInitiallyFilled = None
626 TestInitiallyEmpty = None
629 class TestBlockJobsAfterCycle(ChangeBaseClass):
630 device_name = 'qdev0'
633 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K')
635 self.vm = iotests.VM()
636 self.vm.add_drive_raw("id=drive0,driver=null-co,if=none")
637 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name)
640 result = self.vm.qmp('query-block')
641 self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
643 # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
645 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name)
646 self.assert_qmp(result, 'return', {})
648 result = self.vm.qmp('query-block')
649 self.assert_qmp_absent(result, 'return[0]/inserted')
651 result = self.vm.qmp('blockdev-add',
653 driver=iotests.imgfmt,
654 file={'filename': old_img,
656 self.assert_qmp(result, 'return', {})
658 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name,
660 self.assert_qmp(result, 'return', {})
662 result = self.vm.qmp('query-block')
663 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
673 def test_snapshot_and_commit(self):
674 # We need backing file support
675 if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
678 result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
679 snapshot_file=new_img,
680 format=iotests.imgfmt)
681 self.assert_qmp(result, 'return', {})
683 result = self.vm.qmp('query-block')
684 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
685 self.assert_qmp(result,
686 'return[0]/inserted/image/backing-image/filename',
689 result = self.vm.qmp('block-commit', device='drive0')
690 self.assert_qmp(result, 'return', {})
692 self.vm.event_wait(name='BLOCK_JOB_READY')
694 result = self.vm.qmp('query-block-jobs')
695 self.assert_qmp(result, 'return[0]/device', 'drive0')
697 result = self.vm.qmp('block-job-complete', device='drive0')
698 self.assert_qmp(result, 'return', {})
700 self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
703 if __name__ == '__main__':
704 if iotests.qemu_default_machine != 'pc':
705 # We need floppy and IDE CD-ROM
706 iotests.notrun('not suitable for this machine type: %s' %
707 iotests.qemu_default_machine)
708 # Need to support image creation
709 iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2',
710 'vmdk', 'raw', 'vhdx', 'qed'])