Xen: use qemu_strtoul instead of strtol
[qemu/ar7.git] / tests / qemu-iotests / 041
blobc7da95d94e7dcfdec337f0b99adc7845783c0889
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
41 not_found_error = 'DeviceNotFound'
43 def setUp(self):
44 iotests.create_image(backing_img, self.image_len)
45 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
46 self.vm = iotests.VM().add_drive(test_img)
47 if iotests.qemu_default_machine == 'pc':
48 self.vm.add_drive(None, 'media=cdrom', 'ide')
49 self.vm.launch()
51 def tearDown(self):
52 self.vm.shutdown()
53 os.remove(test_img)
54 os.remove(backing_img)
55 try:
56 os.remove(target_img)
57 except OSError:
58 pass
60 def test_complete(self):
61 self.assert_no_active_block_jobs()
63 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
64 target=self.qmp_target)
65 self.assert_qmp(result, 'return', {})
67 self.complete_and_wait()
68 result = self.vm.qmp('query-block')
69 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
70 self.vm.shutdown()
71 self.assertTrue(iotests.compare_images(test_img, target_img),
72 'target image does not match source after mirroring')
74 def test_cancel(self):
75 self.assert_no_active_block_jobs()
77 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
78 target=self.qmp_target)
79 self.assert_qmp(result, 'return', {})
81 self.cancel_and_wait(force=True)
82 result = self.vm.qmp('query-block')
83 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
84 self.vm.shutdown()
86 def test_cancel_after_ready(self):
87 self.assert_no_active_block_jobs()
89 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
90 target=self.qmp_target)
91 self.assert_qmp(result, 'return', {})
93 self.wait_ready_and_cancel()
94 result = self.vm.qmp('query-block')
95 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
96 self.vm.shutdown()
97 self.assertTrue(iotests.compare_images(test_img, target_img),
98 'target image does not match source after mirroring')
100 def test_pause(self):
101 self.assert_no_active_block_jobs()
103 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
104 target=self.qmp_target)
105 self.assert_qmp(result, 'return', {})
107 result = self.vm.qmp('block-job-pause', device='drive0')
108 self.assert_qmp(result, 'return', {})
110 time.sleep(1)
111 result = self.vm.qmp('query-block-jobs')
112 offset = self.dictpath(result, 'return[0]/offset')
114 time.sleep(1)
115 result = self.vm.qmp('query-block-jobs')
116 self.assert_qmp(result, 'return[0]/offset', offset)
118 result = self.vm.qmp('block-job-resume', device='drive0')
119 self.assert_qmp(result, 'return', {})
121 self.complete_and_wait()
122 self.vm.shutdown()
123 self.assertTrue(iotests.compare_images(test_img, target_img),
124 'target image does not match source after mirroring')
126 def test_small_buffer(self):
127 self.assert_no_active_block_jobs()
129 # A small buffer is rounded up automatically
130 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
131 buf_size=4096, target=self.qmp_target)
132 self.assert_qmp(result, 'return', {})
134 self.complete_and_wait()
135 result = self.vm.qmp('query-block')
136 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
137 self.vm.shutdown()
138 self.assertTrue(iotests.compare_images(test_img, target_img),
139 'target image does not match source after mirroring')
141 def test_small_buffer2(self):
142 self.assert_no_active_block_jobs()
144 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
145 % (self.image_len, self.image_len), target_img)
146 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
147 buf_size=65536, mode='existing', target=self.qmp_target)
148 self.assert_qmp(result, 'return', {})
150 self.complete_and_wait()
151 result = self.vm.qmp('query-block')
152 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
153 self.vm.shutdown()
154 self.assertTrue(iotests.compare_images(test_img, target_img),
155 'target image does not match source after mirroring')
157 def test_large_cluster(self):
158 self.assert_no_active_block_jobs()
160 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
161 % (self.image_len, backing_img), target_img)
162 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
163 mode='existing', target=self.qmp_target)
164 self.assert_qmp(result, 'return', {})
166 self.complete_and_wait()
167 result = self.vm.qmp('query-block')
168 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
169 self.vm.shutdown()
170 self.assertTrue(iotests.compare_images(test_img, target_img),
171 'target image does not match source after mirroring')
173 def test_medium_not_found(self):
174 if iotests.qemu_default_machine != 'pc':
175 return
177 result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full',
178 target=self.qmp_target)
179 self.assert_qmp(result, 'error/class', self.not_found_error)
181 def test_image_not_found(self):
182 result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
183 mode='existing', target=self.qmp_target)
184 self.assert_qmp(result, 'error/class', 'GenericError')
186 def test_device_not_found(self):
187 result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full',
188 target=self.qmp_target)
189 self.assert_qmp(result, 'error/class', self.not_found_error)
191 class TestSingleBlockdev(TestSingleDrive):
192 qmp_cmd = 'blockdev-mirror'
193 qmp_target = 'node1'
194 not_found_error = 'GenericError'
196 def setUp(self):
197 TestSingleDrive.setUp(self)
198 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
199 args = {'options':
200 {'driver': iotests.imgfmt,
201 'node-name': self.qmp_target,
202 'file': { 'filename': target_img, 'driver': 'file' } } }
203 result = self.vm.qmp("blockdev-add", **args)
204 self.assert_qmp(result, 'return', {})
206 test_large_cluster = None
207 test_image_not_found = None
208 test_small_buffer2 = None
210 class TestBlockdevAttached(iotests.QMPTestCase):
211 image_len = 1 * 1024 * 1024 # MB
213 def setUp(self):
214 iotests.create_image(backing_img, self.image_len)
215 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
216 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
217 self.vm = iotests.VM().add_drive(test_img)
218 self.vm.launch()
220 def tearDown(self):
221 self.vm.shutdown()
222 os.remove(test_img)
223 os.remove(target_img)
225 def test_blockdev_attached(self):
226 self.assert_no_active_block_jobs()
227 args = {'options':
228 {'driver': iotests.imgfmt,
229 'id': 'drive1',
230 'file': { 'filename': target_img, 'driver': 'file' } } }
231 result = self.vm.qmp("blockdev-add", **args)
232 self.assert_qmp(result, 'return', {})
233 result = self.vm.qmp('blockdev-mirror', device='drive0', sync='full',
234 target='drive1')
235 self.assert_qmp(result, 'error/class', 'GenericError')
237 class TestSingleDriveZeroLength(TestSingleDrive):
238 image_len = 0
239 test_small_buffer2 = None
240 test_large_cluster = None
242 class TestSingleBlockdevZeroLength(TestSingleBlockdev):
243 image_len = 0
245 class TestSingleDriveUnalignedLength(TestSingleDrive):
246 image_len = 1025 * 1024
247 test_small_buffer2 = None
248 test_large_cluster = None
250 class TestSingleBlockdevUnalignedLength(TestSingleBlockdev):
251 image_len = 1025 * 1024
253 class TestMirrorNoBacking(iotests.QMPTestCase):
254 image_len = 2 * 1024 * 1024 # MB
256 def setUp(self):
257 iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
258 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
259 self.vm = iotests.VM().add_drive(test_img)
260 self.vm.launch()
262 def tearDown(self):
263 self.vm.shutdown()
264 os.remove(test_img)
265 os.remove(backing_img)
266 try:
267 os.remove(target_backing_img)
268 except:
269 pass
270 os.remove(target_img)
272 def test_complete(self):
273 self.assert_no_active_block_jobs()
275 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
276 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
277 mode='existing', target=target_img)
278 self.assert_qmp(result, 'return', {})
280 self.complete_and_wait()
281 result = self.vm.qmp('query-block')
282 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
283 self.vm.shutdown()
284 self.assertTrue(iotests.compare_images(test_img, target_img),
285 'target image does not match source after mirroring')
287 def test_cancel(self):
288 self.assert_no_active_block_jobs()
290 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
291 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
292 mode='existing', target=target_img)
293 self.assert_qmp(result, 'return', {})
295 self.wait_ready_and_cancel()
296 result = self.vm.qmp('query-block')
297 self.assert_qmp(result, 'return[0]/inserted/file', test_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_large_cluster(self):
303 self.assert_no_active_block_jobs()
305 # qemu-img create fails if the image is not there
306 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
307 %(TestMirrorNoBacking.image_len), target_backing_img)
308 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
309 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
311 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
312 mode='existing', target=target_img)
313 self.assert_qmp(result, 'return', {})
315 self.complete_and_wait()
316 result = self.vm.qmp('query-block')
317 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
318 self.vm.shutdown()
319 self.assertTrue(iotests.compare_images(test_img, target_img),
320 'target image does not match source after mirroring')
322 class TestMirrorResized(iotests.QMPTestCase):
323 backing_len = 1 * 1024 * 1024 # MB
324 image_len = 2 * 1024 * 1024 # MB
326 def setUp(self):
327 iotests.create_image(backing_img, TestMirrorResized.backing_len)
328 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
329 qemu_img('resize', test_img, '2M')
330 self.vm = iotests.VM().add_drive(test_img)
331 self.vm.launch()
333 def tearDown(self):
334 self.vm.shutdown()
335 os.remove(test_img)
336 os.remove(backing_img)
337 try:
338 os.remove(target_img)
339 except OSError:
340 pass
342 def test_complete_top(self):
343 self.assert_no_active_block_jobs()
345 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
346 target=target_img)
347 self.assert_qmp(result, 'return', {})
349 self.complete_and_wait()
350 result = self.vm.qmp('query-block')
351 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
352 self.vm.shutdown()
353 self.assertTrue(iotests.compare_images(test_img, target_img),
354 'target image does not match source after mirroring')
356 def test_complete_full(self):
357 self.assert_no_active_block_jobs()
359 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
360 target=target_img)
361 self.assert_qmp(result, 'return', {})
363 self.complete_and_wait()
364 result = self.vm.qmp('query-block')
365 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
366 self.vm.shutdown()
367 self.assertTrue(iotests.compare_images(test_img, target_img),
368 'target image does not match source after mirroring')
370 class TestReadErrors(iotests.QMPTestCase):
371 image_len = 2 * 1024 * 1024 # MB
373 # this should be a multiple of twice the default granularity
374 # so that we hit this offset first in state 1
375 MIRROR_GRANULARITY = 1024 * 1024
377 def create_blkdebug_file(self, name, event, errno):
378 file = open(name, 'w')
379 file.write('''
380 [inject-error]
381 state = "1"
382 event = "%s"
383 errno = "%d"
384 immediately = "off"
385 once = "on"
386 sector = "%d"
388 [set-state]
389 state = "1"
390 event = "%s"
391 new_state = "2"
393 [set-state]
394 state = "2"
395 event = "%s"
396 new_state = "1"
397 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
398 file.close()
400 def setUp(self):
401 self.blkdebug_file = backing_img + ".blkdebug"
402 iotests.create_image(backing_img, TestReadErrors.image_len)
403 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
404 qemu_img('create', '-f', iotests.imgfmt,
405 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
406 % (self.blkdebug_file, backing_img),
407 test_img)
408 # Write something for tests that use sync='top'
409 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
410 test_img)
411 self.vm = iotests.VM().add_drive(test_img)
412 self.vm.launch()
414 def tearDown(self):
415 self.vm.shutdown()
416 os.remove(test_img)
417 os.remove(backing_img)
418 os.remove(self.blkdebug_file)
420 def test_report_read(self):
421 self.assert_no_active_block_jobs()
423 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
424 target=target_img)
425 self.assert_qmp(result, 'return', {})
427 completed = False
428 error = False
429 while not completed:
430 for event in self.vm.get_qmp_events(wait=True):
431 if event['event'] == 'BLOCK_JOB_ERROR':
432 self.assert_qmp(event, 'data/device', 'drive0')
433 self.assert_qmp(event, 'data/operation', 'read')
434 error = True
435 elif event['event'] == 'BLOCK_JOB_READY':
436 self.assertTrue(False, 'job completed unexpectedly')
437 elif event['event'] == 'BLOCK_JOB_COMPLETED':
438 self.assertTrue(error, 'job completed unexpectedly')
439 self.assert_qmp(event, 'data/type', 'mirror')
440 self.assert_qmp(event, 'data/device', 'drive0')
441 self.assert_qmp(event, 'data/error', 'Input/output error')
442 completed = True
444 self.assert_no_active_block_jobs()
445 self.vm.shutdown()
447 def test_ignore_read(self):
448 self.assert_no_active_block_jobs()
450 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
451 target=target_img, on_source_error='ignore')
452 self.assert_qmp(result, 'return', {})
454 event = self.vm.get_qmp_event(wait=True)
455 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
456 self.assert_qmp(event, 'data/device', 'drive0')
457 self.assert_qmp(event, 'data/operation', 'read')
458 result = self.vm.qmp('query-block-jobs')
459 self.assert_qmp(result, 'return[0]/paused', False)
460 self.complete_and_wait()
461 self.vm.shutdown()
463 def test_large_cluster(self):
464 self.assert_no_active_block_jobs()
466 # Test COW into the target image. The first half of the
467 # cluster at MIRROR_GRANULARITY has to be copied from
468 # backing_img, even though sync='top'.
469 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
470 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
471 on_source_error='ignore',
472 mode='existing', target=target_img)
473 self.assert_qmp(result, 'return', {})
475 event = self.vm.get_qmp_event(wait=True)
476 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
477 self.assert_qmp(event, 'data/device', 'drive0')
478 self.assert_qmp(event, 'data/operation', 'read')
479 result = self.vm.qmp('query-block-jobs')
480 self.assert_qmp(result, 'return[0]/paused', False)
481 self.complete_and_wait()
482 self.vm.shutdown()
484 # Detach blkdebug to compare images successfully
485 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
486 self.assertTrue(iotests.compare_images(test_img, target_img),
487 'target image does not match source after mirroring')
489 def test_stop_read(self):
490 self.assert_no_active_block_jobs()
492 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
493 target=target_img, on_source_error='stop')
494 self.assert_qmp(result, 'return', {})
496 error = False
497 ready = False
498 while not ready:
499 for event in self.vm.get_qmp_events(wait=True):
500 if event['event'] == 'BLOCK_JOB_ERROR':
501 self.assert_qmp(event, 'data/device', 'drive0')
502 self.assert_qmp(event, 'data/operation', 'read')
504 result = self.vm.qmp('query-block-jobs')
505 self.assert_qmp(result, 'return[0]/paused', True)
506 self.assert_qmp(result, 'return[0]/io-status', 'failed')
508 result = self.vm.qmp('block-job-resume', device='drive0')
509 self.assert_qmp(result, 'return', {})
510 error = True
511 elif event['event'] == 'BLOCK_JOB_READY':
512 self.assertTrue(error, 'job completed unexpectedly')
513 self.assert_qmp(event, 'data/device', 'drive0')
514 ready = True
516 result = self.vm.qmp('query-block-jobs')
517 self.assert_qmp(result, 'return[0]/paused', False)
518 self.assert_qmp(result, 'return[0]/io-status', 'ok')
520 self.complete_and_wait(wait_ready=False)
521 self.assert_no_active_block_jobs()
522 self.vm.shutdown()
524 class TestWriteErrors(iotests.QMPTestCase):
525 image_len = 2 * 1024 * 1024 # MB
527 # this should be a multiple of twice the default granularity
528 # so that we hit this offset first in state 1
529 MIRROR_GRANULARITY = 1024 * 1024
531 def create_blkdebug_file(self, name, event, errno):
532 file = open(name, 'w')
533 file.write('''
534 [inject-error]
535 state = "1"
536 event = "%s"
537 errno = "%d"
538 immediately = "off"
539 once = "on"
540 sector = "%d"
542 [set-state]
543 state = "1"
544 event = "%s"
545 new_state = "2"
547 [set-state]
548 state = "2"
549 event = "%s"
550 new_state = "1"
551 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
552 file.close()
554 def setUp(self):
555 self.blkdebug_file = target_img + ".blkdebug"
556 iotests.create_image(backing_img, TestWriteErrors.image_len)
557 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
558 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
559 self.vm = iotests.VM().add_drive(test_img)
560 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
561 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
562 self.vm.launch()
564 def tearDown(self):
565 self.vm.shutdown()
566 os.remove(test_img)
567 os.remove(backing_img)
568 os.remove(self.blkdebug_file)
570 def test_report_write(self):
571 self.assert_no_active_block_jobs()
573 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
574 mode='existing', target=self.target_img)
575 self.assert_qmp(result, 'return', {})
577 completed = False
578 error = False
579 while not completed:
580 for event in self.vm.get_qmp_events(wait=True):
581 if event['event'] == 'BLOCK_JOB_ERROR':
582 self.assert_qmp(event, 'data/device', 'drive0')
583 self.assert_qmp(event, 'data/operation', 'write')
584 error = True
585 elif event['event'] == 'BLOCK_JOB_READY':
586 self.assertTrue(False, 'job completed unexpectedly')
587 elif event['event'] == 'BLOCK_JOB_COMPLETED':
588 self.assertTrue(error, 'job completed unexpectedly')
589 self.assert_qmp(event, 'data/type', 'mirror')
590 self.assert_qmp(event, 'data/device', 'drive0')
591 self.assert_qmp(event, 'data/error', 'Input/output error')
592 completed = True
594 self.assert_no_active_block_jobs()
595 self.vm.shutdown()
597 def test_ignore_write(self):
598 self.assert_no_active_block_jobs()
600 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
601 mode='existing', target=self.target_img,
602 on_target_error='ignore')
603 self.assert_qmp(result, 'return', {})
605 event = self.vm.get_qmp_event(wait=True)
606 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
607 self.assert_qmp(event, 'data/device', 'drive0')
608 self.assert_qmp(event, 'data/operation', 'write')
609 result = self.vm.qmp('query-block-jobs')
610 self.assert_qmp(result, 'return[0]/paused', False)
611 self.complete_and_wait()
612 self.vm.shutdown()
614 def test_stop_write(self):
615 self.assert_no_active_block_jobs()
617 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
618 mode='existing', target=self.target_img,
619 on_target_error='stop')
620 self.assert_qmp(result, 'return', {})
622 error = False
623 ready = False
624 while not ready:
625 for event in self.vm.get_qmp_events(wait=True):
626 if event['event'] == 'BLOCK_JOB_ERROR':
627 self.assert_qmp(event, 'data/device', 'drive0')
628 self.assert_qmp(event, 'data/operation', 'write')
630 result = self.vm.qmp('query-block-jobs')
631 self.assert_qmp(result, 'return[0]/paused', True)
632 self.assert_qmp(result, 'return[0]/io-status', 'failed')
634 result = self.vm.qmp('block-job-resume', device='drive0')
635 self.assert_qmp(result, 'return', {})
637 result = self.vm.qmp('query-block-jobs')
638 self.assert_qmp(result, 'return[0]/paused', False)
639 self.assert_qmp(result, 'return[0]/io-status', 'ok')
640 error = True
641 elif event['event'] == 'BLOCK_JOB_READY':
642 self.assertTrue(error, 'job completed unexpectedly')
643 self.assert_qmp(event, 'data/device', 'drive0')
644 ready = True
646 self.complete_and_wait(wait_ready=False)
647 self.assert_no_active_block_jobs()
648 self.vm.shutdown()
650 class TestSetSpeed(iotests.QMPTestCase):
651 image_len = 80 * 1024 * 1024 # MB
653 def setUp(self):
654 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
655 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
656 self.vm = iotests.VM().add_drive(test_img)
657 self.vm.launch()
659 def tearDown(self):
660 self.vm.shutdown()
661 os.remove(test_img)
662 os.remove(backing_img)
663 os.remove(target_img)
665 def test_set_speed(self):
666 self.assert_no_active_block_jobs()
668 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
669 target=target_img)
670 self.assert_qmp(result, 'return', {})
672 # Default speed is 0
673 result = self.vm.qmp('query-block-jobs')
674 self.assert_qmp(result, 'return[0]/device', 'drive0')
675 self.assert_qmp(result, 'return[0]/speed', 0)
677 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
678 self.assert_qmp(result, 'return', {})
680 # Ensure the speed we set was accepted
681 result = self.vm.qmp('query-block-jobs')
682 self.assert_qmp(result, 'return[0]/device', 'drive0')
683 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
685 self.wait_ready_and_cancel()
687 # Check setting speed in drive-mirror works
688 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
689 target=target_img, speed=4*1024*1024)
690 self.assert_qmp(result, 'return', {})
692 result = self.vm.qmp('query-block-jobs')
693 self.assert_qmp(result, 'return[0]/device', 'drive0')
694 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
696 self.wait_ready_and_cancel()
698 def test_set_speed_invalid(self):
699 self.assert_no_active_block_jobs()
701 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
702 target=target_img, speed=-1)
703 self.assert_qmp(result, 'error/class', 'GenericError')
705 self.assert_no_active_block_jobs()
707 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
708 target=target_img)
709 self.assert_qmp(result, 'return', {})
711 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
712 self.assert_qmp(result, 'error/class', 'GenericError')
714 self.wait_ready_and_cancel()
716 class TestUnbackedSource(iotests.QMPTestCase):
717 image_len = 2 * 1024 * 1024 # MB
719 def setUp(self):
720 qemu_img('create', '-f', iotests.imgfmt, test_img,
721 str(TestUnbackedSource.image_len))
722 self.vm = iotests.VM().add_drive(test_img)
723 self.vm.launch()
725 def tearDown(self):
726 self.vm.shutdown()
727 os.remove(test_img)
728 os.remove(target_img)
730 def test_absolute_paths_full(self):
731 self.assert_no_active_block_jobs()
732 result = self.vm.qmp('drive-mirror', device='drive0',
733 sync='full', target=target_img,
734 mode='absolute-paths')
735 self.assert_qmp(result, 'return', {})
736 self.complete_and_wait()
737 self.assert_no_active_block_jobs()
739 def test_absolute_paths_top(self):
740 self.assert_no_active_block_jobs()
741 result = self.vm.qmp('drive-mirror', device='drive0',
742 sync='top', target=target_img,
743 mode='absolute-paths')
744 self.assert_qmp(result, 'return', {})
745 self.complete_and_wait()
746 self.assert_no_active_block_jobs()
748 def test_absolute_paths_none(self):
749 self.assert_no_active_block_jobs()
750 result = self.vm.qmp('drive-mirror', device='drive0',
751 sync='none', target=target_img,
752 mode='absolute-paths')
753 self.assert_qmp(result, 'return', {})
754 self.complete_and_wait()
755 self.assert_no_active_block_jobs()
757 class TestRepairQuorum(iotests.QMPTestCase):
758 """ This class test quorum file repair using drive-mirror.
759 It's mostly a fork of TestSingleDrive """
760 image_len = 1 * 1024 * 1024 # MB
761 IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
763 def has_quorum(self):
764 return 'quorum' in iotests.qemu_img_pipe('--help')
766 def setUp(self):
767 self.vm = iotests.VM()
769 if iotests.qemu_default_machine == 'pc':
770 self.vm.add_drive(None, 'media=cdrom', 'ide')
772 # Add each individual quorum images
773 for i in self.IMAGES:
774 qemu_img('create', '-f', iotests.imgfmt, i,
775 str(TestSingleDrive.image_len))
776 # Assign a node name to each quorum image in order to manipulate
777 # them
778 opts = "node-name=img%i" % self.IMAGES.index(i)
779 self.vm = self.vm.add_drive(i, opts)
781 self.vm.launch()
783 #assemble the quorum block device from the individual files
784 args = { "options" : { "driver": "quorum", "id": "quorum0",
785 "vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
786 if self.has_quorum():
787 result = self.vm.qmp("blockdev-add", **args)
788 self.assert_qmp(result, 'return', {})
791 def tearDown(self):
792 self.vm.shutdown()
793 for i in self.IMAGES + [ quorum_repair_img ]:
794 # Do a try/except because the test may have deleted some images
795 try:
796 os.remove(i)
797 except OSError:
798 pass
800 def test_complete(self):
801 if not self.has_quorum():
802 return
804 self.assert_no_active_block_jobs()
806 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
807 node_name="repair0",
808 replaces="img1",
809 target=quorum_repair_img, format=iotests.imgfmt)
810 self.assert_qmp(result, 'return', {})
812 self.complete_and_wait(drive="quorum0")
813 result = self.vm.qmp('query-named-block-nodes')
814 self.assert_qmp(result, 'return[0]/file', 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 result = self.vm.qmp('query-named-block-nodes')
837 self.assert_qmp(result, 'return[1]/file', quorum_img3)
838 self.vm.shutdown()
840 def test_cancel_after_ready(self):
841 if not self.has_quorum():
842 return
844 self.assert_no_active_block_jobs()
846 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
847 node_name="repair0",
848 replaces="img1",
849 target=quorum_repair_img, format=iotests.imgfmt)
850 self.assert_qmp(result, 'return', {})
852 self.wait_ready_and_cancel(drive="quorum0")
853 result = self.vm.qmp('query-named-block-nodes')
854 # here we check that the last registered quorum file has not been
855 # swapped out and unref
856 self.assert_qmp(result, 'return[1]/file', quorum_img3)
857 self.vm.shutdown()
858 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
859 'target image does not match source after mirroring')
861 def test_pause(self):
862 if not self.has_quorum():
863 return
865 self.assert_no_active_block_jobs()
867 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
868 node_name="repair0",
869 replaces="img1",
870 target=quorum_repair_img, format=iotests.imgfmt)
871 self.assert_qmp(result, 'return', {})
873 result = self.vm.qmp('block-job-pause', device='quorum0')
874 self.assert_qmp(result, 'return', {})
876 time.sleep(1)
877 result = self.vm.qmp('query-block-jobs')
878 offset = self.dictpath(result, 'return[0]/offset')
880 time.sleep(1)
881 result = self.vm.qmp('query-block-jobs')
882 self.assert_qmp(result, 'return[0]/offset', offset)
884 result = self.vm.qmp('block-job-resume', device='quorum0')
885 self.assert_qmp(result, 'return', {})
887 self.complete_and_wait(drive="quorum0")
888 self.vm.shutdown()
889 self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
890 'target image does not match source after mirroring')
892 def test_medium_not_found(self):
893 if not self.has_quorum():
894 return
896 if iotests.qemu_default_machine != 'pc':
897 return
899 result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM
900 sync='full',
901 node_name='repair0',
902 replaces='img1',
903 target=quorum_repair_img, format=iotests.imgfmt)
904 self.assert_qmp(result, 'error/class', 'GenericError')
906 def test_image_not_found(self):
907 if not self.has_quorum():
908 return
910 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
911 node_name='repair0',
912 replaces='img1',
913 mode='existing',
914 target=quorum_repair_img, format=iotests.imgfmt)
915 self.assert_qmp(result, 'error/class', 'GenericError')
917 def test_device_not_found(self):
918 if not self.has_quorum():
919 return
921 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
922 node_name='repair0',
923 replaces='img1',
924 target=quorum_repair_img, format=iotests.imgfmt)
925 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
927 def test_wrong_sync_mode(self):
928 if not self.has_quorum():
929 return
931 result = self.vm.qmp('drive-mirror', device='quorum0',
932 node_name='repair0',
933 replaces='img1',
934 target=quorum_repair_img, format=iotests.imgfmt)
935 self.assert_qmp(result, 'error/class', 'GenericError')
937 def test_no_node_name(self):
938 if not self.has_quorum():
939 return
941 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
942 replaces='img1',
943 target=quorum_repair_img, format=iotests.imgfmt)
944 self.assert_qmp(result, 'error/class', 'GenericError')
946 def test_nonexistent_replaces(self):
947 if not self.has_quorum():
948 return
950 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
951 node_name='repair0',
952 replaces='img77',
953 target=quorum_repair_img, format=iotests.imgfmt)
954 self.assert_qmp(result, 'error/class', 'GenericError')
956 def test_after_a_quorum_snapshot(self):
957 if not self.has_quorum():
958 return
960 result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
961 snapshot_file=quorum_snapshot_file,
962 snapshot_node_name="snap1");
964 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
965 node_name='repair0',
966 replaces="img1",
967 target=quorum_repair_img, format=iotests.imgfmt)
968 self.assert_qmp(result, 'error/class', 'GenericError')
970 result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
971 node_name='repair0',
972 replaces="snap1",
973 target=quorum_repair_img, format=iotests.imgfmt)
974 self.assert_qmp(result, 'return', {})
976 self.complete_and_wait(drive="quorum0")
977 result = self.vm.qmp('query-named-block-nodes')
978 self.assert_qmp(result, 'return[0]/file', quorum_repair_img)
979 # TODO: a better test requiring some QEMU infrastructure will be added
980 # to check that this file is really driven by quorum
981 self.vm.shutdown()
983 if __name__ == '__main__':
984 iotests.main(supported_fmts=['qcow2', 'qed'])