mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes
[qemu/agraf.git] / tests / qemu-iotests / 041
blob720eeff92132151422277a320de054aa01af406f
1 #!/usr/bin/env python
3 # Tests for image mirroring.
5 # Copyright (C) 2012 Red Hat, Inc.
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.
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.
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/>.
21 import time
22 import os
23 import iotests
24 from iotests import qemu_img, qemu_io
25 import struct
27 backing_img = os.path.join(iotests.test_dir, 'backing.img')
28 target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
29 test_img = os.path.join(iotests.test_dir, 'test.img')
30 target_img = os.path.join(iotests.test_dir, 'target.img')
32 class ImageMirroringTestCase(iotests.QMPTestCase):
33 '''Abstract base class for image mirroring test cases'''
35 def assert_no_active_mirrors(self):
36 result = self.vm.qmp('query-block-jobs')
37 self.assert_qmp(result, 'return', [])
39 def cancel_and_wait(self, drive='drive0', wait_ready=True):
40 '''Cancel a block job and wait for it to finish'''
41 if wait_ready:
42 ready = False
43 while not ready:
44 for event in self.vm.get_qmp_events(wait=True):
45 if event['event'] == 'BLOCK_JOB_READY':
46 self.assert_qmp(event, 'data/type', 'mirror')
47 self.assert_qmp(event, 'data/device', drive)
48 ready = True
50 result = self.vm.qmp('block-job-cancel', device=drive,
51 force=not wait_ready)
52 self.assert_qmp(result, 'return', {})
54 cancelled = False
55 while not cancelled:
56 for event in self.vm.get_qmp_events(wait=True):
57 if event['event'] == 'BLOCK_JOB_COMPLETED' or \
58 event['event'] == 'BLOCK_JOB_CANCELLED':
59 self.assert_qmp(event, 'data/type', 'mirror')
60 self.assert_qmp(event, 'data/device', drive)
61 if wait_ready:
62 self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
63 self.assert_qmp(event, 'data/offset', self.image_len)
64 self.assert_qmp(event, 'data/len', self.image_len)
65 cancelled = True
67 self.assert_no_active_mirrors()
69 def complete_and_wait(self, drive='drive0', wait_ready=True):
70 '''Complete a block job and wait for it to finish'''
71 if wait_ready:
72 ready = False
73 while not ready:
74 for event in self.vm.get_qmp_events(wait=True):
75 if event['event'] == 'BLOCK_JOB_READY':
76 self.assert_qmp(event, 'data/type', 'mirror')
77 self.assert_qmp(event, 'data/device', drive)
78 ready = True
80 result = self.vm.qmp('block-job-complete', device=drive)
81 self.assert_qmp(result, 'return', {})
83 completed = False
84 while not completed:
85 for event in self.vm.get_qmp_events(wait=True):
86 if event['event'] == 'BLOCK_JOB_COMPLETED':
87 self.assert_qmp(event, 'data/type', 'mirror')
88 self.assert_qmp(event, 'data/device', drive)
89 self.assert_qmp_absent(event, 'data/error')
90 self.assert_qmp(event, 'data/offset', self.image_len)
91 self.assert_qmp(event, 'data/len', self.image_len)
92 completed = True
94 self.assert_no_active_mirrors()
96 def create_image(self, name, size):
97 file = open(name, 'w')
98 i = 0
99 while i < size:
100 sector = struct.pack('>l504xl', i / 512, i / 512)
101 file.write(sector)
102 i = i + 512
103 file.close()
105 def compare_images(self, img1, img2):
106 try:
107 qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img1, img1 + '.raw')
108 qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img2, img2 + '.raw')
109 file1 = open(img1 + '.raw', 'r')
110 file2 = open(img2 + '.raw', 'r')
111 return file1.read() == file2.read()
112 finally:
113 if file1 is not None:
114 file1.close()
115 if file2 is not None:
116 file2.close()
117 try:
118 os.remove(img1 + '.raw')
119 except OSError:
120 pass
121 try:
122 os.remove(img2 + '.raw')
123 except OSError:
124 pass
126 class TestSingleDrive(ImageMirroringTestCase):
127 image_len = 1 * 1024 * 1024 # MB
129 def setUp(self):
130 self.create_image(backing_img, TestSingleDrive.image_len)
131 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
132 self.vm = iotests.VM().add_drive(test_img)
133 self.vm.launch()
135 def tearDown(self):
136 self.vm.shutdown()
137 os.remove(test_img)
138 os.remove(backing_img)
139 try:
140 os.remove(target_img)
141 except OSError:
142 pass
144 def test_complete(self):
145 self.assert_no_active_mirrors()
147 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
148 target=target_img)
149 self.assert_qmp(result, 'return', {})
151 self.complete_and_wait()
152 result = self.vm.qmp('query-block')
153 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
154 self.vm.shutdown()
155 self.assertTrue(self.compare_images(test_img, target_img),
156 'target image does not match source after mirroring')
158 def test_cancel(self):
159 self.assert_no_active_mirrors()
161 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
162 target=target_img)
163 self.assert_qmp(result, 'return', {})
165 self.cancel_and_wait(wait_ready=False)
166 result = self.vm.qmp('query-block')
167 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
168 self.vm.shutdown()
170 def test_cancel_after_ready(self):
171 self.assert_no_active_mirrors()
173 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
174 target=target_img)
175 self.assert_qmp(result, 'return', {})
177 self.cancel_and_wait()
178 result = self.vm.qmp('query-block')
179 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
180 self.vm.shutdown()
181 self.assertTrue(self.compare_images(test_img, target_img),
182 'target image does not match source after mirroring')
184 def test_pause(self):
185 self.assert_no_active_mirrors()
187 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
188 target=target_img)
189 self.assert_qmp(result, 'return', {})
191 result = self.vm.qmp('block-job-pause', device='drive0')
192 self.assert_qmp(result, 'return', {})
194 time.sleep(1)
195 result = self.vm.qmp('query-block-jobs')
196 offset = self.dictpath(result, 'return[0]/offset')
198 time.sleep(1)
199 result = self.vm.qmp('query-block-jobs')
200 self.assert_qmp(result, 'return[0]/offset', offset)
202 result = self.vm.qmp('block-job-resume', device='drive0')
203 self.assert_qmp(result, 'return', {})
205 self.complete_and_wait()
206 self.vm.shutdown()
207 self.assertTrue(self.compare_images(test_img, target_img),
208 'target image does not match source after mirroring')
210 def test_small_buffer(self):
211 self.assert_no_active_mirrors()
213 # A small buffer is rounded up automatically
214 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
215 buf_size=4096, target=target_img)
216 self.assert_qmp(result, 'return', {})
218 self.complete_and_wait()
219 result = self.vm.qmp('query-block')
220 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
221 self.vm.shutdown()
222 self.assertTrue(self.compare_images(test_img, target_img),
223 'target image does not match source after mirroring')
225 def test_small_buffer2(self):
226 self.assert_no_active_mirrors()
228 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
229 % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img)
230 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
231 buf_size=65536, mode='existing', target=target_img)
232 self.assert_qmp(result, 'return', {})
234 self.complete_and_wait()
235 result = self.vm.qmp('query-block')
236 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
237 self.vm.shutdown()
238 self.assertTrue(self.compare_images(test_img, target_img),
239 'target image does not match source after mirroring')
241 def test_large_cluster(self):
242 self.assert_no_active_mirrors()
244 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
245 % (TestSingleDrive.image_len, backing_img), target_img)
246 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
247 mode='existing', target=target_img)
248 self.assert_qmp(result, 'return', {})
250 self.complete_and_wait()
251 result = self.vm.qmp('query-block')
252 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
253 self.vm.shutdown()
254 self.assertTrue(self.compare_images(test_img, target_img),
255 'target image does not match source after mirroring')
257 def test_medium_not_found(self):
258 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
259 target=target_img)
260 self.assert_qmp(result, 'error/class', 'GenericError')
262 def test_image_not_found(self):
263 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
264 mode='existing', target=target_img)
265 self.assert_qmp(result, 'error/class', 'GenericError')
267 def test_device_not_found(self):
268 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
269 target=target_img)
270 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
272 class TestMirrorNoBacking(ImageMirroringTestCase):
273 image_len = 2 * 1024 * 1024 # MB
275 def complete_and_wait(self, drive='drive0', wait_ready=True):
276 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
277 return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
279 def compare_images(self, img1, img2):
280 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
281 return ImageMirroringTestCase.compare_images(self, img1, img2)
283 def setUp(self):
284 self.create_image(backing_img, TestMirrorNoBacking.image_len)
285 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
286 self.vm = iotests.VM().add_drive(test_img)
287 self.vm.launch()
289 def tearDown(self):
290 self.vm.shutdown()
291 os.remove(test_img)
292 os.remove(backing_img)
293 os.remove(target_backing_img)
294 os.remove(target_img)
296 def test_complete(self):
297 self.assert_no_active_mirrors()
299 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
300 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
301 mode='existing', target=target_img)
302 self.assert_qmp(result, 'return', {})
304 self.complete_and_wait()
305 result = self.vm.qmp('query-block')
306 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
307 self.vm.shutdown()
308 self.assertTrue(self.compare_images(test_img, target_img),
309 'target image does not match source after mirroring')
311 def test_cancel(self):
312 self.assert_no_active_mirrors()
314 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
315 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
316 mode='existing', target=target_img)
317 self.assert_qmp(result, 'return', {})
319 self.cancel_and_wait()
320 result = self.vm.qmp('query-block')
321 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
322 self.vm.shutdown()
323 self.assertTrue(self.compare_images(test_img, target_img),
324 'target image does not match source after mirroring')
326 def test_large_cluster(self):
327 self.assert_no_active_mirrors()
329 # qemu-img create fails if the image is not there
330 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
331 %(TestMirrorNoBacking.image_len), target_backing_img)
332 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
333 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
334 os.remove(target_backing_img)
336 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
337 mode='existing', target=target_img)
338 self.assert_qmp(result, 'return', {})
340 self.complete_and_wait()
341 result = self.vm.qmp('query-block')
342 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
343 self.vm.shutdown()
344 self.assertTrue(self.compare_images(test_img, target_img),
345 'target image does not match source after mirroring')
347 class TestMirrorResized(ImageMirroringTestCase):
348 backing_len = 1 * 1024 * 1024 # MB
349 image_len = 2 * 1024 * 1024 # MB
351 def setUp(self):
352 self.create_image(backing_img, TestMirrorResized.backing_len)
353 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
354 qemu_img('resize', test_img, '2M')
355 self.vm = iotests.VM().add_drive(test_img)
356 self.vm.launch()
358 def tearDown(self):
359 self.vm.shutdown()
360 os.remove(test_img)
361 os.remove(backing_img)
362 try:
363 os.remove(target_img)
364 except OSError:
365 pass
367 def test_complete_top(self):
368 self.assert_no_active_mirrors()
370 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
371 target=target_img)
372 self.assert_qmp(result, 'return', {})
374 self.complete_and_wait()
375 result = self.vm.qmp('query-block')
376 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
377 self.vm.shutdown()
378 self.assertTrue(self.compare_images(test_img, target_img),
379 'target image does not match source after mirroring')
381 def test_complete_full(self):
382 self.assert_no_active_mirrors()
384 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
385 target=target_img)
386 self.assert_qmp(result, 'return', {})
388 self.complete_and_wait()
389 result = self.vm.qmp('query-block')
390 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
391 self.vm.shutdown()
392 self.assertTrue(self.compare_images(test_img, target_img),
393 'target image does not match source after mirroring')
395 class TestReadErrors(ImageMirroringTestCase):
396 image_len = 2 * 1024 * 1024 # MB
398 # this should be a multiple of twice the default granularity
399 # so that we hit this offset first in state 1
400 MIRROR_GRANULARITY = 1024 * 1024
402 def create_blkdebug_file(self, name, event, errno):
403 file = open(name, 'w')
404 file.write('''
405 [inject-error]
406 state = "1"
407 event = "%s"
408 errno = "%d"
409 immediately = "off"
410 once = "on"
411 sector = "%d"
413 [set-state]
414 state = "1"
415 event = "%s"
416 new_state = "2"
418 [set-state]
419 state = "2"
420 event = "%s"
421 new_state = "1"
422 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
423 file.close()
425 def setUp(self):
426 self.blkdebug_file = backing_img + ".blkdebug"
427 self.create_image(backing_img, TestReadErrors.image_len)
428 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
429 qemu_img('create', '-f', iotests.imgfmt,
430 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
431 % (self.blkdebug_file, backing_img),
432 test_img)
433 # Write something for tests that use sync='top'
434 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
435 test_img)
436 self.vm = iotests.VM().add_drive(test_img)
437 self.vm.launch()
439 def tearDown(self):
440 self.vm.shutdown()
441 os.remove(test_img)
442 os.remove(backing_img)
443 os.remove(self.blkdebug_file)
445 def test_report_read(self):
446 self.assert_no_active_mirrors()
448 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
449 target=target_img)
450 self.assert_qmp(result, 'return', {})
452 completed = False
453 error = False
454 while not completed:
455 for event in self.vm.get_qmp_events(wait=True):
456 if event['event'] == 'BLOCK_JOB_ERROR':
457 self.assert_qmp(event, 'data/device', 'drive0')
458 self.assert_qmp(event, 'data/operation', 'read')
459 error = True
460 elif event['event'] == 'BLOCK_JOB_READY':
461 self.assertTrue(False, 'job completed unexpectedly')
462 elif event['event'] == 'BLOCK_JOB_COMPLETED':
463 self.assertTrue(error, 'job completed unexpectedly')
464 self.assert_qmp(event, 'data/type', 'mirror')
465 self.assert_qmp(event, 'data/device', 'drive0')
466 self.assert_qmp(event, 'data/error', 'Input/output error')
467 self.assert_qmp(event, 'data/len', self.image_len)
468 completed = True
470 self.assert_no_active_mirrors()
471 self.vm.shutdown()
473 def test_ignore_read(self):
474 self.assert_no_active_mirrors()
476 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
477 target=target_img, on_source_error='ignore')
478 self.assert_qmp(result, 'return', {})
480 event = self.vm.get_qmp_event(wait=True)
481 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
482 self.assert_qmp(event, 'data/device', 'drive0')
483 self.assert_qmp(event, 'data/operation', 'read')
484 result = self.vm.qmp('query-block-jobs')
485 self.assert_qmp(result, 'return[0]/paused', False)
486 self.complete_and_wait()
487 self.vm.shutdown()
489 def test_large_cluster(self):
490 self.assert_no_active_mirrors()
492 # Test COW into the target image. The first half of the
493 # cluster at MIRROR_GRANULARITY has to be copied from
494 # backing_img, even though sync='top'.
495 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
496 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
497 on_source_error='ignore',
498 mode='existing', target=target_img)
499 self.assert_qmp(result, 'return', {})
501 event = self.vm.get_qmp_event(wait=True)
502 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
503 self.assert_qmp(event, 'data/device', 'drive0')
504 self.assert_qmp(event, 'data/operation', 'read')
505 result = self.vm.qmp('query-block-jobs')
506 self.assert_qmp(result, 'return[0]/paused', False)
507 self.complete_and_wait()
508 self.vm.shutdown()
510 # Detach blkdebug to compare images successfully
511 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
512 self.assertTrue(self.compare_images(test_img, target_img),
513 'target image does not match source after mirroring')
515 def test_stop_read(self):
516 self.assert_no_active_mirrors()
518 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
519 target=target_img, on_source_error='stop')
520 self.assert_qmp(result, 'return', {})
522 error = False
523 ready = False
524 while not ready:
525 for event in self.vm.get_qmp_events(wait=True):
526 if event['event'] == 'BLOCK_JOB_ERROR':
527 self.assert_qmp(event, 'data/device', 'drive0')
528 self.assert_qmp(event, 'data/operation', 'read')
530 result = self.vm.qmp('query-block-jobs')
531 self.assert_qmp(result, 'return[0]/paused', True)
532 self.assert_qmp(result, 'return[0]/io-status', 'failed')
534 result = self.vm.qmp('block-job-resume', device='drive0')
535 self.assert_qmp(result, 'return', {})
536 error = True
537 elif event['event'] == 'BLOCK_JOB_READY':
538 self.assertTrue(error, 'job completed unexpectedly')
539 self.assert_qmp(event, 'data/device', 'drive0')
540 ready = True
542 result = self.vm.qmp('query-block-jobs')
543 self.assert_qmp(result, 'return[0]/paused', False)
544 self.assert_qmp(result, 'return[0]/io-status', 'ok')
546 self.complete_and_wait(wait_ready=False)
547 self.assert_no_active_mirrors()
548 self.vm.shutdown()
550 class TestWriteErrors(ImageMirroringTestCase):
551 image_len = 2 * 1024 * 1024 # MB
553 # this should be a multiple of twice the default granularity
554 # so that we hit this offset first in state 1
555 MIRROR_GRANULARITY = 1024 * 1024
557 def create_blkdebug_file(self, name, event, errno):
558 file = open(name, 'w')
559 file.write('''
560 [inject-error]
561 state = "1"
562 event = "%s"
563 errno = "%d"
564 immediately = "off"
565 once = "on"
566 sector = "%d"
568 [set-state]
569 state = "1"
570 event = "%s"
571 new_state = "2"
573 [set-state]
574 state = "2"
575 event = "%s"
576 new_state = "1"
577 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
578 file.close()
580 def setUp(self):
581 self.blkdebug_file = target_img + ".blkdebug"
582 self.create_image(backing_img, TestWriteErrors.image_len)
583 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
584 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
585 self.vm = iotests.VM().add_drive(test_img)
586 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
587 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
588 self.vm.launch()
590 def tearDown(self):
591 self.vm.shutdown()
592 os.remove(test_img)
593 os.remove(backing_img)
594 os.remove(self.blkdebug_file)
596 def test_report_write(self):
597 self.assert_no_active_mirrors()
599 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
600 mode='existing', target=self.target_img)
601 self.assert_qmp(result, 'return', {})
603 completed = False
604 error = False
605 while not completed:
606 for event in self.vm.get_qmp_events(wait=True):
607 if event['event'] == 'BLOCK_JOB_ERROR':
608 self.assert_qmp(event, 'data/device', 'drive0')
609 self.assert_qmp(event, 'data/operation', 'write')
610 error = True
611 elif event['event'] == 'BLOCK_JOB_READY':
612 self.assertTrue(False, 'job completed unexpectedly')
613 elif event['event'] == 'BLOCK_JOB_COMPLETED':
614 self.assertTrue(error, 'job completed unexpectedly')
615 self.assert_qmp(event, 'data/type', 'mirror')
616 self.assert_qmp(event, 'data/device', 'drive0')
617 self.assert_qmp(event, 'data/error', 'Input/output error')
618 self.assert_qmp(event, 'data/len', self.image_len)
619 completed = True
621 self.assert_no_active_mirrors()
622 self.vm.shutdown()
624 def test_ignore_write(self):
625 self.assert_no_active_mirrors()
627 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
628 mode='existing', target=self.target_img,
629 on_target_error='ignore')
630 self.assert_qmp(result, 'return', {})
632 event = self.vm.get_qmp_event(wait=True)
633 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
634 self.assert_qmp(event, 'data/device', 'drive0')
635 self.assert_qmp(event, 'data/operation', 'write')
636 result = self.vm.qmp('query-block-jobs')
637 self.assert_qmp(result, 'return[0]/paused', False)
638 self.complete_and_wait()
639 self.vm.shutdown()
641 def test_stop_write(self):
642 self.assert_no_active_mirrors()
644 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
645 mode='existing', target=self.target_img,
646 on_target_error='stop')
647 self.assert_qmp(result, 'return', {})
649 error = False
650 ready = False
651 while not ready:
652 for event in self.vm.get_qmp_events(wait=True):
653 if event['event'] == 'BLOCK_JOB_ERROR':
654 self.assert_qmp(event, 'data/device', 'drive0')
655 self.assert_qmp(event, 'data/operation', 'write')
657 result = self.vm.qmp('query-block-jobs')
658 self.assert_qmp(result, 'return[0]/paused', True)
659 self.assert_qmp(result, 'return[0]/io-status', 'failed')
661 result = self.vm.qmp('block-job-resume', device='drive0')
662 self.assert_qmp(result, 'return', {})
664 result = self.vm.qmp('query-block-jobs')
665 self.assert_qmp(result, 'return[0]/paused', False)
666 self.assert_qmp(result, 'return[0]/io-status', 'ok')
667 error = True
668 elif event['event'] == 'BLOCK_JOB_READY':
669 self.assertTrue(error, 'job completed unexpectedly')
670 self.assert_qmp(event, 'data/device', 'drive0')
671 ready = True
673 self.complete_and_wait(wait_ready=False)
674 self.assert_no_active_mirrors()
675 self.vm.shutdown()
677 class TestSetSpeed(ImageMirroringTestCase):
678 image_len = 80 * 1024 * 1024 # MB
680 def setUp(self):
681 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
682 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
683 self.vm = iotests.VM().add_drive(test_img)
684 self.vm.launch()
686 def tearDown(self):
687 self.vm.shutdown()
688 os.remove(test_img)
689 os.remove(backing_img)
690 os.remove(target_img)
692 def test_set_speed(self):
693 self.assert_no_active_mirrors()
695 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
696 target=target_img)
697 self.assert_qmp(result, 'return', {})
699 # Default speed is 0
700 result = self.vm.qmp('query-block-jobs')
701 self.assert_qmp(result, 'return[0]/device', 'drive0')
702 self.assert_qmp(result, 'return[0]/speed', 0)
704 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
705 self.assert_qmp(result, 'return', {})
707 # Ensure the speed we set was accepted
708 result = self.vm.qmp('query-block-jobs')
709 self.assert_qmp(result, 'return[0]/device', 'drive0')
710 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
712 self.cancel_and_wait()
714 # Check setting speed in drive-mirror works
715 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
716 target=target_img, speed=4*1024*1024)
717 self.assert_qmp(result, 'return', {})
719 result = self.vm.qmp('query-block-jobs')
720 self.assert_qmp(result, 'return[0]/device', 'drive0')
721 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
723 self.cancel_and_wait()
725 def test_set_speed_invalid(self):
726 self.assert_no_active_mirrors()
728 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
729 target=target_img, speed=-1)
730 self.assert_qmp(result, 'error/class', 'GenericError')
732 self.assert_no_active_mirrors()
734 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
735 target=target_img)
736 self.assert_qmp(result, 'return', {})
738 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
739 self.assert_qmp(result, 'error/class', 'GenericError')
741 self.cancel_and_wait()
743 if __name__ == '__main__':
744 iotests.main(supported_fmts=['qcow2', 'qed'])