1#!/usr/bin/env python 2# 3# Tests for image mirroring. 4# 5# Copyright (C) 2012 Red Hat, Inc. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20 21import time 22import os 23import iotests 24from iotests import qemu_img, qemu_io 25 26backing_img = os.path.join(iotests.test_dir, 'backing.img') 27target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img') 28test_img = os.path.join(iotests.test_dir, 'test.img') 29target_img = os.path.join(iotests.test_dir, 'target.img') 30 31class ImageMirroringTestCase(iotests.QMPTestCase): 32 '''Abstract base class for image mirroring test cases''' 33 34 def wait_ready(self, drive='drive0'): 35 '''Wait until a block job BLOCK_JOB_READY event''' 36 ready = False 37 while not ready: 38 for event in self.vm.get_qmp_events(wait=True): 39 if event['event'] == 'BLOCK_JOB_READY': 40 self.assert_qmp(event, 'data/type', 'mirror') 41 self.assert_qmp(event, 'data/device', drive) 42 ready = True 43 44 def wait_ready_and_cancel(self, drive='drive0'): 45 self.wait_ready(drive) 46 event = self.cancel_and_wait() 47 self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') 48 self.assert_qmp(event, 'data/type', 'mirror') 49 self.assert_qmp(event, 'data/offset', self.image_len) 50 self.assert_qmp(event, 'data/len', self.image_len) 51 52 def complete_and_wait(self, drive='drive0', wait_ready=True): 53 '''Complete a block job and wait for it to finish''' 54 if wait_ready: 55 self.wait_ready() 56 57 result = self.vm.qmp('block-job-complete', device=drive) 58 self.assert_qmp(result, 'return', {}) 59 60 completed = False 61 while not completed: 62 for event in self.vm.get_qmp_events(wait=True): 63 if event['event'] == 'BLOCK_JOB_COMPLETED': 64 self.assert_qmp(event, 'data/type', 'mirror') 65 self.assert_qmp(event, 'data/device', drive) 66 self.assert_qmp_absent(event, 'data/error') 67 self.assert_qmp(event, 'data/offset', self.image_len) 68 self.assert_qmp(event, 'data/len', self.image_len) 69 completed = True 70 71 self.assert_no_active_block_jobs() 72 73class TestSingleDrive(ImageMirroringTestCase): 74 image_len = 1 * 1024 * 1024 # MB 75 76 def setUp(self): 77 iotests.create_image(backing_img, TestSingleDrive.image_len) 78 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 79 self.vm = iotests.VM().add_drive(test_img) 80 self.vm.launch() 81 82 def tearDown(self): 83 self.vm.shutdown() 84 os.remove(test_img) 85 os.remove(backing_img) 86 try: 87 os.remove(target_img) 88 except OSError: 89 pass 90 91 def test_complete(self): 92 self.assert_no_active_block_jobs() 93 94 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 95 target=target_img) 96 self.assert_qmp(result, 'return', {}) 97 98 self.complete_and_wait() 99 result = self.vm.qmp('query-block') 100 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 101 self.vm.shutdown() 102 self.assertTrue(iotests.compare_images(test_img, target_img), 103 'target image does not match source after mirroring') 104 105 def test_cancel(self): 106 self.assert_no_active_block_jobs() 107 108 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 109 target=target_img) 110 self.assert_qmp(result, 'return', {}) 111 112 self.cancel_and_wait(force=True) 113 result = self.vm.qmp('query-block') 114 self.assert_qmp(result, 'return[0]/inserted/file', test_img) 115 self.vm.shutdown() 116 117 def test_cancel_after_ready(self): 118 self.assert_no_active_block_jobs() 119 120 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 121 target=target_img) 122 self.assert_qmp(result, 'return', {}) 123 124 self.wait_ready_and_cancel() 125 result = self.vm.qmp('query-block') 126 self.assert_qmp(result, 'return[0]/inserted/file', test_img) 127 self.vm.shutdown() 128 self.assertTrue(iotests.compare_images(test_img, target_img), 129 'target image does not match source after mirroring') 130 131 def test_pause(self): 132 self.assert_no_active_block_jobs() 133 134 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 135 target=target_img) 136 self.assert_qmp(result, 'return', {}) 137 138 result = self.vm.qmp('block-job-pause', device='drive0') 139 self.assert_qmp(result, 'return', {}) 140 141 time.sleep(1) 142 result = self.vm.qmp('query-block-jobs') 143 offset = self.dictpath(result, 'return[0]/offset') 144 145 time.sleep(1) 146 result = self.vm.qmp('query-block-jobs') 147 self.assert_qmp(result, 'return[0]/offset', offset) 148 149 result = self.vm.qmp('block-job-resume', device='drive0') 150 self.assert_qmp(result, 'return', {}) 151 152 self.complete_and_wait() 153 self.vm.shutdown() 154 self.assertTrue(iotests.compare_images(test_img, target_img), 155 'target image does not match source after mirroring') 156 157 def test_small_buffer(self): 158 self.assert_no_active_block_jobs() 159 160 # A small buffer is rounded up automatically 161 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 162 buf_size=4096, target=target_img) 163 self.assert_qmp(result, 'return', {}) 164 165 self.complete_and_wait() 166 result = self.vm.qmp('query-block') 167 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 168 self.vm.shutdown() 169 self.assertTrue(iotests.compare_images(test_img, target_img), 170 'target image does not match source after mirroring') 171 172 def test_small_buffer2(self): 173 self.assert_no_active_block_jobs() 174 175 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' 176 % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img) 177 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 178 buf_size=65536, mode='existing', target=target_img) 179 self.assert_qmp(result, 'return', {}) 180 181 self.complete_and_wait() 182 result = self.vm.qmp('query-block') 183 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 184 self.vm.shutdown() 185 self.assertTrue(iotests.compare_images(test_img, target_img), 186 'target image does not match source after mirroring') 187 188 def test_large_cluster(self): 189 self.assert_no_active_block_jobs() 190 191 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' 192 % (TestSingleDrive.image_len, backing_img), target_img) 193 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 194 mode='existing', target=target_img) 195 self.assert_qmp(result, 'return', {}) 196 197 self.complete_and_wait() 198 result = self.vm.qmp('query-block') 199 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 200 self.vm.shutdown() 201 self.assertTrue(iotests.compare_images(test_img, target_img), 202 'target image does not match source after mirroring') 203 204 def test_medium_not_found(self): 205 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full', 206 target=target_img) 207 self.assert_qmp(result, 'error/class', 'GenericError') 208 209 def test_image_not_found(self): 210 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 211 mode='existing', target=target_img) 212 self.assert_qmp(result, 'error/class', 'GenericError') 213 214 def test_device_not_found(self): 215 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full', 216 target=target_img) 217 self.assert_qmp(result, 'error/class', 'DeviceNotFound') 218 219class TestMirrorNoBacking(ImageMirroringTestCase): 220 image_len = 2 * 1024 * 1024 # MB 221 222 def complete_and_wait(self, drive='drive0', wait_ready=True): 223 iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len) 224 return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready) 225 226 def compare_images(self, img1, img2): 227 iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len) 228 return iotests.compare_images(img1, img2) 229 230 def setUp(self): 231 iotests.create_image(backing_img, TestMirrorNoBacking.image_len) 232 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 233 self.vm = iotests.VM().add_drive(test_img) 234 self.vm.launch() 235 236 def tearDown(self): 237 self.vm.shutdown() 238 os.remove(test_img) 239 os.remove(backing_img) 240 os.remove(target_backing_img) 241 os.remove(target_img) 242 243 def test_complete(self): 244 self.assert_no_active_block_jobs() 245 246 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) 247 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 248 mode='existing', target=target_img) 249 self.assert_qmp(result, 'return', {}) 250 251 self.complete_and_wait() 252 result = self.vm.qmp('query-block') 253 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 254 self.vm.shutdown() 255 self.assertTrue(self.compare_images(test_img, target_img), 256 'target image does not match source after mirroring') 257 258 def test_cancel(self): 259 self.assert_no_active_block_jobs() 260 261 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) 262 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 263 mode='existing', target=target_img) 264 self.assert_qmp(result, 'return', {}) 265 266 self.wait_ready_and_cancel() 267 result = self.vm.qmp('query-block') 268 self.assert_qmp(result, 'return[0]/inserted/file', test_img) 269 self.vm.shutdown() 270 self.assertTrue(self.compare_images(test_img, target_img), 271 'target image does not match source after mirroring') 272 273 def test_large_cluster(self): 274 self.assert_no_active_block_jobs() 275 276 # qemu-img create fails if the image is not there 277 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' 278 %(TestMirrorNoBacking.image_len), target_backing_img) 279 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' 280 % (TestMirrorNoBacking.image_len, target_backing_img), target_img) 281 os.remove(target_backing_img) 282 283 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 284 mode='existing', target=target_img) 285 self.assert_qmp(result, 'return', {}) 286 287 self.complete_and_wait() 288 result = self.vm.qmp('query-block') 289 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 290 self.vm.shutdown() 291 self.assertTrue(self.compare_images(test_img, target_img), 292 'target image does not match source after mirroring') 293 294class TestMirrorResized(ImageMirroringTestCase): 295 backing_len = 1 * 1024 * 1024 # MB 296 image_len = 2 * 1024 * 1024 # MB 297 298 def setUp(self): 299 iotests.create_image(backing_img, TestMirrorResized.backing_len) 300 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 301 qemu_img('resize', test_img, '2M') 302 self.vm = iotests.VM().add_drive(test_img) 303 self.vm.launch() 304 305 def tearDown(self): 306 self.vm.shutdown() 307 os.remove(test_img) 308 os.remove(backing_img) 309 try: 310 os.remove(target_img) 311 except OSError: 312 pass 313 314 def test_complete_top(self): 315 self.assert_no_active_block_jobs() 316 317 result = self.vm.qmp('drive-mirror', device='drive0', sync='top', 318 target=target_img) 319 self.assert_qmp(result, 'return', {}) 320 321 self.complete_and_wait() 322 result = self.vm.qmp('query-block') 323 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 324 self.vm.shutdown() 325 self.assertTrue(iotests.compare_images(test_img, target_img), 326 'target image does not match source after mirroring') 327 328 def test_complete_full(self): 329 self.assert_no_active_block_jobs() 330 331 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 332 target=target_img) 333 self.assert_qmp(result, 'return', {}) 334 335 self.complete_and_wait() 336 result = self.vm.qmp('query-block') 337 self.assert_qmp(result, 'return[0]/inserted/file', target_img) 338 self.vm.shutdown() 339 self.assertTrue(iotests.compare_images(test_img, target_img), 340 'target image does not match source after mirroring') 341 342class TestReadErrors(ImageMirroringTestCase): 343 image_len = 2 * 1024 * 1024 # MB 344 345 # this should be a multiple of twice the default granularity 346 # so that we hit this offset first in state 1 347 MIRROR_GRANULARITY = 1024 * 1024 348 349 def create_blkdebug_file(self, name, event, errno): 350 file = open(name, 'w') 351 file.write(''' 352[inject-error] 353state = "1" 354event = "%s" 355errno = "%d" 356immediately = "off" 357once = "on" 358sector = "%d" 359 360[set-state] 361state = "1" 362event = "%s" 363new_state = "2" 364 365[set-state] 366state = "2" 367event = "%s" 368new_state = "1" 369''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) 370 file.close() 371 372 def setUp(self): 373 self.blkdebug_file = backing_img + ".blkdebug" 374 iotests.create_image(backing_img, TestReadErrors.image_len) 375 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) 376 qemu_img('create', '-f', iotests.imgfmt, 377 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' 378 % (self.blkdebug_file, backing_img), 379 test_img) 380 # Write something for tests that use sync='top' 381 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536), 382 test_img) 383 self.vm = iotests.VM().add_drive(test_img) 384 self.vm.launch() 385 386 def tearDown(self): 387 self.vm.shutdown() 388 os.remove(test_img) 389 os.remove(backing_img) 390 os.remove(self.blkdebug_file) 391 392 def test_report_read(self): 393 self.assert_no_active_block_jobs() 394 395 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 396 target=target_img) 397 self.assert_qmp(result, 'return', {}) 398 399 completed = False 400 error = False 401 while not completed: 402 for event in self.vm.get_qmp_events(wait=True): 403 if event['event'] == 'BLOCK_JOB_ERROR': 404 self.assert_qmp(event, 'data/device', 'drive0') 405 self.assert_qmp(event, 'data/operation', 'read') 406 error = True 407 elif event['event'] == 'BLOCK_JOB_READY': 408 self.assertTrue(False, 'job completed unexpectedly') 409 elif event['event'] == 'BLOCK_JOB_COMPLETED': 410 self.assertTrue(error, 'job completed unexpectedly') 411 self.assert_qmp(event, 'data/type', 'mirror') 412 self.assert_qmp(event, 'data/device', 'drive0') 413 self.assert_qmp(event, 'data/error', 'Input/output error') 414 self.assert_qmp(event, 'data/len', self.image_len) 415 completed = True 416 417 self.assert_no_active_block_jobs() 418 self.vm.shutdown() 419 420 def test_ignore_read(self): 421 self.assert_no_active_block_jobs() 422 423 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 424 target=target_img, on_source_error='ignore') 425 self.assert_qmp(result, 'return', {}) 426 427 event = self.vm.get_qmp_event(wait=True) 428 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 429 self.assert_qmp(event, 'data/device', 'drive0') 430 self.assert_qmp(event, 'data/operation', 'read') 431 result = self.vm.qmp('query-block-jobs') 432 self.assert_qmp(result, 'return[0]/paused', False) 433 self.complete_and_wait() 434 self.vm.shutdown() 435 436 def test_large_cluster(self): 437 self.assert_no_active_block_jobs() 438 439 # Test COW into the target image. The first half of the 440 # cluster at MIRROR_GRANULARITY has to be copied from 441 # backing_img, even though sync='top'. 442 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img) 443 result = self.vm.qmp('drive-mirror', device='drive0', sync='top', 444 on_source_error='ignore', 445 mode='existing', target=target_img) 446 self.assert_qmp(result, 'return', {}) 447 448 event = self.vm.get_qmp_event(wait=True) 449 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 450 self.assert_qmp(event, 'data/device', 'drive0') 451 self.assert_qmp(event, 'data/operation', 'read') 452 result = self.vm.qmp('query-block-jobs') 453 self.assert_qmp(result, 'return[0]/paused', False) 454 self.complete_and_wait() 455 self.vm.shutdown() 456 457 # Detach blkdebug to compare images successfully 458 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) 459 self.assertTrue(iotests.compare_images(test_img, target_img), 460 'target image does not match source after mirroring') 461 462 def test_stop_read(self): 463 self.assert_no_active_block_jobs() 464 465 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 466 target=target_img, on_source_error='stop') 467 self.assert_qmp(result, 'return', {}) 468 469 error = False 470 ready = False 471 while not ready: 472 for event in self.vm.get_qmp_events(wait=True): 473 if event['event'] == 'BLOCK_JOB_ERROR': 474 self.assert_qmp(event, 'data/device', 'drive0') 475 self.assert_qmp(event, 'data/operation', 'read') 476 477 result = self.vm.qmp('query-block-jobs') 478 self.assert_qmp(result, 'return[0]/paused', True) 479 self.assert_qmp(result, 'return[0]/io-status', 'failed') 480 481 result = self.vm.qmp('block-job-resume', device='drive0') 482 self.assert_qmp(result, 'return', {}) 483 error = True 484 elif event['event'] == 'BLOCK_JOB_READY': 485 self.assertTrue(error, 'job completed unexpectedly') 486 self.assert_qmp(event, 'data/device', 'drive0') 487 ready = True 488 489 result = self.vm.qmp('query-block-jobs') 490 self.assert_qmp(result, 'return[0]/paused', False) 491 self.assert_qmp(result, 'return[0]/io-status', 'ok') 492 493 self.complete_and_wait(wait_ready=False) 494 self.assert_no_active_block_jobs() 495 self.vm.shutdown() 496 497class TestWriteErrors(ImageMirroringTestCase): 498 image_len = 2 * 1024 * 1024 # MB 499 500 # this should be a multiple of twice the default granularity 501 # so that we hit this offset first in state 1 502 MIRROR_GRANULARITY = 1024 * 1024 503 504 def create_blkdebug_file(self, name, event, errno): 505 file = open(name, 'w') 506 file.write(''' 507[inject-error] 508state = "1" 509event = "%s" 510errno = "%d" 511immediately = "off" 512once = "on" 513sector = "%d" 514 515[set-state] 516state = "1" 517event = "%s" 518new_state = "2" 519 520[set-state] 521state = "2" 522event = "%s" 523new_state = "1" 524''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) 525 file.close() 526 527 def setUp(self): 528 self.blkdebug_file = target_img + ".blkdebug" 529 iotests.create_image(backing_img, TestWriteErrors.image_len) 530 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) 531 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) 532 self.vm = iotests.VM().add_drive(test_img) 533 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img) 534 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img) 535 self.vm.launch() 536 537 def tearDown(self): 538 self.vm.shutdown() 539 os.remove(test_img) 540 os.remove(backing_img) 541 os.remove(self.blkdebug_file) 542 543 def test_report_write(self): 544 self.assert_no_active_block_jobs() 545 546 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 547 mode='existing', target=self.target_img) 548 self.assert_qmp(result, 'return', {}) 549 550 completed = False 551 error = False 552 while not completed: 553 for event in self.vm.get_qmp_events(wait=True): 554 if event['event'] == 'BLOCK_JOB_ERROR': 555 self.assert_qmp(event, 'data/device', 'drive0') 556 self.assert_qmp(event, 'data/operation', 'write') 557 error = True 558 elif event['event'] == 'BLOCK_JOB_READY': 559 self.assertTrue(False, 'job completed unexpectedly') 560 elif event['event'] == 'BLOCK_JOB_COMPLETED': 561 self.assertTrue(error, 'job completed unexpectedly') 562 self.assert_qmp(event, 'data/type', 'mirror') 563 self.assert_qmp(event, 'data/device', 'drive0') 564 self.assert_qmp(event, 'data/error', 'Input/output error') 565 self.assert_qmp(event, 'data/len', self.image_len) 566 completed = True 567 568 self.assert_no_active_block_jobs() 569 self.vm.shutdown() 570 571 def test_ignore_write(self): 572 self.assert_no_active_block_jobs() 573 574 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 575 mode='existing', target=self.target_img, 576 on_target_error='ignore') 577 self.assert_qmp(result, 'return', {}) 578 579 event = self.vm.get_qmp_event(wait=True) 580 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') 581 self.assert_qmp(event, 'data/device', 'drive0') 582 self.assert_qmp(event, 'data/operation', 'write') 583 result = self.vm.qmp('query-block-jobs') 584 self.assert_qmp(result, 'return[0]/paused', False) 585 self.complete_and_wait() 586 self.vm.shutdown() 587 588 def test_stop_write(self): 589 self.assert_no_active_block_jobs() 590 591 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 592 mode='existing', target=self.target_img, 593 on_target_error='stop') 594 self.assert_qmp(result, 'return', {}) 595 596 error = False 597 ready = False 598 while not ready: 599 for event in self.vm.get_qmp_events(wait=True): 600 if event['event'] == 'BLOCK_JOB_ERROR': 601 self.assert_qmp(event, 'data/device', 'drive0') 602 self.assert_qmp(event, 'data/operation', 'write') 603 604 result = self.vm.qmp('query-block-jobs') 605 self.assert_qmp(result, 'return[0]/paused', True) 606 self.assert_qmp(result, 'return[0]/io-status', 'failed') 607 608 result = self.vm.qmp('block-job-resume', device='drive0') 609 self.assert_qmp(result, 'return', {}) 610 611 result = self.vm.qmp('query-block-jobs') 612 self.assert_qmp(result, 'return[0]/paused', False) 613 self.assert_qmp(result, 'return[0]/io-status', 'ok') 614 error = True 615 elif event['event'] == 'BLOCK_JOB_READY': 616 self.assertTrue(error, 'job completed unexpectedly') 617 self.assert_qmp(event, 'data/device', 'drive0') 618 ready = True 619 620 self.complete_and_wait(wait_ready=False) 621 self.assert_no_active_block_jobs() 622 self.vm.shutdown() 623 624class TestSetSpeed(ImageMirroringTestCase): 625 image_len = 80 * 1024 * 1024 # MB 626 627 def setUp(self): 628 qemu_img('create', backing_img, str(TestSetSpeed.image_len)) 629 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) 630 self.vm = iotests.VM().add_drive(test_img) 631 self.vm.launch() 632 633 def tearDown(self): 634 self.vm.shutdown() 635 os.remove(test_img) 636 os.remove(backing_img) 637 os.remove(target_img) 638 639 def test_set_speed(self): 640 self.assert_no_active_block_jobs() 641 642 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 643 target=target_img) 644 self.assert_qmp(result, 'return', {}) 645 646 # Default speed is 0 647 result = self.vm.qmp('query-block-jobs') 648 self.assert_qmp(result, 'return[0]/device', 'drive0') 649 self.assert_qmp(result, 'return[0]/speed', 0) 650 651 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024) 652 self.assert_qmp(result, 'return', {}) 653 654 # Ensure the speed we set was accepted 655 result = self.vm.qmp('query-block-jobs') 656 self.assert_qmp(result, 'return[0]/device', 'drive0') 657 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024) 658 659 self.wait_ready_and_cancel() 660 661 # Check setting speed in drive-mirror works 662 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 663 target=target_img, speed=4*1024*1024) 664 self.assert_qmp(result, 'return', {}) 665 666 result = self.vm.qmp('query-block-jobs') 667 self.assert_qmp(result, 'return[0]/device', 'drive0') 668 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024) 669 670 self.wait_ready_and_cancel() 671 672 def test_set_speed_invalid(self): 673 self.assert_no_active_block_jobs() 674 675 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 676 target=target_img, speed=-1) 677 self.assert_qmp(result, 'error/class', 'GenericError') 678 679 self.assert_no_active_block_jobs() 680 681 result = self.vm.qmp('drive-mirror', device='drive0', sync='full', 682 target=target_img) 683 self.assert_qmp(result, 'return', {}) 684 685 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1) 686 self.assert_qmp(result, 'error/class', 'GenericError') 687 688 self.wait_ready_and_cancel() 689 690if __name__ == '__main__': 691 iotests.main(supported_fmts=['qcow2', 'qed']) 692