commit: get the overlay node before manipulating the backing chain
[qemu.git] / tests / qemu-iotests / 041
blob80939c0d0dec1c5c99ded0d67749944d69c1f1df
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 TestSingleDrive(iotests.QMPTestCase):
38 image_len = 1 * 1024 * 1024 # MB
39 qmp_cmd = 'drive-mirror'
40 qmp_target = target_img
42 def setUp(self):
43 iotests.create_image(backing_img, self.image_len)
44 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
45 self.vm = iotests.VM().add_drive(test_img)
46 if iotests.qemu_default_machine == 'pc':
47 self.vm.add_drive(None, 'media=cdrom', 'ide')
48 self.vm.launch()
50 def tearDown(self):
51 self.vm.shutdown()
52 os.remove(test_img)
53 os.remove(backing_img)
54 try:
55 os.remove(target_img)
56 except OSError:
57 pass
59 def test_complete(self):
60 self.assert_no_active_block_jobs()
62 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
63 target=self.qmp_target)
64 self.assert_qmp(result, 'return', {})
66 self.complete_and_wait()
67 result = self.vm.qmp('query-block')
68 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
69 self.vm.shutdown()
70 self.assertTrue(iotests.compare_images(test_img, target_img),
71 'target image does not match source after mirroring')
73 def test_cancel(self):
74 self.assert_no_active_block_jobs()
76 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
77 target=self.qmp_target)
78 self.assert_qmp(result, 'return', {})
80 self.cancel_and_wait(force=True)
81 result = self.vm.qmp('query-block')
82 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
83 self.vm.shutdown()
85 def test_cancel_after_ready(self):
86 self.assert_no_active_block_jobs()
88 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
89 target=self.qmp_target)
90 self.assert_qmp(result, 'return', {})
92 self.wait_ready_and_cancel()
93 result = self.vm.qmp('query-block')
94 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
95 self.vm.shutdown()
96 self.assertTrue(iotests.compare_images(test_img, target_img),
97 'target image does not match source after mirroring')
99 def test_pause(self):
100 self.assert_no_active_block_jobs()
102 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
103 target=self.qmp_target)
104 self.assert_qmp(result, 'return', {})
106 result = self.vm.qmp('block-job-pause', device='drive0')
107 self.assert_qmp(result, 'return', {})
109 time.sleep(1)
110 result = self.vm.qmp('query-block-jobs')
111 offset = self.dictpath(result, 'return[0]/offset')
113 time.sleep(1)
114 result = self.vm.qmp('query-block-jobs')
115 self.assert_qmp(result, 'return[0]/offset', offset)
117 result = self.vm.qmp('block-job-resume', device='drive0')
118 self.assert_qmp(result, 'return', {})
120 self.complete_and_wait()
121 self.vm.shutdown()
122 self.assertTrue(iotests.compare_images(test_img, target_img),
123 'target image does not match source after mirroring')
125 def test_small_buffer(self):
126 self.assert_no_active_block_jobs()
128 # A small buffer is rounded up automatically
129 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
130 buf_size=4096, target=self.qmp_target)
131 self.assert_qmp(result, 'return', {})
133 self.complete_and_wait()
134 result = self.vm.qmp('query-block')
135 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
136 self.vm.shutdown()
137 self.assertTrue(iotests.compare_images(test_img, target_img),
138 'target image does not match source after mirroring')
140 def test_small_buffer2(self):
141 self.assert_no_active_block_jobs()
143 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
144 % (self.image_len, self.image_len), target_img)
145 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
146 buf_size=65536, mode='existing', target=self.qmp_target)
147 self.assert_qmp(result, 'return', {})
149 self.complete_and_wait()
150 result = self.vm.qmp('query-block')
151 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
152 self.vm.shutdown()
153 self.assertTrue(iotests.compare_images(test_img, target_img),
154 'target image does not match source after mirroring')
156 def test_large_cluster(self):
157 self.assert_no_active_block_jobs()
159 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
160 % (self.image_len, backing_img), target_img)
161 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
162 mode='existing', target=self.qmp_target)
163 self.assert_qmp(result, 'return', {})
165 self.complete_and_wait()
166 result = self.vm.qmp('query-block')
167 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
168 self.vm.shutdown()
169 self.assertTrue(iotests.compare_images(test_img, target_img),
170 'target image does not match source after mirroring')
172 def test_medium_not_found(self):
173 if iotests.qemu_default_machine != 'pc':
174 return
176 result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full',
177 target=self.qmp_target)
178 self.assert_qmp(result, 'error/class', 'GenericError')
180 def test_image_not_found(self):
181 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
182 mode='existing', target=self.qmp_target)
183 self.assert_qmp(result, 'error/class', 'GenericError')
185 def test_device_not_found(self):
186 result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full',
187 target=self.qmp_target)
188 self.assert_qmp(result, 'error/class', 'GenericError')
190 class TestSingleBlockdev(TestSingleDrive):
191 qmp_cmd = 'blockdev-mirror'
192 qmp_target = 'node1'
194 def setUp(self):
195 TestSingleDrive.setUp(self)
196 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
197 args = {'options':
198 {'driver': iotests.imgfmt,
199 'node-name': self.qmp_target,
200 'file': { 'filename': target_img, 'driver': 'file' } } }
201 result = self.vm.qmp("blockdev-add", **args)
202 self.assert_qmp(result, 'return', {})
204 test_large_cluster = None
205 test_image_not_found = None
206 test_small_buffer2 = None
208 class TestSingleDriveZeroLength(TestSingleDrive):
209 image_len = 0
210 test_small_buffer2 = None
211 test_large_cluster = None
213 class TestSingleBlockdevZeroLength(TestSingleBlockdev):
214 image_len = 0
216 class TestSingleDriveUnalignedLength(TestSingleDrive):
217 image_len = 1025 * 1024
218 test_small_buffer2 = None
219 test_large_cluster = None
221 class TestSingleBlockdevUnalignedLength(TestSingleBlockdev):
222 image_len = 1025 * 1024
224 class TestMirrorNoBacking(iotests.QMPTestCase):
225 image_len = 2 * 1024 * 1024 # MB
227 def setUp(self):
228 iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
229 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
230 self.vm = iotests.VM().add_drive(test_img)
231 self.vm.launch()
233 def tearDown(self):
234 self.vm.shutdown()
235 os.remove(test_img)
236 os.remove(backing_img)
237 try:
238 os.remove(target_backing_img)
239 except:
240 pass
241 os.remove(target_img)
243 def test_complete(self):
244 self.assert_no_active_block_jobs()
246 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
247 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
248 mode='existing', target=target_img)
249 self.assert_qmp(result, 'return', {})
251 self.complete_and_wait()
252 result = self.vm.qmp('query-block')
253 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
254 self.vm.shutdown()
255 self.assertTrue(iotests.compare_images(test_img, target_img),
256 'target image does not match source after mirroring')
258 def test_cancel(self):
259 self.assert_no_active_block_jobs()
261 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
262 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
263 mode='existing', target=target_img)
264 self.assert_qmp(result, 'return', {})
266 self.wait_ready_and_cancel()
267 result = self.vm.qmp('query-block')
268 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
269 self.vm.shutdown()
270 self.assertTrue(iotests.compare_images(test_img, target_img),
271 'target image does not match source after mirroring')
273 def test_large_cluster(self):
274 self.assert_no_active_block_jobs()
276 # qemu-img create fails if the image is not there
277 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
278 %(TestMirrorNoBacking.image_len), target_backing_img)
279 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
280 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
282 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
283 mode='existing', target=target_img)
284 self.assert_qmp(result, 'return', {})
286 self.complete_and_wait()
287 result = self.vm.qmp('query-block')
288 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
289 self.vm.shutdown()
290 self.assertTrue(iotests.compare_images(test_img, target_img),
291 'target image does not match source after mirroring')
293 class TestMirrorResized(iotests.QMPTestCase):
294 backing_len = 1 * 1024 * 1024 # MB
295 image_len = 2 * 1024 * 1024 # MB
297 def setUp(self):
298 iotests.create_image(backing_img, TestMirrorResized.backing_len)
299 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
300 qemu_img('resize', test_img, '2M')
301 self.vm = iotests.VM().add_drive(test_img)
302 self.vm.launch()
304 def tearDown(self):
305 self.vm.shutdown()
306 os.remove(test_img)
307 os.remove(backing_img)
308 try:
309 os.remove(target_img)
310 except OSError:
311 pass
313 def test_complete_top(self):
314 self.assert_no_active_block_jobs()
316 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
317 target=target_img)
318 self.assert_qmp(result, 'return', {})
320 self.complete_and_wait()
321 result = self.vm.qmp('query-block')
322 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
323 self.vm.shutdown()
324 self.assertTrue(iotests.compare_images(test_img, target_img),
325 'target image does not match source after mirroring')
327 def test_complete_full(self):
328 self.assert_no_active_block_jobs()
330 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
331 target=target_img)
332 self.assert_qmp(result, 'return', {})
334 self.complete_and_wait()
335 result = self.vm.qmp('query-block')
336 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
337 self.vm.shutdown()
338 self.assertTrue(iotests.compare_images(test_img, target_img),
339 'target image does not match source after mirroring')
341 class TestReadErrors(iotests.QMPTestCase):
342 image_len = 2 * 1024 * 1024 # MB
344 # this should be a multiple of twice the default granularity
345 # so that we hit this offset first in state 1
346 MIRROR_GRANULARITY = 1024 * 1024
348 def create_blkdebug_file(self, name, event, errno):
349 file = open(name, 'w')
350 file.write('''
351 [inject-error]
352 state = "1"
353 event = "%s"
354 errno = "%d"
355 immediately = "off"
356 once = "on"
357 sector = "%d"
359 [set-state]
360 state = "1"
361 event = "%s"
362 new_state = "2"
364 [set-state]
365 state = "2"
366 event = "%s"
367 new_state = "1"
368 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
369 file.close()
371 def setUp(self):
372 self.blkdebug_file = backing_img + ".blkdebug"
373 iotests.create_image(backing_img, TestReadErrors.image_len)
374 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
375 qemu_img('create', '-f', iotests.imgfmt,
376 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
377 % (self.blkdebug_file, backing_img),
378 test_img)
379 # Write something for tests that use sync='top'
380 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
381 test_img)
382 self.vm = iotests.VM().add_drive(test_img)
383 self.vm.launch()
385 def tearDown(self):
386 self.vm.shutdown()
387 os.remove(test_img)
388 os.remove(backing_img)
389 os.remove(self.blkdebug_file)
391 def test_report_read(self):
392 self.assert_no_active_block_jobs()
394 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
395 target=target_img)
396 self.assert_qmp(result, 'return', {})
398 completed = False
399 error = False
400 while not completed:
401 for event in self.vm.get_qmp_events(wait=True):
402 if event['event'] == 'BLOCK_JOB_ERROR':
403 self.assert_qmp(event, 'data/device', 'drive0')
404 self.assert_qmp(event, 'data/operation', 'read')
405 error = True
406 elif event['event'] == 'BLOCK_JOB_READY':
407 self.assertTrue(False, 'job completed unexpectedly')
408 elif event['event'] == 'BLOCK_JOB_COMPLETED':
409 self.assertTrue(error, 'job completed unexpectedly')
410 self.assert_qmp(event, 'data/type', 'mirror')
411 self.assert_qmp(event, 'data/device', 'drive0')
412 self.assert_qmp(event, 'data/error', 'Input/output error')
413 completed = True
415 self.assert_no_active_block_jobs()
416 self.vm.shutdown()
418 def test_ignore_read(self):
419 self.assert_no_active_block_jobs()
421 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
422 target=target_img, on_source_error='ignore')
423 self.assert_qmp(result, 'return', {})
425 event = self.vm.get_qmp_event(wait=True)
426 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
427 self.assert_qmp(event, 'data/device', 'drive0')
428 self.assert_qmp(event, 'data/operation', 'read')
429 result = self.vm.qmp('query-block-jobs')
430 self.assert_qmp(result, 'return[0]/paused', False)
431 self.complete_and_wait()
432 self.vm.shutdown()
434 def test_large_cluster(self):
435 self.assert_no_active_block_jobs()
437 # Test COW into the target image. The first half of the
438 # cluster at MIRROR_GRANULARITY has to be copied from
439 # backing_img, even though sync='top'.
440 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
441 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
442 on_source_error='ignore',
443 mode='existing', target=target_img)
444 self.assert_qmp(result, 'return', {})
446 event = self.vm.get_qmp_event(wait=True)
447 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
448 self.assert_qmp(event, 'data/device', 'drive0')
449 self.assert_qmp(event, 'data/operation', 'read')
450 result = self.vm.qmp('query-block-jobs')
451 self.assert_qmp(result, 'return[0]/paused', False)
452 self.complete_and_wait()
453 self.vm.shutdown()
455 # Detach blkdebug to compare images successfully
456 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
457 self.assertTrue(iotests.compare_images(test_img, target_img),
458 'target image does not match source after mirroring')
460 def test_stop_read(self):
461 self.assert_no_active_block_jobs()
463 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
464 target=target_img, on_source_error='stop')
465 self.assert_qmp(result, 'return', {})
467 error = False
468 ready = False
469 while not ready:
470 for event in self.vm.get_qmp_events(wait=True):
471 if event['event'] == 'BLOCK_JOB_ERROR':
472 self.assert_qmp(event, 'data/device', 'drive0')
473 self.assert_qmp(event, 'data/operation', 'read')
475 result = self.vm.qmp('query-block-jobs')
476 self.assert_qmp(result, 'return[0]/paused', True)
477 self.assert_qmp(result, 'return[0]/io-status', 'failed')
479 result = self.vm.qmp('block-job-resume', device='drive0')
480 self.assert_qmp(result, 'return', {})
481 error = True
482 elif event['event'] == 'BLOCK_JOB_READY':
483 self.assertTrue(error, 'job completed unexpectedly')
484 self.assert_qmp(event, 'data/device', 'drive0')
485 ready = True
487 result = self.vm.qmp('query-block-jobs')
488 self.assert_qmp(result, 'return[0]/paused', False)
489 self.assert_qmp(result, 'return[0]/io-status', 'ok')
491 self.complete_and_wait(wait_ready=False)
492 self.assert_no_active_block_jobs()
493 self.vm.shutdown()
495 class TestWriteErrors(iotests.QMPTestCase):
496 image_len = 2 * 1024 * 1024 # MB
498 # this should be a multiple of twice the default granularity
499 # so that we hit this offset first in state 1
500 MIRROR_GRANULARITY = 1024 * 1024
502 def create_blkdebug_file(self, name, event, errno):
503 file = open(name, 'w')
504 file.write('''
505 [inject-error]
506 state = "1"
507 event = "%s"
508 errno = "%d"
509 immediately = "off"
510 once = "on"
511 sector = "%d"
513 [set-state]
514 state = "1"
515 event = "%s"
516 new_state = "2"
518 [set-state]
519 state = "2"
520 event = "%s"
521 new_state = "1"
522 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
523 file.close()
525 def setUp(self):
526 self.blkdebug_file = target_img + ".blkdebug"
527 iotests.create_image(backing_img, TestWriteErrors.image_len)
528 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
529 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
530 self.vm = iotests.VM().add_drive(test_img)
531 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
532 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
533 self.vm.launch()
535 def tearDown(self):
536 self.vm.shutdown()
537 os.remove(test_img)
538 os.remove(backing_img)
539 os.remove(self.blkdebug_file)
541 def test_report_write(self):
542 self.assert_no_active_block_jobs()
544 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
545 mode='existing', target=self.target_img)
546 self.assert_qmp(result, 'return', {})
548 completed = False
549 error = False
550 while not completed:
551 for event in self.vm.get_qmp_events(wait=True):
552 if event['event'] == 'BLOCK_JOB_ERROR':
553 self.assert_qmp(event, 'data/device', 'drive0')
554 self.assert_qmp(event, 'data/operation', 'write')
555 error = True
556 elif event['event'] == 'BLOCK_JOB_READY':
557 self.assertTrue(False, 'job completed unexpectedly')
558 elif event['event'] == 'BLOCK_JOB_COMPLETED':
559 self.assertTrue(error, 'job completed unexpectedly')
560 self.assert_qmp(event, 'data/type', 'mirror')
561 self.assert_qmp(event, 'data/device', 'drive0')
562 self.assert_qmp(event, 'data/error', 'Input/output error')
563 completed = True
565 self.assert_no_active_block_jobs()
566 self.vm.shutdown()
568 def test_ignore_write(self):
569 self.assert_no_active_block_jobs()
571 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
572 mode='existing', target=self.target_img,
573 on_target_error='ignore')
574 self.assert_qmp(result, 'return', {})
576 event = self.vm.get_qmp_event(wait=True)
577 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
578 self.assert_qmp(event, 'data/device', 'drive0')
579 self.assert_qmp(event, 'data/operation', 'write')
580 result = self.vm.qmp('query-block-jobs')
581 self.assert_qmp(result, 'return[0]/paused', False)
582 self.complete_and_wait()
583 self.vm.shutdown()
585 def test_stop_write(self):
586 self.assert_no_active_block_jobs()
588 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
589 mode='existing', target=self.target_img,
590 on_target_error='stop')
591 self.assert_qmp(result, 'return', {})
593 error = False
594 ready = False
595 while not ready:
596 for event in self.vm.get_qmp_events(wait=True):
597 if event['event'] == 'BLOCK_JOB_ERROR':
598 self.assert_qmp(event, 'data/device', 'drive0')
599 self.assert_qmp(event, 'data/operation', 'write')
601 result = self.vm.qmp('query-block-jobs')
602 self.assert_qmp(result, 'return[0]/paused', True)
603 self.assert_qmp(result, 'return[0]/io-status', 'failed')
605 result = self.vm.qmp('block-job-resume', device='drive0')
606 self.assert_qmp(result, 'return', {})
608 result = self.vm.qmp('query-block-jobs')
609 self.assert_qmp(result, 'return[0]/paused', False)
610 self.assert_qmp(result, 'return[0]/io-status', 'ok')
611 error = True
612 elif event['event'] == 'BLOCK_JOB_READY':
613 self.assertTrue(error, 'job completed unexpectedly')
614 self.assert_qmp(event, 'data/device', 'drive0')
615 ready = True
617 self.complete_and_wait(wait_ready=False)
618 self.assert_no_active_block_jobs()
619 self.vm.shutdown()
621 class TestSetSpeed(iotests.QMPTestCase):
622 image_len = 80 * 1024 * 1024 # MB
624 def setUp(self):
625 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
626 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
627 self.vm = iotests.VM().add_drive(test_img)
628 self.vm.launch()
630 def tearDown(self):
631 self.vm.shutdown()
632 os.remove(test_img)
633 os.remove(backing_img)
634 os.remove(target_img)
636 def test_set_speed(self):
637 self.assert_no_active_block_jobs()
639 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
640 target=target_img)
641 self.assert_qmp(result, 'return', {})
643 # Default speed is 0
644 result = self.vm.qmp('query-block-jobs')
645 self.assert_qmp(result, 'return[0]/device', 'drive0')
646 self.assert_qmp(result, 'return[0]/speed', 0)
648 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
649 self.assert_qmp(result, 'return', {})
651 # Ensure the speed we set was accepted
652 result = self.vm.qmp('query-block-jobs')
653 self.assert_qmp(result, 'return[0]/device', 'drive0')
654 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
656 self.wait_ready_and_cancel()
658 # Check setting speed in drive-mirror works
659 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
660 target=target_img, speed=4*1024*1024)
661 self.assert_qmp(result, 'return', {})
663 result = self.vm.qmp('query-block-jobs')
664 self.assert_qmp(result, 'return[0]/device', 'drive0')
665 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
667 self.wait_ready_and_cancel()
669 def test_set_speed_invalid(self):
670 self.assert_no_active_block_jobs()
672 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
673 target=target_img, speed=-1)
674 self.assert_qmp(result, 'error/class', 'GenericError')
676 self.assert_no_active_block_jobs()
678 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
679 target=target_img)
680 self.assert_qmp(result, 'return', {})
682 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
683 self.assert_qmp(result, 'error/class', 'GenericError')
685 self.wait_ready_and_cancel()
687 class TestUnbackedSource(iotests.QMPTestCase):
688 image_len = 2 * 1024 * 1024 # MB
690 def setUp(self):
691 qemu_img('create', '-f', iotests.imgfmt, test_img,
692 str(TestUnbackedSource.image_len))
693 self.vm = iotests.VM().add_drive(test_img)
694 self.vm.launch()
696 def tearDown(self):
697 self.vm.shutdown()
698 os.remove(test_img)
699 os.remove(target_img)
701 def test_absolute_paths_full(self):
702 self.assert_no_active_block_jobs()
703 result = self.vm.qmp('drive-mirror', device='drive0',
704 sync='full', target=target_img,
705 mode='absolute-paths')
706 self.assert_qmp(result, 'return', {})
707 self.complete_and_wait()
708 self.assert_no_active_block_jobs()
710 def test_absolute_paths_top(self):
711 self.assert_no_active_block_jobs()
712 result = self.vm.qmp('drive-mirror', device='drive0',
713 sync='top', target=target_img,
714 mode='absolute-paths')
715 self.assert_qmp(result, 'return', {})
716 self.complete_and_wait()
717 self.assert_no_active_block_jobs()
719 def test_absolute_paths_none(self):
720 self.assert_no_active_block_jobs()
721 result = self.vm.qmp('drive-mirror', device='drive0',
722 sync='none', target=target_img,
723 mode='absolute-paths')
724 self.assert_qmp(result, 'return', {})
725 self.complete_and_wait()
726 self.assert_no_active_block_jobs()
728 class TestGranularity(iotests.QMPTestCase):
729 image_len = 10 * 1024 * 1024 # MB
731 def setUp(self):
732 qemu_img('create', '-f', iotests.imgfmt, test_img,
733 str(TestGranularity.image_len))
734 qemu_io('-c', 'write 0 %d' % (self.image_len),
735 test_img)
736 self.vm = iotests.VM().add_drive(test_img)
737 self.vm.launch()
739 def tearDown(self):
740 self.vm.shutdown()
741 self.assertTrue(iotests.compare_images(test_img, target_img),
742 'target image does not match source after mirroring')
743 os.remove(test_img)
744 os.remove(target_img)
746 def test_granularity(self):
747 self.assert_no_active_block_jobs()
748 result = self.vm.qmp('drive-mirror', device='drive0',
749 sync='full', target=target_img,
750 mode='absolute-paths', granularity=8192)
751 self.assert_qmp(result, 'return', {})
752 event = self.vm.get_qmp_event(wait=60.0)
753 # Failures will manifest as COMPLETED/ERROR.
754 self.assert_qmp(event, 'event', 'BLOCK_JOB_READY')
755 self.complete_and_wait(drive='drive0', wait_ready=False)
756 self.assert_no_active_block_jobs()
758 class TestRepairQuorum(iotests.QMPTestCase):
759 """ This class test quorum file repair using drive-mirror.
760 It's mostly a fork of TestSingleDrive """
761 image_len = 1 * 1024 * 1024 # MB
762 IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
764 def has_quorum(self):
765 return 'quorum' in iotests.qemu_img_pipe('--help')
767 def setUp(self):
768 self.vm = iotests.VM()
770 if iotests.qemu_default_machine == 'pc':
771 self.vm.add_drive(None, 'media=cdrom', 'ide')
773 # Add each individual quorum images
774 for i in self.IMAGES:
775 qemu_img('create', '-f', iotests.imgfmt, i,
776 str(TestSingleDrive.image_len))
777 # Assign a node name to each quorum image in order to manipulate
778 # them
779 opts = "node-name=img%i" % self.IMAGES.index(i)
780 self.vm = self.vm.add_drive(i, opts)
782 self.vm.launch()
784 #assemble the quorum block device from the individual files
785 args = { "options" : { "driver": "quorum", "id": "quorum0",
786 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
787 if self.has_quorum():
788 result = self.vm.qmp("blockdev-add", **args)
789 self.assert_qmp(result, 'return', {})
792 def tearDown(self):
793 self.vm.shutdown()
794 for i in self.IMAGES + [ quorum_repair_img ]:
795 # Do a try/except because the test may have deleted some images
796 try:
797 os.remove(i)
798 except OSError:
799 pass
801 def test_complete(self):
802 if not self.has_quorum():
803 return
805 self.assert_no_active_block_jobs()
807 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
808 node_name="repair0",
809 replaces="img1",
810 target=quorum_repair_img, format=iotests.imgfmt)
811 self.assert_qmp(result, 'return', {})
813 self.complete_and_wait(drive="quorum0")
814 self.assert_has_block_node("repair0", quorum_repair_img)
815 # TODO: a better test requiring some QEMU infrastructure will be added
816 # to check that this file is really driven by quorum
817 self.vm.shutdown()
818 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
819 'target image does not match source after mirroring')
821 def test_cancel(self):
822 if not self.has_quorum():
823 return
825 self.assert_no_active_block_jobs()
827 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
828 node_name="repair0",
829 replaces="img1",
830 target=quorum_repair_img, format=iotests.imgfmt)
831 self.assert_qmp(result, 'return', {})
833 self.cancel_and_wait(drive="quorum0", force=True)
834 # here we check that the last registered quorum file has not been
835 # swapped out and unref
836 self.assert_has_block_node(None, quorum_img3)
837 self.vm.shutdown()
839 def test_cancel_after_ready(self):
840 if not self.has_quorum():
841 return
843 self.assert_no_active_block_jobs()
845 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
846 node_name="repair0",
847 replaces="img1",
848 target=quorum_repair_img, format=iotests.imgfmt)
849 self.assert_qmp(result, 'return', {})
851 self.wait_ready_and_cancel(drive="quorum0")
852 # here we check that the last registered quorum file has not been
853 # swapped out and unref
854 self.assert_has_block_node(None, quorum_img3)
855 self.vm.shutdown()
856 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
857 'target image does not match source after mirroring')
859 def test_pause(self):
860 if not self.has_quorum():
861 return
863 self.assert_no_active_block_jobs()
865 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
866 node_name="repair0",
867 replaces="img1",
868 target=quorum_repair_img, format=iotests.imgfmt)
869 self.assert_qmp(result, 'return', {})
871 result = self.vm.qmp('block-job-pause', device='quorum0')
872 self.assert_qmp(result, 'return', {})
874 time.sleep(1)
875 result = self.vm.qmp('query-block-jobs')
876 offset = self.dictpath(result, 'return[0]/offset')
878 time.sleep(1)
879 result = self.vm.qmp('query-block-jobs')
880 self.assert_qmp(result, 'return[0]/offset', offset)
882 result = self.vm.qmp('block-job-resume', device='quorum0')
883 self.assert_qmp(result, 'return', {})
885 self.complete_and_wait(drive="quorum0")
886 self.vm.shutdown()
887 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
888 'target image does not match source after mirroring')
890 def test_medium_not_found(self):
891 if not self.has_quorum():
892 return
894 if iotests.qemu_default_machine != 'pc':
895 return
897 result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM
898 sync='full',
899 node_name='repair0',
900 replaces='img1',
901 target=quorum_repair_img, format=iotests.imgfmt)
902 self.assert_qmp(result, 'error/class', 'GenericError')
904 def test_image_not_found(self):
905 if not self.has_quorum():
906 return
908 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
909 node_name='repair0',
910 replaces='img1',
911 mode='existing',
912 target=quorum_repair_img, format=iotests.imgfmt)
913 self.assert_qmp(result, 'error/class', 'GenericError')
915 def test_device_not_found(self):
916 if not self.has_quorum():
917 return
919 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
920 node_name='repair0',
921 replaces='img1',
922 target=quorum_repair_img, format=iotests.imgfmt)
923 self.assert_qmp(result, 'error/class', 'GenericError')
925 def test_wrong_sync_mode(self):
926 if not self.has_quorum():
927 return
929 result = self.vm.qmp('drive-mirror', device='quorum0',
930 node_name='repair0',
931 replaces='img1',
932 target=quorum_repair_img, format=iotests.imgfmt)
933 self.assert_qmp(result, 'error/class', 'GenericError')
935 def test_no_node_name(self):
936 if not self.has_quorum():
937 return
939 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
940 replaces='img1',
941 target=quorum_repair_img, format=iotests.imgfmt)
942 self.assert_qmp(result, 'error/class', 'GenericError')
944 def test_nonexistent_replaces(self):
945 if not self.has_quorum():
946 return
948 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
949 node_name='repair0',
950 replaces='img77',
951 target=quorum_repair_img, format=iotests.imgfmt)
952 self.assert_qmp(result, 'error/class', 'GenericError')
954 def test_after_a_quorum_snapshot(self):
955 if not self.has_quorum():
956 return
958 result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
959 snapshot_file=quorum_snapshot_file,
960 snapshot_node_name="snap1");
962 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
963 node_name='repair0',
964 replaces="img1",
965 target=quorum_repair_img, format=iotests.imgfmt)
966 self.assert_qmp(result, 'error/class', 'GenericError')
968 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
969 node_name='repair0',
970 replaces="snap1",
971 target=quorum_repair_img, format=iotests.imgfmt)
972 self.assert_qmp(result, 'return', {})
974 self.complete_and_wait(drive="quorum0")
975 self.assert_has_block_node("repair0", quorum_repair_img)
976 # TODO: a better test requiring some QEMU infrastructure will be added
977 # to check that this file is really driven by quorum
978 self.vm.shutdown()
980 if __name__ == '__main__':
981 iotests.main(supported_fmts=['qcow2', 'qed'])