usb/ehci: split into multiple source files
[qemu/kevin.git] / tests / qemu-iotests / 041
blobc6eb851871385b238c905300c93526a8d3f213c7
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_large_cluster(self):
211 self.assert_no_active_mirrors()
213 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
214 % (TestSingleDrive.image_len, backing_img), target_img)
215 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
216 mode='existing', target=target_img)
217 self.assert_qmp(result, 'return', {})
219 self.complete_and_wait()
220 result = self.vm.qmp('query-block')
221 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
222 self.vm.shutdown()
223 self.assertTrue(self.compare_images(test_img, target_img),
224 'target image does not match source after mirroring')
226 def test_medium_not_found(self):
227 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
228 target=target_img)
229 self.assert_qmp(result, 'error/class', 'GenericError')
231 def test_image_not_found(self):
232 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
233 mode='existing', target=target_img)
234 self.assert_qmp(result, 'error/class', 'GenericError')
236 def test_device_not_found(self):
237 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
238 target=target_img)
239 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
241 class TestMirrorNoBacking(ImageMirroringTestCase):
242 image_len = 2 * 1024 * 1024 # MB
244 def complete_and_wait(self, drive='drive0', wait_ready=True):
245 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
246 return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
248 def compare_images(self, img1, img2):
249 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
250 return ImageMirroringTestCase.compare_images(self, img1, img2)
252 def setUp(self):
253 self.create_image(backing_img, TestMirrorNoBacking.image_len)
254 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
255 self.vm = iotests.VM().add_drive(test_img)
256 self.vm.launch()
258 def tearDown(self):
259 self.vm.shutdown()
260 os.remove(test_img)
261 os.remove(backing_img)
262 os.remove(target_backing_img)
263 os.remove(target_img)
265 def test_complete(self):
266 self.assert_no_active_mirrors()
268 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
269 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
270 mode='existing', target=target_img)
271 self.assert_qmp(result, 'return', {})
273 self.complete_and_wait()
274 result = self.vm.qmp('query-block')
275 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
276 self.vm.shutdown()
277 self.assertTrue(self.compare_images(test_img, target_img),
278 'target image does not match source after mirroring')
280 def test_cancel(self):
281 self.assert_no_active_mirrors()
283 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
284 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
285 mode='existing', target=target_img)
286 self.assert_qmp(result, 'return', {})
288 self.cancel_and_wait()
289 result = self.vm.qmp('query-block')
290 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
291 self.vm.shutdown()
292 self.assertTrue(self.compare_images(test_img, target_img),
293 'target image does not match source after mirroring')
295 class TestReadErrors(ImageMirroringTestCase):
296 image_len = 2 * 1024 * 1024 # MB
298 # this should be a multiple of twice the default granularity
299 # so that we hit this offset first in state 1
300 MIRROR_GRANULARITY = 1024 * 1024
302 def create_blkdebug_file(self, name, event, errno):
303 file = open(name, 'w')
304 file.write('''
305 [inject-error]
306 state = "1"
307 event = "%s"
308 errno = "%d"
309 immediately = "off"
310 once = "on"
311 sector = "%d"
313 [set-state]
314 state = "1"
315 event = "%s"
316 new_state = "2"
318 [set-state]
319 state = "2"
320 event = "%s"
321 new_state = "1"
322 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
323 file.close()
325 def setUp(self):
326 self.blkdebug_file = backing_img + ".blkdebug"
327 self.create_image(backing_img, TestReadErrors.image_len)
328 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
329 qemu_img('create', '-f', iotests.imgfmt,
330 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
331 % (self.blkdebug_file, backing_img),
332 test_img)
333 self.vm = iotests.VM().add_drive(test_img)
334 self.vm.launch()
336 def tearDown(self):
337 self.vm.shutdown()
338 os.remove(test_img)
339 os.remove(backing_img)
340 os.remove(self.blkdebug_file)
342 def test_report_read(self):
343 self.assert_no_active_mirrors()
345 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
346 target=target_img)
347 self.assert_qmp(result, 'return', {})
349 completed = False
350 error = False
351 while not completed:
352 for event in self.vm.get_qmp_events(wait=True):
353 if event['event'] == 'BLOCK_JOB_ERROR':
354 self.assert_qmp(event, 'data/device', 'drive0')
355 self.assert_qmp(event, 'data/operation', 'read')
356 error = True
357 elif event['event'] == 'BLOCK_JOB_READY':
358 self.assertTrue(False, 'job completed unexpectedly')
359 elif event['event'] == 'BLOCK_JOB_COMPLETED':
360 self.assertTrue(error, 'job completed unexpectedly')
361 self.assert_qmp(event, 'data/type', 'mirror')
362 self.assert_qmp(event, 'data/device', 'drive0')
363 self.assert_qmp(event, 'data/error', 'Input/output error')
364 self.assert_qmp(event, 'data/len', self.image_len)
365 completed = True
367 self.assert_no_active_mirrors()
368 self.vm.shutdown()
370 def test_ignore_read(self):
371 self.assert_no_active_mirrors()
373 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
374 target=target_img, on_source_error='ignore')
375 self.assert_qmp(result, 'return', {})
377 event = self.vm.get_qmp_event(wait=True)
378 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
379 self.assert_qmp(event, 'data/device', 'drive0')
380 self.assert_qmp(event, 'data/operation', 'read')
381 result = self.vm.qmp('query-block-jobs')
382 self.assert_qmp(result, 'return[0]/paused', False)
383 self.complete_and_wait()
384 self.vm.shutdown()
386 def test_stop_read(self):
387 self.assert_no_active_mirrors()
389 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
390 target=target_img, on_source_error='stop')
391 self.assert_qmp(result, 'return', {})
393 error = False
394 ready = False
395 while not ready:
396 for event in self.vm.get_qmp_events(wait=True):
397 if event['event'] == 'BLOCK_JOB_ERROR':
398 self.assert_qmp(event, 'data/device', 'drive0')
399 self.assert_qmp(event, 'data/operation', 'read')
401 result = self.vm.qmp('query-block-jobs')
402 self.assert_qmp(result, 'return[0]/paused', True)
403 self.assert_qmp(result, 'return[0]/io-status', 'failed')
405 result = self.vm.qmp('block-job-resume', device='drive0')
406 self.assert_qmp(result, 'return', {})
407 error = True
408 elif event['event'] == 'BLOCK_JOB_READY':
409 self.assertTrue(error, 'job completed unexpectedly')
410 self.assert_qmp(event, 'data/device', 'drive0')
411 ready = True
413 result = self.vm.qmp('query-block-jobs')
414 self.assert_qmp(result, 'return[0]/paused', False)
415 self.assert_qmp(result, 'return[0]/io-status', 'ok')
417 self.complete_and_wait(wait_ready=False)
418 self.assert_no_active_mirrors()
419 self.vm.shutdown()
421 class TestWriteErrors(ImageMirroringTestCase):
422 image_len = 2 * 1024 * 1024 # MB
424 # this should be a multiple of twice the default granularity
425 # so that we hit this offset first in state 1
426 MIRROR_GRANULARITY = 1024 * 1024
428 def create_blkdebug_file(self, name, event, errno):
429 file = open(name, 'w')
430 file.write('''
431 [inject-error]
432 state = "1"
433 event = "%s"
434 errno = "%d"
435 immediately = "off"
436 once = "on"
437 sector = "%d"
439 [set-state]
440 state = "1"
441 event = "%s"
442 new_state = "2"
444 [set-state]
445 state = "2"
446 event = "%s"
447 new_state = "1"
448 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
449 file.close()
451 def setUp(self):
452 self.blkdebug_file = target_img + ".blkdebug"
453 self.create_image(backing_img, TestWriteErrors.image_len)
454 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
455 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
456 self.vm = iotests.VM().add_drive(test_img)
457 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
458 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
459 self.vm.launch()
461 def tearDown(self):
462 self.vm.shutdown()
463 os.remove(test_img)
464 os.remove(backing_img)
465 os.remove(self.blkdebug_file)
467 def test_report_write(self):
468 self.assert_no_active_mirrors()
470 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
471 mode='existing', target=self.target_img)
472 self.assert_qmp(result, 'return', {})
474 completed = False
475 error = False
476 while not completed:
477 for event in self.vm.get_qmp_events(wait=True):
478 if event['event'] == 'BLOCK_JOB_ERROR':
479 self.assert_qmp(event, 'data/device', 'drive0')
480 self.assert_qmp(event, 'data/operation', 'write')
481 error = True
482 elif event['event'] == 'BLOCK_JOB_READY':
483 self.assertTrue(False, 'job completed unexpectedly')
484 elif event['event'] == 'BLOCK_JOB_COMPLETED':
485 self.assertTrue(error, 'job completed unexpectedly')
486 self.assert_qmp(event, 'data/type', 'mirror')
487 self.assert_qmp(event, 'data/device', 'drive0')
488 self.assert_qmp(event, 'data/error', 'Input/output error')
489 self.assert_qmp(event, 'data/len', self.image_len)
490 completed = True
492 self.assert_no_active_mirrors()
493 self.vm.shutdown()
495 def test_ignore_write(self):
496 self.assert_no_active_mirrors()
498 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
499 mode='existing', target=self.target_img,
500 on_target_error='ignore')
501 self.assert_qmp(result, 'return', {})
503 event = self.vm.get_qmp_event(wait=True)
504 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
505 self.assert_qmp(event, 'data/device', 'drive0')
506 self.assert_qmp(event, 'data/operation', 'write')
507 result = self.vm.qmp('query-block-jobs')
508 self.assert_qmp(result, 'return[0]/paused', False)
509 self.complete_and_wait()
510 self.vm.shutdown()
512 def test_stop_write(self):
513 self.assert_no_active_mirrors()
515 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
516 mode='existing', target=self.target_img,
517 on_target_error='stop')
518 self.assert_qmp(result, 'return', {})
520 error = False
521 ready = False
522 while not ready:
523 for event in self.vm.get_qmp_events(wait=True):
524 if event['event'] == 'BLOCK_JOB_ERROR':
525 self.assert_qmp(event, 'data/device', 'drive0')
526 self.assert_qmp(event, 'data/operation', 'write')
528 result = self.vm.qmp('query-block-jobs')
529 self.assert_qmp(result, 'return[0]/paused', True)
530 self.assert_qmp(result, 'return[0]/io-status', 'failed')
532 result = self.vm.qmp('block-job-resume', device='drive0')
533 self.assert_qmp(result, 'return', {})
535 result = self.vm.qmp('query-block-jobs')
536 self.assert_qmp(result, 'return[0]/paused', False)
537 self.assert_qmp(result, 'return[0]/io-status', 'ok')
538 error = True
539 elif event['event'] == 'BLOCK_JOB_READY':
540 self.assertTrue(error, 'job completed unexpectedly')
541 self.assert_qmp(event, 'data/device', 'drive0')
542 ready = True
544 self.complete_and_wait(wait_ready=False)
545 self.assert_no_active_mirrors()
546 self.vm.shutdown()
548 class TestSetSpeed(ImageMirroringTestCase):
549 image_len = 80 * 1024 * 1024 # MB
551 def setUp(self):
552 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
553 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
554 self.vm = iotests.VM().add_drive(test_img)
555 self.vm.launch()
557 def tearDown(self):
558 self.vm.shutdown()
559 os.remove(test_img)
560 os.remove(backing_img)
561 os.remove(target_img)
563 def test_set_speed(self):
564 self.assert_no_active_mirrors()
566 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
567 target=target_img)
568 self.assert_qmp(result, 'return', {})
570 # Default speed is 0
571 result = self.vm.qmp('query-block-jobs')
572 self.assert_qmp(result, 'return[0]/device', 'drive0')
573 self.assert_qmp(result, 'return[0]/speed', 0)
575 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
576 self.assert_qmp(result, 'return', {})
578 # Ensure the speed we set was accepted
579 result = self.vm.qmp('query-block-jobs')
580 self.assert_qmp(result, 'return[0]/device', 'drive0')
581 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
583 self.cancel_and_wait()
585 # Check setting speed in drive-mirror works
586 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
587 target=target_img, speed=4*1024*1024)
588 self.assert_qmp(result, 'return', {})
590 result = self.vm.qmp('query-block-jobs')
591 self.assert_qmp(result, 'return[0]/device', 'drive0')
592 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
594 self.cancel_and_wait()
596 def test_set_speed_invalid(self):
597 self.assert_no_active_mirrors()
599 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
600 target=target_img, speed=-1)
601 self.assert_qmp(result, 'error/class', 'GenericError')
603 self.assert_no_active_mirrors()
605 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
606 target=target_img)
607 self.assert_qmp(result, 'return', {})
609 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
610 self.assert_qmp(result, 'error/class', 'GenericError')
612 self.cancel_and_wait()
614 if __name__ == '__main__':
615 iotests.main(supported_fmts=['qcow2', 'qed'])