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, read_only_node=False): 211 result = self.vm.qmp('blockdev-add', 212 node_name='new', 213 driver=iotests.imgfmt, 214 read_only=read_only_node, 215 file={'filename': new_img, 216 'driver': 'file'}) 217 self.assert_qmp(result, 'return', {}) 218 219 result = self.vm.qmp('blockdev-open-tray', 220 id=self.device_name, force=True) 221 self.assert_qmp(result, 'return', {}) 222 223 self.wait_for_open() 224 225 result = self.vm.qmp('query-block') 226 if self.has_real_tray: 227 self.assert_qmp(result, 'return[0]/tray_open', True) 228 if self.was_empty == True: 229 self.assert_qmp_absent(result, 'return[0]/inserted') 230 else: 231 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 232 233 result = self.vm.qmp('blockdev-remove-medium', 234 id=self.device_name) 235 self.assert_qmp(result, 'return', {}) 236 237 result = self.vm.qmp('query-block') 238 if self.has_real_tray: 239 self.assert_qmp(result, 'return[0]/tray_open', True) 240 self.assert_qmp_absent(result, 'return[0]/inserted') 241 242 result = self.vm.qmp('blockdev-insert-medium', 243 id=self.device_name, node_name='new') 244 self.assert_qmp(result, 'return', {}) 245 246 result = self.vm.qmp('query-block') 247 if self.has_real_tray: 248 self.assert_qmp(result, 'return[0]/tray_open', True) 249 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 250 251 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 252 self.assert_qmp(result, 'return', {}) 253 254 self.wait_for_close() 255 256 result = self.vm.qmp('query-block') 257 if self.has_real_tray: 258 self.assert_qmp(result, 'return[0]/tray_open', False) 259 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 260 261 def test_cycle_read_only_media(self): 262 self.test_cycle(True) 263 264 def test_close_on_closed(self): 265 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 266 # Should be a no-op 267 self.assert_qmp(result, 'return', {}) 268 self.assertEqual(self.vm.get_qmp_events(wait=False), []) 269 270 def test_remove_on_closed(self): 271 if not self.has_real_tray: 272 return 273 274 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 275 self.assert_qmp(result, 'error/class', 'GenericError') 276 277 def test_insert_on_closed(self): 278 if not self.has_real_tray: 279 return 280 281 result = self.vm.qmp('blockdev-add', 282 node_name='new', 283 driver=iotests.imgfmt, 284 file={'filename': new_img, 285 'driver': 'file'}) 286 self.assert_qmp(result, 'return', {}) 287 288 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 289 node_name='new') 290 self.assert_qmp(result, 'error/class', 'GenericError') 291 292class TestInitiallyFilled(GeneralChangeTestsBaseClass): 293 was_empty = False 294 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), 302 self.device_name)) 303 self.vm.launch() 304 305 def tearDown(self): 306 self.vm.shutdown() 307 os.remove(old_img) 308 os.remove(new_img) 309 310 def test_insert_on_filled(self): 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('blockdev-open-tray', id=self.device_name) 319 self.assert_qmp(result, 'return', {}) 320 321 self.wait_for_open() 322 323 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 324 node_name='new') 325 self.assert_qmp(result, 'error/class', 'GenericError') 326 327class TestInitiallyEmpty(GeneralChangeTestsBaseClass): 328 was_empty = True 329 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), 335 self.device_name)) 336 self.vm.launch() 337 338 def tearDown(self): 339 self.vm.shutdown() 340 os.remove(new_img) 341 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', {}) 345 346 self.wait_for_open() 347 348 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 349 # Should be a no-op 350 self.assert_qmp(result, 'return', {}) 351 352class TestCDInitiallyFilled(TestInitiallyFilled): 353 TestInitiallyFilled = TestInitiallyFilled 354 has_real_tray = True 355 356 def setUp(self): 357 self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide') 358 359class TestCDInitiallyEmpty(TestInitiallyEmpty): 360 TestInitiallyEmpty = TestInitiallyEmpty 361 has_real_tray = True 362 363 def setUp(self): 364 self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide') 365 366class TestFloppyInitiallyFilled(TestInitiallyFilled): 367 TestInitiallyFilled = TestInitiallyFilled 368 has_real_tray = False 369 370 def setUp(self): 371 self.TestInitiallyFilled.setUp(self, 'disk', 'floppy') 372 373class TestFloppyInitiallyEmpty(TestInitiallyEmpty): 374 TestInitiallyEmpty = TestInitiallyEmpty 375 has_real_tray = False 376 377 def setUp(self): 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 382 383class TestChangeReadOnly(ChangeBaseClass): 384 device_name = 'qdev0' 385 386 def setUp(self): 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() 390 391 def tearDown(self): 392 self.vm.shutdown() 393 os.chmod(old_img, 0o666) 394 os.chmod(new_img, 0o666) 395 os.remove(old_img) 396 os.remove(new_img) 397 398 def test_ro_ro_retain(self): 399 os.chmod(old_img, 0o444) 400 os.chmod(new_img, 0o444) 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) 403 self.vm.launch() 404 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) 408 409 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 410 filename=new_img, 411 format=iotests.imgfmt, 412 read_only_mode='retain') 413 self.assert_qmp(result, 'return', {}) 414 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) 418 419 def test_ro_rw_retain(self): 420 os.chmod(old_img, 0o444) 421 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none') 422 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 423 self.vm.launch() 424 425 result = self.vm.qmp('query-block') 426 self.assert_qmp(result, 'return[0]/inserted/ro', True) 427 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 428 429 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 430 filename=new_img, 431 format=iotests.imgfmt, 432 read_only_mode='retain') 433 self.assert_qmp(result, 'return', {}) 434 435 result = self.vm.qmp('query-block') 436 self.assert_qmp(result, 'return[0]/inserted/ro', True) 437 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 438 439 def test_rw_ro_retain(self): 440 os.chmod(new_img, 0o444) 441 self.vm.add_drive(old_img, 'media=disk', 'none') 442 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 443 self.vm.launch() 444 445 result = self.vm.qmp('query-block') 446 self.assert_qmp(result, 'return[0]/inserted/ro', False) 447 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 448 449 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 450 filename=new_img, 451 format=iotests.imgfmt, 452 read_only_mode='retain') 453 self.assert_qmp(result, 'error/class', 'GenericError') 454 455 self.assertEqual(self.vm.get_qmp_events(wait=False), []) 456 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) 460 461 def test_ro_rw(self): 462 os.chmod(old_img, 0o444) 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) 465 self.vm.launch() 466 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) 470 471 result = self.vm.qmp('blockdev-change-medium', 472 id=self.device_name, 473 filename=new_img, 474 format=iotests.imgfmt, 475 read_only_mode='read-write') 476 self.assert_qmp(result, 'return', {}) 477 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) 481 482 def test_rw_ro(self): 483 os.chmod(new_img, 0o444) 484 self.vm.add_drive(old_img, 'media=disk', 'none') 485 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 486 self.vm.launch() 487 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) 491 492 result = self.vm.qmp('blockdev-change-medium', 493 id=self.device_name, 494 filename=new_img, 495 format=iotests.imgfmt, 496 read_only_mode='read-only') 497 self.assert_qmp(result, 'return', {}) 498 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) 502 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) 506 self.vm.launch() 507 508 result = self.vm.qmp('query-block') 509 self.assert_qmp(result, 'return[0]/inserted/ro', False) 510 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 511 512 result = self.vm.qmp('blockdev-change-medium', 513 id=self.device_name, 514 filename=new_img, 515 format=iotests.imgfmt, 516 read_only_mode='read-only') 517 self.assert_qmp(result, 'return', {}) 518 519 result = self.vm.qmp('query-block') 520 self.assert_qmp(result, 'return[0]/inserted/ro', True) 521 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 522 523 def test_make_ro_rw(self): 524 os.chmod(new_img, 0o444) 525 self.vm.add_drive(old_img, 'media=disk', 'none') 526 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 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 id=self.device_name, 535 filename=new_img, 536 format=iotests.imgfmt, 537 read_only_mode='read-write') 538 self.assert_qmp(result, 'error/class', 'GenericError') 539 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) 543 544 def test_make_rw_ro_by_retain(self): 545 os.chmod(old_img, 0o444) 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) 548 self.vm.launch() 549 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) 553 554 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 555 filename=new_img, 556 format=iotests.imgfmt, 557 read_only_mode='retain') 558 self.assert_qmp(result, 'return', {}) 559 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) 563 564 def test_make_ro_rw_by_retain(self): 565 os.chmod(new_img, 0o444) 566 self.vm.add_drive(old_img, 'media=disk', 'none') 567 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 568 self.vm.launch() 569 570 result = self.vm.qmp('query-block') 571 self.assert_qmp(result, 'return[0]/inserted/ro', False) 572 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 573 574 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 575 filename=new_img, 576 format=iotests.imgfmt, 577 read_only_mode='retain') 578 self.assert_qmp(result, 'error/class', 'GenericError') 579 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) 583 584 def test_rw_ro_cycle(self): 585 os.chmod(new_img, 0o444) 586 self.vm.add_drive(old_img, 'media=disk', 'none') 587 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 588 self.vm.launch() 589 590 result = self.vm.qmp('query-block') 591 self.assert_qmp(result, 'return[0]/inserted/ro', False) 592 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 593 594 result = self.vm.qmp('blockdev-add', 595 node_name='new', 596 driver=iotests.imgfmt, 597 read_only=True, 598 file={'filename': new_img, 599 'driver': 'file'}) 600 self.assert_qmp(result, 'return', {}) 601 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) 605 606 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 607 self.assert_qmp(result, 'return', {}) 608 609 result = self.vm.qmp('query-block') 610 self.assert_qmp_absent(result, 'return[0]/inserted') 611 612 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 613 node_name='new') 614 self.assert_qmp(result, 'return', {}) 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 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) 623 624GeneralChangeTestsBaseClass = None 625TestInitiallyFilled = None 626TestInitiallyEmpty = None 627 628 629class TestBlockJobsAfterCycle(ChangeBaseClass): 630 device_name = 'qdev0' 631 632 def setUp(self): 633 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K') 634 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) 638 self.vm.launch() 639 640 result = self.vm.qmp('query-block') 641 self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co') 642 643 # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray 644 # is not necessary 645 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 646 self.assert_qmp(result, 'return', {}) 647 648 result = self.vm.qmp('query-block') 649 self.assert_qmp_absent(result, 'return[0]/inserted') 650 651 result = self.vm.qmp('blockdev-add', 652 node_name='node0', 653 driver=iotests.imgfmt, 654 file={'filename': old_img, 655 'driver': 'file'}) 656 self.assert_qmp(result, 'return', {}) 657 658 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 659 node_name='node0') 660 self.assert_qmp(result, 'return', {}) 661 662 result = self.vm.qmp('query-block') 663 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 664 665 def tearDown(self): 666 self.vm.shutdown() 667 os.remove(old_img) 668 try: 669 os.remove(new_img) 670 except OSError: 671 pass 672 673 def test_snapshot_and_commit(self): 674 # We need backing file support 675 if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed': 676 return 677 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', {}) 682 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', 687 old_img) 688 689 result = self.vm.qmp('block-commit', device='drive0') 690 self.assert_qmp(result, 'return', {}) 691 692 self.vm.event_wait(name='BLOCK_JOB_READY') 693 694 result = self.vm.qmp('query-block-jobs') 695 self.assert_qmp(result, 'return[0]/device', 'drive0') 696 697 result = self.vm.qmp('block-job-complete', device='drive0') 698 self.assert_qmp(result, 'return', {}) 699 700 self.vm.event_wait(name='BLOCK_JOB_COMPLETED') 701 702 703if __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']) 711