xen: build on ARM
[qemu/ar7.git] / tests / qemu-iotests / 041
blob0815e192740b804db31082ee79c912d728a40677
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
26 backing_img = os.path.join(iotests.test_dir, 'backing.img')
27 target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
28 test_img = os.path.join(iotests.test_dir, 'test.img')
29 target_img = os.path.join(iotests.test_dir, 'target.img')
31 quorum_img1 = os.path.join(iotests.test_dir, 'quorum1.img')
32 quorum_img2 = os.path.join(iotests.test_dir, 'quorum2.img')
33 quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
34 quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
35 quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
37 class ImageMirroringTestCase(iotests.QMPTestCase):
38 '''Abstract base class for image mirroring test cases'''
40 def wait_ready(self, drive='drive0'):
41 '''Wait until a block job BLOCK_JOB_READY event'''
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 def wait_ready_and_cancel(self, drive='drive0'):
51 self.wait_ready(drive=drive)
52 event = self.cancel_and_wait(drive=drive)
53 self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
54 self.assert_qmp(event, 'data/type', 'mirror')
55 self.assert_qmp(event, 'data/offset', self.image_len)
56 self.assert_qmp(event, 'data/len', self.image_len)
58 def complete_and_wait(self, drive='drive0', wait_ready=True):
59 '''Complete a block job and wait for it to finish'''
60 if wait_ready:
61 self.wait_ready(drive=drive)
63 result = self.vm.qmp('block-job-complete', device=drive)
64 self.assert_qmp(result, 'return', {})
66 event = self.wait_until_completed(drive=drive)
67 self.assert_qmp(event, 'data/type', 'mirror')
69 class TestSingleDrive(ImageMirroringTestCase):
70 image_len = 1 * 1024 * 1024 # MB
72 def setUp(self):
73 iotests.create_image(backing_img, self.image_len)
74 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
75 self.vm = iotests.VM().add_drive(test_img)
76 self.vm.launch()
78 def tearDown(self):
79 self.vm.shutdown()
80 os.remove(test_img)
81 os.remove(backing_img)
82 try:
83 os.remove(target_img)
84 except OSError:
85 pass
87 def test_complete(self):
88 self.assert_no_active_block_jobs()
90 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
91 target=target_img)
92 self.assert_qmp(result, 'return', {})
94 self.complete_and_wait()
95 result = self.vm.qmp('query-block')
96 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
97 self.vm.shutdown()
98 self.assertTrue(iotests.compare_images(test_img, target_img),
99 'target image does not match source after mirroring')
101 def test_cancel(self):
102 self.assert_no_active_block_jobs()
104 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
105 target=target_img)
106 self.assert_qmp(result, 'return', {})
108 self.cancel_and_wait(force=True)
109 result = self.vm.qmp('query-block')
110 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
111 self.vm.shutdown()
113 def test_cancel_after_ready(self):
114 self.assert_no_active_block_jobs()
116 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
117 target=target_img)
118 self.assert_qmp(result, 'return', {})
120 self.wait_ready_and_cancel()
121 result = self.vm.qmp('query-block')
122 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
123 self.vm.shutdown()
124 self.assertTrue(iotests.compare_images(test_img, target_img),
125 'target image does not match source after mirroring')
127 def test_pause(self):
128 self.assert_no_active_block_jobs()
130 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
131 target=target_img)
132 self.assert_qmp(result, 'return', {})
134 result = self.vm.qmp('block-job-pause', device='drive0')
135 self.assert_qmp(result, 'return', {})
137 time.sleep(1)
138 result = self.vm.qmp('query-block-jobs')
139 offset = self.dictpath(result, 'return[0]/offset')
141 time.sleep(1)
142 result = self.vm.qmp('query-block-jobs')
143 self.assert_qmp(result, 'return[0]/offset', offset)
145 result = self.vm.qmp('block-job-resume', device='drive0')
146 self.assert_qmp(result, 'return', {})
148 self.complete_and_wait()
149 self.vm.shutdown()
150 self.assertTrue(iotests.compare_images(test_img, target_img),
151 'target image does not match source after mirroring')
153 def test_small_buffer(self):
154 self.assert_no_active_block_jobs()
156 # A small buffer is rounded up automatically
157 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
158 buf_size=4096, target=target_img)
159 self.assert_qmp(result, 'return', {})
161 self.complete_and_wait()
162 result = self.vm.qmp('query-block')
163 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
164 self.vm.shutdown()
165 self.assertTrue(iotests.compare_images(test_img, target_img),
166 'target image does not match source after mirroring')
168 def test_small_buffer2(self):
169 self.assert_no_active_block_jobs()
171 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
172 % (self.image_len, self.image_len), target_img)
173 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
174 buf_size=65536, mode='existing', target=target_img)
175 self.assert_qmp(result, 'return', {})
177 self.complete_and_wait()
178 result = self.vm.qmp('query-block')
179 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
180 self.vm.shutdown()
181 self.assertTrue(iotests.compare_images(test_img, target_img),
182 'target image does not match source after mirroring')
184 def test_large_cluster(self):
185 self.assert_no_active_block_jobs()
187 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
188 % (self.image_len, backing_img), target_img)
189 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
190 mode='existing', target=target_img)
191 self.assert_qmp(result, 'return', {})
193 self.complete_and_wait()
194 result = self.vm.qmp('query-block')
195 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
196 self.vm.shutdown()
197 self.assertTrue(iotests.compare_images(test_img, target_img),
198 'target image does not match source after mirroring')
200 def test_medium_not_found(self):
201 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
202 target=target_img)
203 self.assert_qmp(result, 'error/class', 'GenericError')
205 def test_image_not_found(self):
206 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
207 mode='existing', target=target_img)
208 self.assert_qmp(result, 'error/class', 'GenericError')
210 def test_device_not_found(self):
211 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
212 target=target_img)
213 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
215 class TestSingleDriveZeroLength(TestSingleDrive):
216 image_len = 0
217 test_small_buffer2 = None
218 test_large_cluster = None
220 class TestMirrorNoBacking(ImageMirroringTestCase):
221 image_len = 2 * 1024 * 1024 # MB
223 def complete_and_wait(self, drive='drive0', wait_ready=True):
224 iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
225 return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
227 def compare_images(self, img1, img2):
228 iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
229 return iotests.compare_images(img1, img2)
231 def setUp(self):
232 iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
233 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
234 self.vm = iotests.VM().add_drive(test_img)
235 self.vm.launch()
237 def tearDown(self):
238 self.vm.shutdown()
239 os.remove(test_img)
240 os.remove(backing_img)
241 os.remove(target_backing_img)
242 os.remove(target_img)
244 def test_complete(self):
245 self.assert_no_active_block_jobs()
247 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
248 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
249 mode='existing', target=target_img)
250 self.assert_qmp(result, 'return', {})
252 self.complete_and_wait()
253 result = self.vm.qmp('query-block')
254 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
255 self.vm.shutdown()
256 self.assertTrue(self.compare_images(test_img, target_img),
257 'target image does not match source after mirroring')
259 def test_cancel(self):
260 self.assert_no_active_block_jobs()
262 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
263 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
264 mode='existing', target=target_img)
265 self.assert_qmp(result, 'return', {})
267 self.wait_ready_and_cancel()
268 result = self.vm.qmp('query-block')
269 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
270 self.vm.shutdown()
271 self.assertTrue(self.compare_images(test_img, target_img),
272 'target image does not match source after mirroring')
274 def test_large_cluster(self):
275 self.assert_no_active_block_jobs()
277 # qemu-img create fails if the image is not there
278 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
279 %(TestMirrorNoBacking.image_len), target_backing_img)
280 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
281 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
282 os.remove(target_backing_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.complete_and_wait()
289 result = self.vm.qmp('query-block')
290 self.assert_qmp(result, 'return[0]/inserted/file', target_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 TestMirrorResized(ImageMirroringTestCase):
296 backing_len = 1 * 1024 * 1024 # MB
297 image_len = 2 * 1024 * 1024 # MB
299 def setUp(self):
300 iotests.create_image(backing_img, TestMirrorResized.backing_len)
301 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
302 qemu_img('resize', test_img, '2M')
303 self.vm = iotests.VM().add_drive(test_img)
304 self.vm.launch()
306 def tearDown(self):
307 self.vm.shutdown()
308 os.remove(test_img)
309 os.remove(backing_img)
310 try:
311 os.remove(target_img)
312 except OSError:
313 pass
315 def test_complete_top(self):
316 self.assert_no_active_block_jobs()
318 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
319 target=target_img)
320 self.assert_qmp(result, 'return', {})
322 self.complete_and_wait()
323 result = self.vm.qmp('query-block')
324 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
325 self.vm.shutdown()
326 self.assertTrue(iotests.compare_images(test_img, target_img),
327 'target image does not match source after mirroring')
329 def test_complete_full(self):
330 self.assert_no_active_block_jobs()
332 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
333 target=target_img)
334 self.assert_qmp(result, 'return', {})
336 self.complete_and_wait()
337 result = self.vm.qmp('query-block')
338 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
339 self.vm.shutdown()
340 self.assertTrue(iotests.compare_images(test_img, target_img),
341 'target image does not match source after mirroring')
343 class TestReadErrors(ImageMirroringTestCase):
344 image_len = 2 * 1024 * 1024 # MB
346 # this should be a multiple of twice the default granularity
347 # so that we hit this offset first in state 1
348 MIRROR_GRANULARITY = 1024 * 1024
350 def create_blkdebug_file(self, name, event, errno):
351 file = open(name, 'w')
352 file.write('''
353 [inject-error]
354 state = "1"
355 event = "%s"
356 errno = "%d"
357 immediately = "off"
358 once = "on"
359 sector = "%d"
361 [set-state]
362 state = "1"
363 event = "%s"
364 new_state = "2"
366 [set-state]
367 state = "2"
368 event = "%s"
369 new_state = "1"
370 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
371 file.close()
373 def setUp(self):
374 self.blkdebug_file = backing_img + ".blkdebug"
375 iotests.create_image(backing_img, TestReadErrors.image_len)
376 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
377 qemu_img('create', '-f', iotests.imgfmt,
378 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
379 % (self.blkdebug_file, backing_img),
380 test_img)
381 # Write something for tests that use sync='top'
382 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
383 test_img)
384 self.vm = iotests.VM().add_drive(test_img)
385 self.vm.launch()
387 def tearDown(self):
388 self.vm.shutdown()
389 os.remove(test_img)
390 os.remove(backing_img)
391 os.remove(self.blkdebug_file)
393 def test_report_read(self):
394 self.assert_no_active_block_jobs()
396 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
397 target=target_img)
398 self.assert_qmp(result, 'return', {})
400 completed = False
401 error = False
402 while not completed:
403 for event in self.vm.get_qmp_events(wait=True):
404 if event['event'] == 'BLOCK_JOB_ERROR':
405 self.assert_qmp(event, 'data/device', 'drive0')
406 self.assert_qmp(event, 'data/operation', 'read')
407 error = True
408 elif event['event'] == 'BLOCK_JOB_READY':
409 self.assertTrue(False, 'job completed unexpectedly')
410 elif event['event'] == 'BLOCK_JOB_COMPLETED':
411 self.assertTrue(error, 'job completed unexpectedly')
412 self.assert_qmp(event, 'data/type', 'mirror')
413 self.assert_qmp(event, 'data/device', 'drive0')
414 self.assert_qmp(event, 'data/error', 'Input/output error')
415 self.assert_qmp(event, 'data/len', self.image_len)
416 completed = True
418 self.assert_no_active_block_jobs()
419 self.vm.shutdown()
421 def test_ignore_read(self):
422 self.assert_no_active_block_jobs()
424 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
425 target=target_img, on_source_error='ignore')
426 self.assert_qmp(result, 'return', {})
428 event = self.vm.get_qmp_event(wait=True)
429 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
430 self.assert_qmp(event, 'data/device', 'drive0')
431 self.assert_qmp(event, 'data/operation', 'read')
432 result = self.vm.qmp('query-block-jobs')
433 self.assert_qmp(result, 'return[0]/paused', False)
434 self.complete_and_wait()
435 self.vm.shutdown()
437 def test_large_cluster(self):
438 self.assert_no_active_block_jobs()
440 # Test COW into the target image. The first half of the
441 # cluster at MIRROR_GRANULARITY has to be copied from
442 # backing_img, even though sync='top'.
443 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
444 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
445 on_source_error='ignore',
446 mode='existing', target=target_img)
447 self.assert_qmp(result, 'return', {})
449 event = self.vm.get_qmp_event(wait=True)
450 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
451 self.assert_qmp(event, 'data/device', 'drive0')
452 self.assert_qmp(event, 'data/operation', 'read')
453 result = self.vm.qmp('query-block-jobs')
454 self.assert_qmp(result, 'return[0]/paused', False)
455 self.complete_and_wait()
456 self.vm.shutdown()
458 # Detach blkdebug to compare images successfully
459 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
460 self.assertTrue(iotests.compare_images(test_img, target_img),
461 'target image does not match source after mirroring')
463 def test_stop_read(self):
464 self.assert_no_active_block_jobs()
466 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
467 target=target_img, on_source_error='stop')
468 self.assert_qmp(result, 'return', {})
470 error = False
471 ready = False
472 while not ready:
473 for event in self.vm.get_qmp_events(wait=True):
474 if event['event'] == 'BLOCK_JOB_ERROR':
475 self.assert_qmp(event, 'data/device', 'drive0')
476 self.assert_qmp(event, 'data/operation', 'read')
478 result = self.vm.qmp('query-block-jobs')
479 self.assert_qmp(result, 'return[0]/paused', True)
480 self.assert_qmp(result, 'return[0]/io-status', 'failed')
482 result = self.vm.qmp('block-job-resume', device='drive0')
483 self.assert_qmp(result, 'return', {})
484 error = True
485 elif event['event'] == 'BLOCK_JOB_READY':
486 self.assertTrue(error, 'job completed unexpectedly')
487 self.assert_qmp(event, 'data/device', 'drive0')
488 ready = True
490 result = self.vm.qmp('query-block-jobs')
491 self.assert_qmp(result, 'return[0]/paused', False)
492 self.assert_qmp(result, 'return[0]/io-status', 'ok')
494 self.complete_and_wait(wait_ready=False)
495 self.assert_no_active_block_jobs()
496 self.vm.shutdown()
498 class TestWriteErrors(ImageMirroringTestCase):
499 image_len = 2 * 1024 * 1024 # MB
501 # this should be a multiple of twice the default granularity
502 # so that we hit this offset first in state 1
503 MIRROR_GRANULARITY = 1024 * 1024
505 def create_blkdebug_file(self, name, event, errno):
506 file = open(name, 'w')
507 file.write('''
508 [inject-error]
509 state = "1"
510 event = "%s"
511 errno = "%d"
512 immediately = "off"
513 once = "on"
514 sector = "%d"
516 [set-state]
517 state = "1"
518 event = "%s"
519 new_state = "2"
521 [set-state]
522 state = "2"
523 event = "%s"
524 new_state = "1"
525 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
526 file.close()
528 def setUp(self):
529 self.blkdebug_file = target_img + ".blkdebug"
530 iotests.create_image(backing_img, TestWriteErrors.image_len)
531 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
532 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
533 self.vm = iotests.VM().add_drive(test_img)
534 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
535 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
536 self.vm.launch()
538 def tearDown(self):
539 self.vm.shutdown()
540 os.remove(test_img)
541 os.remove(backing_img)
542 os.remove(self.blkdebug_file)
544 def test_report_write(self):
545 self.assert_no_active_block_jobs()
547 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
548 mode='existing', target=self.target_img)
549 self.assert_qmp(result, 'return', {})
551 completed = False
552 error = False
553 while not completed:
554 for event in self.vm.get_qmp_events(wait=True):
555 if event['event'] == 'BLOCK_JOB_ERROR':
556 self.assert_qmp(event, 'data/device', 'drive0')
557 self.assert_qmp(event, 'data/operation', 'write')
558 error = True
559 elif event['event'] == 'BLOCK_JOB_READY':
560 self.assertTrue(False, 'job completed unexpectedly')
561 elif event['event'] == 'BLOCK_JOB_COMPLETED':
562 self.assertTrue(error, 'job completed unexpectedly')
563 self.assert_qmp(event, 'data/type', 'mirror')
564 self.assert_qmp(event, 'data/device', 'drive0')
565 self.assert_qmp(event, 'data/error', 'Input/output error')
566 self.assert_qmp(event, 'data/len', self.image_len)
567 completed = True
569 self.assert_no_active_block_jobs()
570 self.vm.shutdown()
572 def test_ignore_write(self):
573 self.assert_no_active_block_jobs()
575 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
576 mode='existing', target=self.target_img,
577 on_target_error='ignore')
578 self.assert_qmp(result, 'return', {})
580 event = self.vm.get_qmp_event(wait=True)
581 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
582 self.assert_qmp(event, 'data/device', 'drive0')
583 self.assert_qmp(event, 'data/operation', 'write')
584 result = self.vm.qmp('query-block-jobs')
585 self.assert_qmp(result, 'return[0]/paused', False)
586 self.complete_and_wait()
587 self.vm.shutdown()
589 def test_stop_write(self):
590 self.assert_no_active_block_jobs()
592 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
593 mode='existing', target=self.target_img,
594 on_target_error='stop')
595 self.assert_qmp(result, 'return', {})
597 error = False
598 ready = False
599 while not ready:
600 for event in self.vm.get_qmp_events(wait=True):
601 if event['event'] == 'BLOCK_JOB_ERROR':
602 self.assert_qmp(event, 'data/device', 'drive0')
603 self.assert_qmp(event, 'data/operation', 'write')
605 result = self.vm.qmp('query-block-jobs')
606 self.assert_qmp(result, 'return[0]/paused', True)
607 self.assert_qmp(result, 'return[0]/io-status', 'failed')
609 result = self.vm.qmp('block-job-resume', device='drive0')
610 self.assert_qmp(result, 'return', {})
612 result = self.vm.qmp('query-block-jobs')
613 self.assert_qmp(result, 'return[0]/paused', False)
614 self.assert_qmp(result, 'return[0]/io-status', 'ok')
615 error = True
616 elif event['event'] == 'BLOCK_JOB_READY':
617 self.assertTrue(error, 'job completed unexpectedly')
618 self.assert_qmp(event, 'data/device', 'drive0')
619 ready = True
621 self.complete_and_wait(wait_ready=False)
622 self.assert_no_active_block_jobs()
623 self.vm.shutdown()
625 class TestSetSpeed(ImageMirroringTestCase):
626 image_len = 80 * 1024 * 1024 # MB
628 def setUp(self):
629 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
630 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
631 self.vm = iotests.VM().add_drive(test_img)
632 self.vm.launch()
634 def tearDown(self):
635 self.vm.shutdown()
636 os.remove(test_img)
637 os.remove(backing_img)
638 os.remove(target_img)
640 def test_set_speed(self):
641 self.assert_no_active_block_jobs()
643 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
644 target=target_img)
645 self.assert_qmp(result, 'return', {})
647 # Default speed is 0
648 result = self.vm.qmp('query-block-jobs')
649 self.assert_qmp(result, 'return[0]/device', 'drive0')
650 self.assert_qmp(result, 'return[0]/speed', 0)
652 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
653 self.assert_qmp(result, 'return', {})
655 # Ensure the speed we set was accepted
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', 8 * 1024 * 1024)
660 self.wait_ready_and_cancel()
662 # Check setting speed in drive-mirror works
663 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
664 target=target_img, speed=4*1024*1024)
665 self.assert_qmp(result, 'return', {})
667 result = self.vm.qmp('query-block-jobs')
668 self.assert_qmp(result, 'return[0]/device', 'drive0')
669 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
671 self.wait_ready_and_cancel()
673 def test_set_speed_invalid(self):
674 self.assert_no_active_block_jobs()
676 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
677 target=target_img, speed=-1)
678 self.assert_qmp(result, 'error/class', 'GenericError')
680 self.assert_no_active_block_jobs()
682 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
683 target=target_img)
684 self.assert_qmp(result, 'return', {})
686 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
687 self.assert_qmp(result, 'error/class', 'GenericError')
689 self.wait_ready_and_cancel()
691 class TestUnbackedSource(ImageMirroringTestCase):
692 image_len = 2 * 1024 * 1024 # MB
694 def setUp(self):
695 qemu_img('create', '-f', iotests.imgfmt, test_img,
696 str(TestUnbackedSource.image_len))
697 self.vm = iotests.VM().add_drive(test_img)
698 self.vm.launch()
700 def tearDown(self):
701 self.vm.shutdown()
702 os.remove(test_img)
703 os.remove(target_img)
705 def test_absolute_paths_full(self):
706 self.assert_no_active_block_jobs()
707 result = self.vm.qmp('drive-mirror', device='drive0',
708 sync='full', target=target_img,
709 mode='absolute-paths')
710 self.assert_qmp(result, 'return', {})
711 self.complete_and_wait()
712 self.assert_no_active_block_jobs()
714 def test_absolute_paths_top(self):
715 self.assert_no_active_block_jobs()
716 result = self.vm.qmp('drive-mirror', device='drive0',
717 sync='top', target=target_img,
718 mode='absolute-paths')
719 self.assert_qmp(result, 'return', {})
720 self.complete_and_wait()
721 self.assert_no_active_block_jobs()
723 def test_absolute_paths_none(self):
724 self.assert_no_active_block_jobs()
725 result = self.vm.qmp('drive-mirror', device='drive0',
726 sync='none', target=target_img,
727 mode='absolute-paths')
728 self.assert_qmp(result, 'return', {})
729 self.complete_and_wait()
730 self.assert_no_active_block_jobs()
732 class TestRepairQuorum(ImageMirroringTestCase):
733 """ This class test quorum file repair using drive-mirror.
734 It's mostly a fork of TestSingleDrive """
735 image_len = 1 * 1024 * 1024 # MB
736 IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
738 def setUp(self):
739 self.vm = iotests.VM()
741 # Add each individual quorum images
742 for i in self.IMAGES:
743 qemu_img('create', '-f', iotests.imgfmt, i,
744 str(TestSingleDrive.image_len))
745 # Assign a node name to each quorum image in order to manipulate
746 # them
747 opts = "node-name=img%i" % self.IMAGES.index(i)
748 self.vm = self.vm.add_drive(i, opts)
750 self.vm.launch()
752 #assemble the quorum block device from the individual files
753 args = { "options" : { "driver": "quorum", "id": "quorum0",
754 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
755 result = self.vm.qmp("blockdev-add", **args)
756 self.assert_qmp(result, 'return', {})
759 def tearDown(self):
760 self.vm.shutdown()
761 for i in self.IMAGES + [ quorum_repair_img ]:
762 # Do a try/except because the test may have deleted some images
763 try:
764 os.remove(i)
765 except OSError:
766 pass
768 def test_complete(self):
769 self.assert_no_active_block_jobs()
771 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
772 node_name="repair0",
773 replaces="img1",
774 target=quorum_repair_img, format=iotests.imgfmt)
775 self.assert_qmp(result, 'return', {})
777 self.complete_and_wait(drive="quorum0")
778 result = self.vm.qmp('query-named-block-nodes')
779 self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
780 # TODO: a better test requiring some QEMU infrastructure will be added
781 # to check that this file is really driven by quorum
782 self.vm.shutdown()
783 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
784 'target image does not match source after mirroring')
786 def test_cancel(self):
787 self.assert_no_active_block_jobs()
789 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
790 node_name="repair0",
791 replaces="img1",
792 target=quorum_repair_img, format=iotests.imgfmt)
793 self.assert_qmp(result, 'return', {})
795 self.cancel_and_wait(drive="quorum0", force=True)
796 # here we check that the last registered quorum file has not been
797 # swapped out and unref
798 result = self.vm.qmp('query-named-block-nodes')
799 self.assert_qmp(result, 'return[0]/file', quorum_img3)
800 self.vm.shutdown()
802 def test_cancel_after_ready(self):
803 self.assert_no_active_block_jobs()
805 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
806 node_name="repair0",
807 replaces="img1",
808 target=quorum_repair_img, format=iotests.imgfmt)
809 self.assert_qmp(result, 'return', {})
811 self.wait_ready_and_cancel(drive="quorum0")
812 result = self.vm.qmp('query-named-block-nodes')
813 # here we check that the last registered quorum file has not been
814 # swapped out and unref
815 self.assert_qmp(result, 'return[0]/file', quorum_img3)
816 self.vm.shutdown()
817 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
818 'target image does not match source after mirroring')
820 def test_pause(self):
821 self.assert_no_active_block_jobs()
823 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
824 node_name="repair0",
825 replaces="img1",
826 target=quorum_repair_img, format=iotests.imgfmt)
827 self.assert_qmp(result, 'return', {})
829 result = self.vm.qmp('block-job-pause', device='quorum0')
830 self.assert_qmp(result, 'return', {})
832 time.sleep(1)
833 result = self.vm.qmp('query-block-jobs')
834 offset = self.dictpath(result, 'return[0]/offset')
836 time.sleep(1)
837 result = self.vm.qmp('query-block-jobs')
838 self.assert_qmp(result, 'return[0]/offset', offset)
840 result = self.vm.qmp('block-job-resume', device='quorum0')
841 self.assert_qmp(result, 'return', {})
843 self.complete_and_wait(drive="quorum0")
844 self.vm.shutdown()
845 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
846 'target image does not match source after mirroring')
848 def test_medium_not_found(self):
849 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
850 node_name='repair0',
851 replaces='img1',
852 target=quorum_repair_img, format=iotests.imgfmt)
853 self.assert_qmp(result, 'error/class', 'GenericError')
855 def test_image_not_found(self):
856 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
857 node_name='repair0',
858 replaces='img1',
859 mode='existing',
860 target=quorum_repair_img, format=iotests.imgfmt)
861 self.assert_qmp(result, 'error/class', 'GenericError')
863 def test_device_not_found(self):
864 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
865 node_name='repair0',
866 replaces='img1',
867 target=quorum_repair_img, format=iotests.imgfmt)
868 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
870 def test_wrong_sync_mode(self):
871 result = self.vm.qmp('drive-mirror', device='quorum0',
872 node_name='repair0',
873 replaces='img1',
874 target=quorum_repair_img, format=iotests.imgfmt)
875 self.assert_qmp(result, 'error/class', 'GenericError')
877 def test_no_node_name(self):
878 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
879 replaces='img1',
880 target=quorum_repair_img, format=iotests.imgfmt)
881 self.assert_qmp(result, 'error/class', 'GenericError')
883 def test_unexistant_replaces(self):
884 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
885 node_name='repair0',
886 replaces='img77',
887 target=quorum_repair_img, format=iotests.imgfmt)
888 self.assert_qmp(result, 'error/class', 'GenericError')
890 def test_after_a_quorum_snapshot(self):
891 result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
892 snapshot_file=quorum_snapshot_file,
893 snapshot_node_name="snap1");
895 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
896 node_name='repair0',
897 replaces="img1",
898 target=quorum_repair_img, format=iotests.imgfmt)
899 self.assert_qmp(result, 'error/class', 'GenericError')
901 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
902 node_name='repair0',
903 replaces="snap1",
904 target=quorum_repair_img, format=iotests.imgfmt)
905 self.assert_qmp(result, 'return', {})
907 self.complete_and_wait(drive="quorum0")
908 result = self.vm.qmp('query-named-block-nodes')
909 self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
910 # TODO: a better test requiring some QEMU infrastructure will be added
911 # to check that this file is really driven by quorum
912 self.vm.shutdown()
914 if __name__ == '__main__':
915 iotests.main(supported_fmts=['qcow2', 'qed'])