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