qemu-gdb: add $qemu_coroutine_sp and $qemu_coroutine_pc
[qemu/ar7.git] / tests / qemu-iotests / 041
blob05b5962cee851b026058f798dca8210eed5c2bde
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')
38 class TestSingleDrive(iotests.QMPTestCase):
39 image_len = 1 * 1024 * 1024 # MB
41 def setUp(self):
42 iotests.create_image(backing_img, self.image_len)
43 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
44 self.vm = iotests.VM().add_drive(test_img)
45 if iotests.qemu_default_machine == 'pc':
46 self.vm.add_drive(None, 'media=cdrom', 'ide')
47 self.vm.launch()
49 def tearDown(self):
50 self.vm.shutdown()
51 os.remove(test_img)
52 os.remove(backing_img)
53 try:
54 os.remove(target_img)
55 except OSError:
56 pass
58 def test_complete(self):
59 self.assert_no_active_block_jobs()
61 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
62 target=target_img)
63 self.assert_qmp(result, 'return', {})
65 self.complete_and_wait()
66 result = self.vm.qmp('query-block')
67 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
68 self.vm.shutdown()
69 self.assertTrue(iotests.compare_images(test_img, target_img),
70 'target image does not match source after mirroring')
72 def test_cancel(self):
73 self.assert_no_active_block_jobs()
75 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
76 target=target_img)
77 self.assert_qmp(result, 'return', {})
79 self.cancel_and_wait(force=True)
80 result = self.vm.qmp('query-block')
81 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
82 self.vm.shutdown()
84 def test_cancel_after_ready(self):
85 self.assert_no_active_block_jobs()
87 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
88 target=target_img)
89 self.assert_qmp(result, 'return', {})
91 self.wait_ready_and_cancel()
92 result = self.vm.qmp('query-block')
93 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
94 self.vm.shutdown()
95 self.assertTrue(iotests.compare_images(test_img, target_img),
96 'target image does not match source after mirroring')
98 def test_pause(self):
99 self.assert_no_active_block_jobs()
101 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
102 target=target_img)
103 self.assert_qmp(result, 'return', {})
105 result = self.vm.qmp('block-job-pause', device='drive0')
106 self.assert_qmp(result, 'return', {})
108 time.sleep(1)
109 result = self.vm.qmp('query-block-jobs')
110 offset = self.dictpath(result, 'return[0]/offset')
112 time.sleep(1)
113 result = self.vm.qmp('query-block-jobs')
114 self.assert_qmp(result, 'return[0]/offset', offset)
116 result = self.vm.qmp('block-job-resume', device='drive0')
117 self.assert_qmp(result, 'return', {})
119 self.complete_and_wait()
120 self.vm.shutdown()
121 self.assertTrue(iotests.compare_images(test_img, target_img),
122 'target image does not match source after mirroring')
124 def test_small_buffer(self):
125 self.assert_no_active_block_jobs()
127 # A small buffer is rounded up automatically
128 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
129 buf_size=4096, target=target_img)
130 self.assert_qmp(result, 'return', {})
132 self.complete_and_wait()
133 result = self.vm.qmp('query-block')
134 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
135 self.vm.shutdown()
136 self.assertTrue(iotests.compare_images(test_img, target_img),
137 'target image does not match source after mirroring')
139 def test_small_buffer2(self):
140 self.assert_no_active_block_jobs()
142 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
143 % (self.image_len, self.image_len), target_img)
144 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
145 buf_size=65536, mode='existing', target=target_img)
146 self.assert_qmp(result, 'return', {})
148 self.complete_and_wait()
149 result = self.vm.qmp('query-block')
150 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
151 self.vm.shutdown()
152 self.assertTrue(iotests.compare_images(test_img, target_img),
153 'target image does not match source after mirroring')
155 def test_large_cluster(self):
156 self.assert_no_active_block_jobs()
158 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
159 % (self.image_len, backing_img), target_img)
160 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
161 mode='existing', target=target_img)
162 self.assert_qmp(result, 'return', {})
164 self.complete_and_wait()
165 result = self.vm.qmp('query-block')
166 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
167 self.vm.shutdown()
168 self.assertTrue(iotests.compare_images(test_img, target_img),
169 'target image does not match source after mirroring')
171 def test_medium_not_found(self):
172 if iotests.qemu_default_machine != 'pc':
173 return
175 result = self.vm.qmp('drive-mirror', device='drive1', # CD-ROM
176 sync='full', target=target_img)
177 self.assert_qmp(result, 'error/class', 'GenericError')
179 def test_image_not_found(self):
180 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
181 mode='existing', target=target_img)
182 self.assert_qmp(result, 'error/class', 'GenericError')
184 def test_device_not_found(self):
185 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
186 target=target_img)
187 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
189 class TestSingleDriveZeroLength(TestSingleDrive):
190 image_len = 0
191 test_small_buffer2 = None
192 test_large_cluster = None
194 class TestSingleDriveUnalignedLength(TestSingleDrive):
195 image_len = 1025 * 1024
196 test_small_buffer2 = None
197 test_large_cluster = None
199 class TestMirrorNoBacking(iotests.QMPTestCase):
200 image_len = 2 * 1024 * 1024 # MB
202 def setUp(self):
203 iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
204 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
205 self.vm = iotests.VM().add_drive(test_img)
206 self.vm.launch()
208 def tearDown(self):
209 self.vm.shutdown()
210 os.remove(test_img)
211 os.remove(backing_img)
212 try:
213 os.remove(target_backing_img)
214 except:
215 pass
216 os.remove(target_img)
218 def test_complete(self):
219 self.assert_no_active_block_jobs()
221 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
222 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
223 mode='existing', target=target_img)
224 self.assert_qmp(result, 'return', {})
226 self.complete_and_wait()
227 result = self.vm.qmp('query-block')
228 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
229 self.vm.shutdown()
230 self.assertTrue(iotests.compare_images(test_img, target_img),
231 'target image does not match source after mirroring')
233 def test_cancel(self):
234 self.assert_no_active_block_jobs()
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', {})
241 self.wait_ready_and_cancel()
242 result = self.vm.qmp('query-block')
243 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
244 self.vm.shutdown()
245 self.assertTrue(iotests.compare_images(test_img, target_img),
246 'target image does not match source after mirroring')
248 def test_large_cluster(self):
249 self.assert_no_active_block_jobs()
251 # qemu-img create fails if the image is not there
252 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
253 %(TestMirrorNoBacking.image_len), target_backing_img)
254 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
255 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
257 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
258 mode='existing', target=target_img)
259 self.assert_qmp(result, 'return', {})
261 self.complete_and_wait()
262 result = self.vm.qmp('query-block')
263 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
264 self.vm.shutdown()
265 self.assertTrue(iotests.compare_images(test_img, target_img),
266 'target image does not match source after mirroring')
268 class TestMirrorResized(iotests.QMPTestCase):
269 backing_len = 1 * 1024 * 1024 # MB
270 image_len = 2 * 1024 * 1024 # MB
272 def setUp(self):
273 iotests.create_image(backing_img, TestMirrorResized.backing_len)
274 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
275 qemu_img('resize', test_img, '2M')
276 self.vm = iotests.VM().add_drive(test_img)
277 self.vm.launch()
279 def tearDown(self):
280 self.vm.shutdown()
281 os.remove(test_img)
282 os.remove(backing_img)
283 try:
284 os.remove(target_img)
285 except OSError:
286 pass
288 def test_complete_top(self):
289 self.assert_no_active_block_jobs()
291 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
292 target=target_img)
293 self.assert_qmp(result, 'return', {})
295 self.complete_and_wait()
296 result = self.vm.qmp('query-block')
297 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
298 self.vm.shutdown()
299 self.assertTrue(iotests.compare_images(test_img, target_img),
300 'target image does not match source after mirroring')
302 def test_complete_full(self):
303 self.assert_no_active_block_jobs()
305 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
306 target=target_img)
307 self.assert_qmp(result, 'return', {})
309 self.complete_and_wait()
310 result = self.vm.qmp('query-block')
311 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
312 self.vm.shutdown()
313 self.assertTrue(iotests.compare_images(test_img, target_img),
314 'target image does not match source after mirroring')
316 class TestReadErrors(iotests.QMPTestCase):
317 image_len = 2 * 1024 * 1024 # MB
319 # this should be a multiple of twice the default granularity
320 # so that we hit this offset first in state 1
321 MIRROR_GRANULARITY = 1024 * 1024
323 def create_blkdebug_file(self, name, event, errno):
324 file = open(name, 'w')
325 file.write('''
326 [inject-error]
327 state = "1"
328 event = "%s"
329 errno = "%d"
330 immediately = "off"
331 once = "on"
332 sector = "%d"
334 [set-state]
335 state = "1"
336 event = "%s"
337 new_state = "2"
339 [set-state]
340 state = "2"
341 event = "%s"
342 new_state = "1"
343 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
344 file.close()
346 def setUp(self):
347 self.blkdebug_file = backing_img + ".blkdebug"
348 iotests.create_image(backing_img, TestReadErrors.image_len)
349 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
350 qemu_img('create', '-f', iotests.imgfmt,
351 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
352 % (self.blkdebug_file, backing_img),
353 test_img)
354 # Write something for tests that use sync='top'
355 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
356 test_img)
357 self.vm = iotests.VM().add_drive(test_img)
358 self.vm.launch()
360 def tearDown(self):
361 self.vm.shutdown()
362 os.remove(test_img)
363 os.remove(backing_img)
364 os.remove(self.blkdebug_file)
366 def test_report_read(self):
367 self.assert_no_active_block_jobs()
369 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
370 target=target_img)
371 self.assert_qmp(result, 'return', {})
373 completed = False
374 error = False
375 while not completed:
376 for event in self.vm.get_qmp_events(wait=True):
377 if event['event'] == 'BLOCK_JOB_ERROR':
378 self.assert_qmp(event, 'data/device', 'drive0')
379 self.assert_qmp(event, 'data/operation', 'read')
380 error = True
381 elif event['event'] == 'BLOCK_JOB_READY':
382 self.assertTrue(False, 'job completed unexpectedly')
383 elif event['event'] == 'BLOCK_JOB_COMPLETED':
384 self.assertTrue(error, 'job completed unexpectedly')
385 self.assert_qmp(event, 'data/type', 'mirror')
386 self.assert_qmp(event, 'data/device', 'drive0')
387 self.assert_qmp(event, 'data/error', 'Input/output error')
388 completed = True
390 self.assert_no_active_block_jobs()
391 self.vm.shutdown()
393 def test_ignore_read(self):
394 self.assert_no_active_block_jobs()
396 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
397 target=target_img, on_source_error='ignore')
398 self.assert_qmp(result, 'return', {})
400 event = self.vm.get_qmp_event(wait=True)
401 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
402 self.assert_qmp(event, 'data/device', 'drive0')
403 self.assert_qmp(event, 'data/operation', 'read')
404 result = self.vm.qmp('query-block-jobs')
405 self.assert_qmp(result, 'return[0]/paused', False)
406 self.complete_and_wait()
407 self.vm.shutdown()
409 def test_large_cluster(self):
410 self.assert_no_active_block_jobs()
412 # Test COW into the target image. The first half of the
413 # cluster at MIRROR_GRANULARITY has to be copied from
414 # backing_img, even though sync='top'.
415 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
416 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
417 on_source_error='ignore',
418 mode='existing', target=target_img)
419 self.assert_qmp(result, 'return', {})
421 event = self.vm.get_qmp_event(wait=True)
422 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
423 self.assert_qmp(event, 'data/device', 'drive0')
424 self.assert_qmp(event, 'data/operation', 'read')
425 result = self.vm.qmp('query-block-jobs')
426 self.assert_qmp(result, 'return[0]/paused', False)
427 self.complete_and_wait()
428 self.vm.shutdown()
430 # Detach blkdebug to compare images successfully
431 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
432 self.assertTrue(iotests.compare_images(test_img, target_img),
433 'target image does not match source after mirroring')
435 def test_stop_read(self):
436 self.assert_no_active_block_jobs()
438 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
439 target=target_img, on_source_error='stop')
440 self.assert_qmp(result, 'return', {})
442 error = False
443 ready = False
444 while not ready:
445 for event in self.vm.get_qmp_events(wait=True):
446 if event['event'] == 'BLOCK_JOB_ERROR':
447 self.assert_qmp(event, 'data/device', 'drive0')
448 self.assert_qmp(event, 'data/operation', 'read')
450 result = self.vm.qmp('query-block-jobs')
451 self.assert_qmp(result, 'return[0]/paused', True)
452 self.assert_qmp(result, 'return[0]/io-status', 'failed')
454 result = self.vm.qmp('block-job-resume', device='drive0')
455 self.assert_qmp(result, 'return', {})
456 error = True
457 elif event['event'] == 'BLOCK_JOB_READY':
458 self.assertTrue(error, 'job completed unexpectedly')
459 self.assert_qmp(event, 'data/device', 'drive0')
460 ready = True
462 result = self.vm.qmp('query-block-jobs')
463 self.assert_qmp(result, 'return[0]/paused', False)
464 self.assert_qmp(result, 'return[0]/io-status', 'ok')
466 self.complete_and_wait(wait_ready=False)
467 self.assert_no_active_block_jobs()
468 self.vm.shutdown()
470 class TestWriteErrors(iotests.QMPTestCase):
471 image_len = 2 * 1024 * 1024 # MB
473 # this should be a multiple of twice the default granularity
474 # so that we hit this offset first in state 1
475 MIRROR_GRANULARITY = 1024 * 1024
477 def create_blkdebug_file(self, name, event, errno):
478 file = open(name, 'w')
479 file.write('''
480 [inject-error]
481 state = "1"
482 event = "%s"
483 errno = "%d"
484 immediately = "off"
485 once = "on"
486 sector = "%d"
488 [set-state]
489 state = "1"
490 event = "%s"
491 new_state = "2"
493 [set-state]
494 state = "2"
495 event = "%s"
496 new_state = "1"
497 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
498 file.close()
500 def setUp(self):
501 self.blkdebug_file = target_img + ".blkdebug"
502 iotests.create_image(backing_img, TestWriteErrors.image_len)
503 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
504 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
505 self.vm = iotests.VM().add_drive(test_img)
506 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
507 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
508 self.vm.launch()
510 def tearDown(self):
511 self.vm.shutdown()
512 os.remove(test_img)
513 os.remove(backing_img)
514 os.remove(self.blkdebug_file)
516 def test_report_write(self):
517 self.assert_no_active_block_jobs()
519 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
520 mode='existing', target=self.target_img)
521 self.assert_qmp(result, 'return', {})
523 completed = False
524 error = False
525 while not completed:
526 for event in self.vm.get_qmp_events(wait=True):
527 if event['event'] == 'BLOCK_JOB_ERROR':
528 self.assert_qmp(event, 'data/device', 'drive0')
529 self.assert_qmp(event, 'data/operation', 'write')
530 error = True
531 elif event['event'] == 'BLOCK_JOB_READY':
532 self.assertTrue(False, 'job completed unexpectedly')
533 elif event['event'] == 'BLOCK_JOB_COMPLETED':
534 self.assertTrue(error, 'job completed unexpectedly')
535 self.assert_qmp(event, 'data/type', 'mirror')
536 self.assert_qmp(event, 'data/device', 'drive0')
537 self.assert_qmp(event, 'data/error', 'Input/output error')
538 completed = True
540 self.assert_no_active_block_jobs()
541 self.vm.shutdown()
543 def test_ignore_write(self):
544 self.assert_no_active_block_jobs()
546 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
547 mode='existing', target=self.target_img,
548 on_target_error='ignore')
549 self.assert_qmp(result, 'return', {})
551 event = self.vm.get_qmp_event(wait=True)
552 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
553 self.assert_qmp(event, 'data/device', 'drive0')
554 self.assert_qmp(event, 'data/operation', 'write')
555 result = self.vm.qmp('query-block-jobs')
556 self.assert_qmp(result, 'return[0]/paused', False)
557 self.complete_and_wait()
558 self.vm.shutdown()
560 def test_stop_write(self):
561 self.assert_no_active_block_jobs()
563 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
564 mode='existing', target=self.target_img,
565 on_target_error='stop')
566 self.assert_qmp(result, 'return', {})
568 error = False
569 ready = False
570 while not ready:
571 for event in self.vm.get_qmp_events(wait=True):
572 if event['event'] == 'BLOCK_JOB_ERROR':
573 self.assert_qmp(event, 'data/device', 'drive0')
574 self.assert_qmp(event, 'data/operation', 'write')
576 result = self.vm.qmp('query-block-jobs')
577 self.assert_qmp(result, 'return[0]/paused', True)
578 self.assert_qmp(result, 'return[0]/io-status', 'failed')
580 result = self.vm.qmp('block-job-resume', device='drive0')
581 self.assert_qmp(result, 'return', {})
583 result = self.vm.qmp('query-block-jobs')
584 self.assert_qmp(result, 'return[0]/paused', False)
585 self.assert_qmp(result, 'return[0]/io-status', 'ok')
586 error = True
587 elif event['event'] == 'BLOCK_JOB_READY':
588 self.assertTrue(error, 'job completed unexpectedly')
589 self.assert_qmp(event, 'data/device', 'drive0')
590 ready = True
592 self.complete_and_wait(wait_ready=False)
593 self.assert_no_active_block_jobs()
594 self.vm.shutdown()
596 class TestSetSpeed(iotests.QMPTestCase):
597 image_len = 80 * 1024 * 1024 # MB
599 def setUp(self):
600 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
601 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
602 self.vm = iotests.VM().add_drive(test_img)
603 self.vm.launch()
605 def tearDown(self):
606 self.vm.shutdown()
607 os.remove(test_img)
608 os.remove(backing_img)
609 os.remove(target_img)
611 def test_set_speed(self):
612 self.assert_no_active_block_jobs()
614 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
615 target=target_img)
616 self.assert_qmp(result, 'return', {})
618 # Default speed is 0
619 result = self.vm.qmp('query-block-jobs')
620 self.assert_qmp(result, 'return[0]/device', 'drive0')
621 self.assert_qmp(result, 'return[0]/speed', 0)
623 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
624 self.assert_qmp(result, 'return', {})
626 # Ensure the speed we set was accepted
627 result = self.vm.qmp('query-block-jobs')
628 self.assert_qmp(result, 'return[0]/device', 'drive0')
629 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
631 self.wait_ready_and_cancel()
633 # Check setting speed in drive-mirror works
634 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
635 target=target_img, speed=4*1024*1024)
636 self.assert_qmp(result, 'return', {})
638 result = self.vm.qmp('query-block-jobs')
639 self.assert_qmp(result, 'return[0]/device', 'drive0')
640 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
642 self.wait_ready_and_cancel()
644 def test_set_speed_invalid(self):
645 self.assert_no_active_block_jobs()
647 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
648 target=target_img, speed=-1)
649 self.assert_qmp(result, 'error/class', 'GenericError')
651 self.assert_no_active_block_jobs()
653 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
654 target=target_img)
655 self.assert_qmp(result, 'return', {})
657 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
658 self.assert_qmp(result, 'error/class', 'GenericError')
660 self.wait_ready_and_cancel()
662 class TestUnbackedSource(iotests.QMPTestCase):
663 image_len = 2 * 1024 * 1024 # MB
665 def setUp(self):
666 qemu_img('create', '-f', iotests.imgfmt, test_img,
667 str(TestUnbackedSource.image_len))
668 self.vm = iotests.VM().add_drive(test_img)
669 self.vm.launch()
671 def tearDown(self):
672 self.vm.shutdown()
673 os.remove(test_img)
674 os.remove(target_img)
676 def test_absolute_paths_full(self):
677 self.assert_no_active_block_jobs()
678 result = self.vm.qmp('drive-mirror', device='drive0',
679 sync='full', target=target_img,
680 mode='absolute-paths')
681 self.assert_qmp(result, 'return', {})
682 self.complete_and_wait()
683 self.assert_no_active_block_jobs()
685 def test_absolute_paths_top(self):
686 self.assert_no_active_block_jobs()
687 result = self.vm.qmp('drive-mirror', device='drive0',
688 sync='top', target=target_img,
689 mode='absolute-paths')
690 self.assert_qmp(result, 'return', {})
691 self.complete_and_wait()
692 self.assert_no_active_block_jobs()
694 def test_absolute_paths_none(self):
695 self.assert_no_active_block_jobs()
696 result = self.vm.qmp('drive-mirror', device='drive0',
697 sync='none', target=target_img,
698 mode='absolute-paths')
699 self.assert_qmp(result, 'return', {})
700 self.complete_and_wait()
701 self.assert_no_active_block_jobs()
703 class TestRepairQuorum(iotests.QMPTestCase):
704 """ This class test quorum file repair using drive-mirror.
705 It's mostly a fork of TestSingleDrive """
706 image_len = 1 * 1024 * 1024 # MB
707 IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
709 def has_quorum(self):
710 return 'quorum' in iotests.qemu_img_pipe('--help')
712 def setUp(self):
713 self.vm = iotests.VM()
715 if iotests.qemu_default_machine == 'pc':
716 self.vm.add_drive(None, 'media=cdrom', 'ide')
718 # Add each individual quorum images
719 for i in self.IMAGES:
720 qemu_img('create', '-f', iotests.imgfmt, i,
721 str(TestSingleDrive.image_len))
722 # Assign a node name to each quorum image in order to manipulate
723 # them
724 opts = "node-name=img%i" % self.IMAGES.index(i)
725 self.vm = self.vm.add_drive(i, opts)
727 self.vm.launch()
729 #assemble the quorum block device from the individual files
730 args = { "options" : { "driver": "quorum", "id": "quorum0",
731 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
732 if self.has_quorum():
733 result = self.vm.qmp("blockdev-add", **args)
734 self.assert_qmp(result, 'return', {})
737 def tearDown(self):
738 self.vm.shutdown()
739 for i in self.IMAGES + [ quorum_repair_img ]:
740 # Do a try/except because the test may have deleted some images
741 try:
742 os.remove(i)
743 except OSError:
744 pass
746 def test_complete(self):
747 if not self.has_quorum():
748 return
750 self.assert_no_active_block_jobs()
752 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
753 node_name="repair0",
754 replaces="img1",
755 target=quorum_repair_img, format=iotests.imgfmt)
756 self.assert_qmp(result, 'return', {})
758 self.complete_and_wait(drive="quorum0")
759 result = self.vm.qmp('query-named-block-nodes')
760 self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
761 # TODO: a better test requiring some QEMU infrastructure will be added
762 # to check that this file is really driven by quorum
763 self.vm.shutdown()
764 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
765 'target image does not match source after mirroring')
767 def test_cancel(self):
768 if not self.has_quorum():
769 return
771 self.assert_no_active_block_jobs()
773 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
774 node_name="repair0",
775 replaces="img1",
776 target=quorum_repair_img, format=iotests.imgfmt)
777 self.assert_qmp(result, 'return', {})
779 self.cancel_and_wait(drive="quorum0", force=True)
780 # here we check that the last registered quorum file has not been
781 # swapped out and unref
782 result = self.vm.qmp('query-named-block-nodes')
783 self.assert_qmp(result, 'return[1]/file', quorum_img3)
784 self.vm.shutdown()
786 def test_cancel_after_ready(self):
787 if not self.has_quorum():
788 return
790 self.assert_no_active_block_jobs()
792 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
793 node_name="repair0",
794 replaces="img1",
795 target=quorum_repair_img, format=iotests.imgfmt)
796 self.assert_qmp(result, 'return', {})
798 self.wait_ready_and_cancel(drive="quorum0")
799 result = self.vm.qmp('query-named-block-nodes')
800 # here we check that the last registered quorum file has not been
801 # swapped out and unref
802 self.assert_qmp(result, 'return[1]/file', quorum_img3)
803 self.vm.shutdown()
804 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
805 'target image does not match source after mirroring')
807 def test_pause(self):
808 if not self.has_quorum():
809 return
811 self.assert_no_active_block_jobs()
813 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
814 node_name="repair0",
815 replaces="img1",
816 target=quorum_repair_img, format=iotests.imgfmt)
817 self.assert_qmp(result, 'return', {})
819 result = self.vm.qmp('block-job-pause', device='quorum0')
820 self.assert_qmp(result, 'return', {})
822 time.sleep(1)
823 result = self.vm.qmp('query-block-jobs')
824 offset = self.dictpath(result, 'return[0]/offset')
826 time.sleep(1)
827 result = self.vm.qmp('query-block-jobs')
828 self.assert_qmp(result, 'return[0]/offset', offset)
830 result = self.vm.qmp('block-job-resume', device='quorum0')
831 self.assert_qmp(result, 'return', {})
833 self.complete_and_wait(drive="quorum0")
834 self.vm.shutdown()
835 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
836 'target image does not match source after mirroring')
838 def test_medium_not_found(self):
839 if not self.has_quorum():
840 return
842 if iotests.qemu_default_machine != 'pc':
843 return
845 result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM
846 sync='full',
847 node_name='repair0',
848 replaces='img1',
849 target=quorum_repair_img, format=iotests.imgfmt)
850 self.assert_qmp(result, 'error/class', 'GenericError')
852 def test_image_not_found(self):
853 if not self.has_quorum():
854 return
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 if not self.has_quorum():
865 return
867 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
868 node_name='repair0',
869 replaces='img1',
870 target=quorum_repair_img, format=iotests.imgfmt)
871 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
873 def test_wrong_sync_mode(self):
874 if not self.has_quorum():
875 return
877 result = self.vm.qmp('drive-mirror', device='quorum0',
878 node_name='repair0',
879 replaces='img1',
880 target=quorum_repair_img, format=iotests.imgfmt)
881 self.assert_qmp(result, 'error/class', 'GenericError')
883 def test_no_node_name(self):
884 if not self.has_quorum():
885 return
887 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
888 replaces='img1',
889 target=quorum_repair_img, format=iotests.imgfmt)
890 self.assert_qmp(result, 'error/class', 'GenericError')
892 def test_nonexistent_replaces(self):
893 if not self.has_quorum():
894 return
896 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
897 node_name='repair0',
898 replaces='img77',
899 target=quorum_repair_img, format=iotests.imgfmt)
900 self.assert_qmp(result, 'error/class', 'GenericError')
902 def test_after_a_quorum_snapshot(self):
903 if not self.has_quorum():
904 return
906 result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
907 snapshot_file=quorum_snapshot_file,
908 snapshot_node_name="snap1");
910 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
911 node_name='repair0',
912 replaces="img1",
913 target=quorum_repair_img, format=iotests.imgfmt)
914 self.assert_qmp(result, 'error/class', 'GenericError')
916 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
917 node_name='repair0',
918 replaces="snap1",
919 target=quorum_repair_img, format=iotests.imgfmt)
920 self.assert_qmp(result, 'return', {})
922 self.complete_and_wait(drive="quorum0")
923 result = self.vm.qmp('query-named-block-nodes')
924 self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
925 # TODO: a better test requiring some QEMU infrastructure will be added
926 # to check that this file is really driven by quorum
927 self.vm.shutdown()
929 if __name__ == '__main__':
930 iotests.main(supported_fmts=['qcow2', 'qed'])