1#!/usr/bin/env python3 2# group: rw 3# 4# Test case for the QMP 'change' command and all other associated 5# commands 6# 7# Copyright (C) 2015 Red Hat, Inc. 8# 9# This program is free software; you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation; either version 2 of the License, or 12# (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program. If not, see <http://www.gnu.org/licenses/>. 21# 22 23import os 24import stat 25import time 26import iotests 27from iotests import qemu_img 28 29old_img = os.path.join(iotests.test_dir, 'test0.img') 30new_img = os.path.join(iotests.test_dir, 'test1.img') 31 32def interface_to_device_name(interface): 33 if interface == 'ide': 34 return 'ide-cd' 35 elif interface == 'floppy': 36 return 'floppy' 37 elif interface == 'scsi': 38 return 'scsi-cd' 39 else: 40 return None 41 42class ChangeBaseClass(iotests.QMPTestCase): 43 has_opened = False 44 has_closed = False 45 46 device_name = 'qdev0' 47 use_drive = False 48 49 def process_events(self): 50 for event in self.vm.get_qmp_events(wait=False): 51 if (event['event'] == 'DEVICE_TRAY_MOVED' and 52 (event['data']['device'] == 'drive0' or 53 event['data']['id'] == self.device_name)): 54 if event['data']['tray-open'] == False: 55 self.has_closed = True 56 else: 57 self.has_opened = True 58 59 def wait_for_open(self): 60 if not self.has_real_tray: 61 return 62 63 with iotests.Timeout(3, 'Timeout while waiting for the tray to open'): 64 while not self.has_opened: 65 self.process_events() 66 67 def wait_for_close(self): 68 if not self.has_real_tray: 69 return 70 71 with iotests.Timeout(3, 'Timeout while waiting for the tray to close'): 72 while not self.has_closed: 73 self.process_events() 74 75class GeneralChangeTestsBaseClass(ChangeBaseClass): 76 77 def test_change(self): 78 # 'change' requires a drive name, so skip the test for blockdev 79 if not self.use_drive: 80 return 81 82 result = self.vm.qmp('change', device='drive0', target=new_img, 83 arg=iotests.imgfmt) 84 self.assert_qmp(result, 'return', {}) 85 86 self.wait_for_open() 87 self.wait_for_close() 88 89 result = self.vm.qmp('query-block') 90 if self.has_real_tray: 91 self.assert_qmp(result, 'return[0]/tray_open', False) 92 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 93 94 def test_blockdev_change_medium(self): 95 result = self.vm.qmp('blockdev-change-medium', 96 id=self.device_name, filename=new_img, 97 format=iotests.imgfmt) 98 99 self.assert_qmp(result, 'return', {}) 100 101 self.wait_for_open() 102 self.wait_for_close() 103 104 result = self.vm.qmp('query-block') 105 if self.has_real_tray: 106 self.assert_qmp(result, 'return[0]/tray_open', False) 107 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 108 109 def test_eject(self): 110 result = self.vm.qmp('eject', id=self.device_name, force=True) 111 self.assert_qmp(result, 'return', {}) 112 113 self.wait_for_open() 114 115 result = self.vm.qmp('query-block') 116 if self.has_real_tray: 117 self.assert_qmp(result, 'return[0]/tray_open', True) 118 self.assert_qmp_absent(result, 'return[0]/inserted') 119 120 def test_tray_eject_change(self): 121 result = self.vm.qmp('eject', id=self.device_name, force=True) 122 self.assert_qmp(result, 'return', {}) 123 124 self.wait_for_open() 125 126 result = self.vm.qmp('query-block') 127 if self.has_real_tray: 128 self.assert_qmp(result, 'return[0]/tray_open', True) 129 self.assert_qmp_absent(result, 'return[0]/inserted') 130 131 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 132 filename=new_img, format=iotests.imgfmt) 133 self.assert_qmp(result, 'return', {}) 134 135 self.wait_for_close() 136 137 result = self.vm.qmp('query-block') 138 if self.has_real_tray: 139 self.assert_qmp(result, 'return[0]/tray_open', False) 140 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 141 142 def test_tray_open_close(self): 143 result = self.vm.qmp('blockdev-open-tray', 144 id=self.device_name, force=True) 145 self.assert_qmp(result, 'return', {}) 146 147 self.wait_for_open() 148 149 result = self.vm.qmp('query-block') 150 if self.has_real_tray: 151 self.assert_qmp(result, 'return[0]/tray_open', True) 152 if self.was_empty == True: 153 self.assert_qmp_absent(result, 'return[0]/inserted') 154 else: 155 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 156 157 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 158 self.assert_qmp(result, 'return', {}) 159 160 if self.has_real_tray or not self.was_empty: 161 self.wait_for_close() 162 163 result = self.vm.qmp('query-block') 164 if self.has_real_tray: 165 self.assert_qmp(result, 'return[0]/tray_open', False) 166 if self.was_empty == True: 167 self.assert_qmp_absent(result, 'return[0]/inserted') 168 else: 169 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 170 171 def test_tray_eject_close(self): 172 result = self.vm.qmp('eject', id=self.device_name, force=True) 173 self.assert_qmp(result, 'return', {}) 174 175 self.wait_for_open() 176 177 result = self.vm.qmp('query-block') 178 if self.has_real_tray: 179 self.assert_qmp(result, 'return[0]/tray_open', True) 180 self.assert_qmp_absent(result, 'return[0]/inserted') 181 182 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 183 self.assert_qmp(result, 'return', {}) 184 185 self.wait_for_close() 186 187 result = self.vm.qmp('query-block') 188 if self.has_real_tray: 189 self.assert_qmp(result, 'return[0]/tray_open', False) 190 self.assert_qmp_absent(result, 'return[0]/inserted') 191 192 def test_tray_open_change(self): 193 result = self.vm.qmp('blockdev-open-tray', id=self.device_name, 194 force=True) 195 self.assert_qmp(result, 'return', {}) 196 197 self.wait_for_open() 198 199 result = self.vm.qmp('query-block') 200 if self.has_real_tray: 201 self.assert_qmp(result, 'return[0]/tray_open', True) 202 if self.was_empty == True: 203 self.assert_qmp_absent(result, 'return[0]/inserted') 204 else: 205 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 206 207 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 208 filename=new_img, 209 format=iotests.imgfmt) 210 self.assert_qmp(result, 'return', {}) 211 212 self.wait_for_close() 213 214 result = self.vm.qmp('query-block') 215 if self.has_real_tray: 216 self.assert_qmp(result, 'return[0]/tray_open', False) 217 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 218 219 def test_cycle(self, read_only_node=False): 220 result = self.vm.qmp('blockdev-add', 221 node_name='new', 222 driver=iotests.imgfmt, 223 read_only=read_only_node, 224 file={'filename': new_img, 225 'driver': 'file'}) 226 self.assert_qmp(result, 'return', {}) 227 228 result = self.vm.qmp('blockdev-open-tray', 229 id=self.device_name, force=True) 230 self.assert_qmp(result, 'return', {}) 231 232 self.wait_for_open() 233 234 result = self.vm.qmp('query-block') 235 if self.has_real_tray: 236 self.assert_qmp(result, 'return[0]/tray_open', True) 237 if self.was_empty == True: 238 self.assert_qmp_absent(result, 'return[0]/inserted') 239 else: 240 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 241 242 result = self.vm.qmp('blockdev-remove-medium', 243 id=self.device_name) 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_absent(result, 'return[0]/inserted') 250 251 result = self.vm.qmp('blockdev-insert-medium', 252 id=self.device_name, node_name='new') 253 self.assert_qmp(result, 'return', {}) 254 255 result = self.vm.qmp('query-block') 256 if self.has_real_tray: 257 self.assert_qmp(result, 'return[0]/tray_open', True) 258 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 259 260 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 261 self.assert_qmp(result, 'return', {}) 262 263 self.wait_for_close() 264 265 result = self.vm.qmp('query-block') 266 if self.has_real_tray: 267 self.assert_qmp(result, 'return[0]/tray_open', False) 268 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 269 270 def test_cycle_read_only_media(self): 271 self.test_cycle(True) 272 273 def test_close_on_closed(self): 274 result = self.vm.qmp('blockdev-close-tray', id=self.device_name) 275 # Should be a no-op 276 self.assert_qmp(result, 'return', {}) 277 self.assertEqual(self.vm.get_qmp_events(wait=False), []) 278 279 def test_remove_on_closed(self): 280 if not self.has_real_tray: 281 return 282 283 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 284 self.assert_qmp(result, 'error/class', 'GenericError') 285 286 def test_insert_on_closed(self): 287 if not self.has_real_tray: 288 return 289 290 result = self.vm.qmp('blockdev-add', 291 node_name='new', 292 driver=iotests.imgfmt, 293 file={'filename': new_img, 294 'driver': 'file'}) 295 self.assert_qmp(result, 'return', {}) 296 297 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 298 node_name='new') 299 self.assert_qmp(result, 'error/class', 'GenericError') 300 301class TestInitiallyFilled(GeneralChangeTestsBaseClass): 302 was_empty = False 303 304 def setUp(self): 305 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k') 306 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k') 307 self.vm = iotests.VM() 308 if self.use_drive: 309 self.vm.add_drive(old_img, 'media=%s' % self.media, 'none') 310 else: 311 self.vm.add_blockdev([ 'node-name=drive0', 312 'driver=%s' % iotests.imgfmt, 313 'file.driver=file', 314 'file.filename=%s' % old_img ]) 315 if self.interface == 'scsi': 316 self.vm.add_device('virtio-scsi-pci') 317 self.vm.add_device('%s,drive=drive0,id=%s' % 318 (interface_to_device_name(self.interface), 319 self.device_name)) 320 self.vm.launch() 321 322 def tearDown(self): 323 self.vm.shutdown() 324 os.remove(old_img) 325 os.remove(new_img) 326 327 def test_insert_on_filled(self): 328 result = self.vm.qmp('blockdev-add', 329 node_name='new', 330 driver=iotests.imgfmt, 331 file={'filename': new_img, 332 'driver': 'file'}) 333 self.assert_qmp(result, 'return', {}) 334 335 result = self.vm.qmp('blockdev-open-tray', id=self.device_name) 336 self.assert_qmp(result, 'return', {}) 337 338 self.wait_for_open() 339 340 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 341 node_name='new') 342 self.assert_qmp(result, 'error/class', 'GenericError') 343 344class TestInitiallyEmpty(GeneralChangeTestsBaseClass): 345 was_empty = True 346 347 def setUp(self): 348 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k') 349 self.vm = iotests.VM() 350 if self.use_drive: 351 self.vm.add_drive(None, 'media=%s' % self.media, 'none') 352 if self.interface == 'scsi': 353 self.vm.add_device('virtio-scsi-pci') 354 self.vm.add_device('%s,%sid=%s' % 355 (interface_to_device_name(self.interface), 356 'drive=drive0,' if self.use_drive else '', 357 self.device_name)) 358 self.vm.launch() 359 360 def tearDown(self): 361 self.vm.shutdown() 362 os.remove(new_img) 363 364 def test_remove_on_empty(self): 365 result = self.vm.qmp('blockdev-open-tray', id=self.device_name) 366 self.assert_qmp(result, 'return', {}) 367 368 self.wait_for_open() 369 370 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 371 # Should be a no-op 372 self.assert_qmp(result, 'return', {}) 373 374# Do this in a function to avoid leaking variables like case into the global 375# name space (otherwise tests would be run for the abstract base classes) 376def create_basic_test_classes(): 377 for (media, interface, has_real_tray) in [ ('cdrom', 'ide', True), 378 ('cdrom', 'scsi', True), 379 ('disk', 'floppy', False) ]: 380 381 for case in [ TestInitiallyFilled, TestInitiallyEmpty ]: 382 for use_drive in [ True, False ]: 383 attr = { 'media': media, 384 'interface': interface, 385 'has_real_tray': has_real_tray, 386 'use_drive': use_drive } 387 388 name = '%s_%s_%s_%s' % (case.__name__, media, interface, 389 'drive' if use_drive else 'blockdev') 390 globals()[name] = type(name, (case, ), attr) 391 392create_basic_test_classes() 393 394class TestChangeReadOnly(ChangeBaseClass): 395 device_name = 'qdev0' 396 397 def setUp(self): 398 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k') 399 qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k') 400 self.vm = iotests.VM() 401 402 def tearDown(self): 403 self.vm.shutdown() 404 os.chmod(old_img, 0o666) 405 os.chmod(new_img, 0o666) 406 os.remove(old_img) 407 os.remove(new_img) 408 409 def test_ro_ro_retain(self): 410 os.chmod(old_img, 0o444) 411 os.chmod(new_img, 0o444) 412 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none') 413 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 414 self.vm.launch() 415 416 result = self.vm.qmp('query-block') 417 self.assert_qmp(result, 'return[0]/inserted/ro', True) 418 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 419 420 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 421 filename=new_img, 422 format=iotests.imgfmt, 423 read_only_mode='retain') 424 self.assert_qmp(result, 'return', {}) 425 426 result = self.vm.qmp('query-block') 427 self.assert_qmp(result, 'return[0]/inserted/ro', True) 428 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 429 430 def test_ro_rw_retain(self): 431 os.chmod(old_img, 0o444) 432 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none') 433 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 434 self.vm.launch() 435 436 result = self.vm.qmp('query-block') 437 self.assert_qmp(result, 'return[0]/inserted/ro', True) 438 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 439 440 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 441 filename=new_img, 442 format=iotests.imgfmt, 443 read_only_mode='retain') 444 self.assert_qmp(result, 'return', {}) 445 446 result = self.vm.qmp('query-block') 447 self.assert_qmp(result, 'return[0]/inserted/ro', True) 448 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 449 450 @iotests.skip_if_user_is_root 451 def test_rw_ro_retain(self): 452 os.chmod(new_img, 0o444) 453 self.vm.add_drive(old_img, 'media=disk', 'none') 454 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 455 self.vm.launch() 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 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 462 filename=new_img, 463 format=iotests.imgfmt, 464 read_only_mode='retain') 465 self.assert_qmp(result, 'error/class', 'GenericError') 466 467 self.assertEqual(self.vm.get_qmp_events(wait=False), []) 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 def test_ro_rw(self): 474 os.chmod(old_img, 0o444) 475 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none') 476 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 477 self.vm.launch() 478 479 result = self.vm.qmp('query-block') 480 self.assert_qmp(result, 'return[0]/inserted/ro', True) 481 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 482 483 result = self.vm.qmp('blockdev-change-medium', 484 id=self.device_name, 485 filename=new_img, 486 format=iotests.imgfmt, 487 read_only_mode='read-write') 488 self.assert_qmp(result, 'return', {}) 489 490 result = self.vm.qmp('query-block') 491 self.assert_qmp(result, 'return[0]/inserted/ro', False) 492 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 493 494 def test_rw_ro(self): 495 os.chmod(new_img, 0o444) 496 self.vm.add_drive(old_img, 'media=disk', 'none') 497 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 498 self.vm.launch() 499 500 result = self.vm.qmp('query-block') 501 self.assert_qmp(result, 'return[0]/inserted/ro', False) 502 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 503 504 result = self.vm.qmp('blockdev-change-medium', 505 id=self.device_name, 506 filename=new_img, 507 format=iotests.imgfmt, 508 read_only_mode='read-only') 509 self.assert_qmp(result, 'return', {}) 510 511 result = self.vm.qmp('query-block') 512 self.assert_qmp(result, 'return[0]/inserted/ro', True) 513 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 514 515 def test_make_rw_ro(self): 516 self.vm.add_drive(old_img, 'media=disk', 'none') 517 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 518 self.vm.launch() 519 520 result = self.vm.qmp('query-block') 521 self.assert_qmp(result, 'return[0]/inserted/ro', False) 522 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 523 524 result = self.vm.qmp('blockdev-change-medium', 525 id=self.device_name, 526 filename=new_img, 527 format=iotests.imgfmt, 528 read_only_mode='read-only') 529 self.assert_qmp(result, 'return', {}) 530 531 result = self.vm.qmp('query-block') 532 self.assert_qmp(result, 'return[0]/inserted/ro', True) 533 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 534 535 @iotests.skip_if_user_is_root 536 def test_make_ro_rw(self): 537 os.chmod(new_img, 0o444) 538 self.vm.add_drive(old_img, 'media=disk', 'none') 539 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 540 self.vm.launch() 541 542 result = self.vm.qmp('query-block') 543 self.assert_qmp(result, 'return[0]/inserted/ro', False) 544 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 545 546 result = self.vm.qmp('blockdev-change-medium', 547 id=self.device_name, 548 filename=new_img, 549 format=iotests.imgfmt, 550 read_only_mode='read-write') 551 self.assert_qmp(result, 'error/class', 'GenericError') 552 553 result = self.vm.qmp('query-block') 554 self.assert_qmp(result, 'return[0]/inserted/ro', False) 555 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 556 557 def test_make_rw_ro_by_retain(self): 558 os.chmod(old_img, 0o444) 559 self.vm.add_drive(old_img, 'media=disk,read-only=on', 'none') 560 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 561 self.vm.launch() 562 563 result = self.vm.qmp('query-block') 564 self.assert_qmp(result, 'return[0]/inserted/ro', True) 565 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 566 567 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 568 filename=new_img, 569 format=iotests.imgfmt, 570 read_only_mode='retain') 571 self.assert_qmp(result, 'return', {}) 572 573 result = self.vm.qmp('query-block') 574 self.assert_qmp(result, 'return[0]/inserted/ro', True) 575 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 576 577 @iotests.skip_if_user_is_root 578 def test_make_ro_rw_by_retain(self): 579 os.chmod(new_img, 0o444) 580 self.vm.add_drive(old_img, 'media=disk', 'none') 581 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 582 self.vm.launch() 583 584 result = self.vm.qmp('query-block') 585 self.assert_qmp(result, 'return[0]/inserted/ro', False) 586 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 587 588 result = self.vm.qmp('blockdev-change-medium', id=self.device_name, 589 filename=new_img, 590 format=iotests.imgfmt, 591 read_only_mode='retain') 592 self.assert_qmp(result, 'error/class', 'GenericError') 593 594 result = self.vm.qmp('query-block') 595 self.assert_qmp(result, 'return[0]/inserted/ro', False) 596 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 597 598 def test_rw_ro_cycle(self): 599 os.chmod(new_img, 0o444) 600 self.vm.add_drive(old_img, 'media=disk', 'none') 601 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 602 self.vm.launch() 603 604 result = self.vm.qmp('query-block') 605 self.assert_qmp(result, 'return[0]/inserted/ro', False) 606 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 607 608 result = self.vm.qmp('blockdev-add', 609 node_name='new', 610 driver=iotests.imgfmt, 611 read_only=True, 612 file={'filename': new_img, 613 'driver': 'file'}) 614 self.assert_qmp(result, 'return', {}) 615 616 result = self.vm.qmp('query-block') 617 self.assert_qmp(result, 'return[0]/inserted/ro', False) 618 self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img) 619 620 result = self.vm.qmp('blockdev-remove-medium', id=self.device_name) 621 self.assert_qmp(result, 'return', {}) 622 623 result = self.vm.qmp('query-block') 624 self.assert_qmp_absent(result, 'return[0]/inserted') 625 626 result = self.vm.qmp('blockdev-insert-medium', id=self.device_name, 627 node_name='new') 628 self.assert_qmp(result, 'return', {}) 629 630 result = self.vm.qmp('query-block') 631 self.assert_qmp(result, 'return[0]/inserted/ro', True) 632 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 633 634 result = self.vm.qmp('query-block') 635 self.assert_qmp(result, 'return[0]/inserted/ro', True) 636 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 637 638GeneralChangeTestsBaseClass = None 639TestInitiallyFilled = None 640TestInitiallyEmpty = None 641 642 643class TestBlockJobsAfterCycle(ChangeBaseClass): 644 device_name = 'qdev0' 645 646 def setUp(self): 647 qemu_img('create', '-f', iotests.imgfmt, old_img, '1440K') 648 649 self.vm = iotests.VM() 650 self.vm.add_drive_raw("id=drive0,driver=null-co,if=none") 651 self.vm.add_device('floppy,drive=drive0,id=%s' % self.device_name) 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('blockdev-remove-medium', id=self.device_name) 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('blockdev-insert-medium', id=self.device_name, 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 # We need backing file support 688 @iotests.skip_for_formats(('vpc', 'parallels', 'qcow', 'vdi', 'vmdk', 'raw', 689 'vhdx')) 690 def test_snapshot_and_commit(self): 691 result = self.vm.qmp('blockdev-snapshot-sync', device='drive0', 692 snapshot_file=new_img, 693 format=iotests.imgfmt) 694 self.assert_qmp(result, 'return', {}) 695 696 result = self.vm.qmp('query-block') 697 self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) 698 self.assert_qmp(result, 699 'return[0]/inserted/image/backing-image/filename', 700 old_img) 701 702 result = self.vm.qmp('block-commit', device='drive0') 703 self.assert_qmp(result, 'return', {}) 704 705 self.vm.event_wait(name='BLOCK_JOB_READY') 706 707 result = self.vm.qmp('query-block-jobs') 708 self.assert_qmp(result, 'return[0]/device', 'drive0') 709 710 result = self.vm.qmp('block-job-complete', device='drive0') 711 self.assert_qmp(result, 'return', {}) 712 713 self.vm.event_wait(name='BLOCK_JOB_COMPLETED') 714 715 716if __name__ == '__main__': 717 if iotests.qemu_default_machine != 'pc': 718 # We need floppy and IDE CD-ROM 719 iotests.notrun('not suitable for this machine type: %s' % 720 iotests.qemu_default_machine) 721 # Need to support image creation 722 iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2', 723 'vmdk', 'raw', 'vhdx', 'qed'], 724 supported_protocols=['file']) 725