]> git.proxmox.com Git - qemu.git/blob - tests/qemu-iotests/041
mirror: add buf-size argument to drive-mirror
[qemu.git] / tests / qemu-iotests / 041
1 #!/usr/bin/env python
2 #
3 # Tests for image mirroring.
4 #
5 # Copyright (C) 2012 Red Hat, Inc.
6 #
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.
11 #
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.
16 #
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/>.
19 #
20
21 import time
22 import os
23 import iotests
24 from iotests import qemu_img, qemu_io
25 import struct
26
27 backing_img = os.path.join(iotests.test_dir, 'backing.img')
28 target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
29 test_img = os.path.join(iotests.test_dir, 'test.img')
30 target_img = os.path.join(iotests.test_dir, 'target.img')
31
32 class ImageMirroringTestCase(iotests.QMPTestCase):
33 '''Abstract base class for image mirroring test cases'''
34
35 def assert_no_active_mirrors(self):
36 result = self.vm.qmp('query-block-jobs')
37 self.assert_qmp(result, 'return', [])
38
39 def cancel_and_wait(self, drive='drive0', wait_ready=True):
40 '''Cancel a block job and wait for it to finish'''
41 if wait_ready:
42 ready = False
43 while not ready:
44 for event in self.vm.get_qmp_events(wait=True):
45 if event['event'] == 'BLOCK_JOB_READY':
46 self.assert_qmp(event, 'data/type', 'mirror')
47 self.assert_qmp(event, 'data/device', drive)
48 ready = True
49
50 result = self.vm.qmp('block-job-cancel', device=drive,
51 force=not wait_ready)
52 self.assert_qmp(result, 'return', {})
53
54 cancelled = False
55 while not cancelled:
56 for event in self.vm.get_qmp_events(wait=True):
57 if event['event'] == 'BLOCK_JOB_COMPLETED' or \
58 event['event'] == 'BLOCK_JOB_CANCELLED':
59 self.assert_qmp(event, 'data/type', 'mirror')
60 self.assert_qmp(event, 'data/device', drive)
61 if wait_ready:
62 self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
63 self.assert_qmp(event, 'data/offset', self.image_len)
64 self.assert_qmp(event, 'data/len', self.image_len)
65 cancelled = True
66
67 self.assert_no_active_mirrors()
68
69 def complete_and_wait(self, drive='drive0', wait_ready=True):
70 '''Complete a block job and wait for it to finish'''
71 if wait_ready:
72 ready = False
73 while not ready:
74 for event in self.vm.get_qmp_events(wait=True):
75 if event['event'] == 'BLOCK_JOB_READY':
76 self.assert_qmp(event, 'data/type', 'mirror')
77 self.assert_qmp(event, 'data/device', drive)
78 ready = True
79
80 result = self.vm.qmp('block-job-complete', device=drive)
81 self.assert_qmp(result, 'return', {})
82
83 completed = False
84 while not completed:
85 for event in self.vm.get_qmp_events(wait=True):
86 if event['event'] == 'BLOCK_JOB_COMPLETED':
87 self.assert_qmp(event, 'data/type', 'mirror')
88 self.assert_qmp(event, 'data/device', drive)
89 self.assert_qmp_absent(event, 'data/error')
90 self.assert_qmp(event, 'data/offset', self.image_len)
91 self.assert_qmp(event, 'data/len', self.image_len)
92 completed = True
93
94 self.assert_no_active_mirrors()
95
96 def create_image(self, name, size):
97 file = open(name, 'w')
98 i = 0
99 while i < size:
100 sector = struct.pack('>l504xl', i / 512, i / 512)
101 file.write(sector)
102 i = i + 512
103 file.close()
104
105 def compare_images(self, img1, img2):
106 try:
107 qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img1, img1 + '.raw')
108 qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img2, img2 + '.raw')
109 file1 = open(img1 + '.raw', 'r')
110 file2 = open(img2 + '.raw', 'r')
111 return file1.read() == file2.read()
112 finally:
113 if file1 is not None:
114 file1.close()
115 if file2 is not None:
116 file2.close()
117 try:
118 os.remove(img1 + '.raw')
119 except OSError:
120 pass
121 try:
122 os.remove(img2 + '.raw')
123 except OSError:
124 pass
125
126 class TestSingleDrive(ImageMirroringTestCase):
127 image_len = 1 * 1024 * 1024 # MB
128
129 def setUp(self):
130 self.create_image(backing_img, TestSingleDrive.image_len)
131 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
132 self.vm = iotests.VM().add_drive(test_img)
133 self.vm.launch()
134
135 def tearDown(self):
136 self.vm.shutdown()
137 os.remove(test_img)
138 os.remove(backing_img)
139 try:
140 os.remove(target_img)
141 except OSError:
142 pass
143
144 def test_complete(self):
145 self.assert_no_active_mirrors()
146
147 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
148 target=target_img)
149 self.assert_qmp(result, 'return', {})
150
151 self.complete_and_wait()
152 result = self.vm.qmp('query-block')
153 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
154 self.vm.shutdown()
155 self.assertTrue(self.compare_images(test_img, target_img),
156 'target image does not match source after mirroring')
157
158 def test_cancel(self):
159 self.assert_no_active_mirrors()
160
161 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
162 target=target_img)
163 self.assert_qmp(result, 'return', {})
164
165 self.cancel_and_wait(wait_ready=False)
166 result = self.vm.qmp('query-block')
167 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
168 self.vm.shutdown()
169
170 def test_cancel_after_ready(self):
171 self.assert_no_active_mirrors()
172
173 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
174 target=target_img)
175 self.assert_qmp(result, 'return', {})
176
177 self.cancel_and_wait()
178 result = self.vm.qmp('query-block')
179 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
180 self.vm.shutdown()
181 self.assertTrue(self.compare_images(test_img, target_img),
182 'target image does not match source after mirroring')
183
184 def test_pause(self):
185 self.assert_no_active_mirrors()
186
187 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
188 target=target_img)
189 self.assert_qmp(result, 'return', {})
190
191 result = self.vm.qmp('block-job-pause', device='drive0')
192 self.assert_qmp(result, 'return', {})
193
194 time.sleep(1)
195 result = self.vm.qmp('query-block-jobs')
196 offset = self.dictpath(result, 'return[0]/offset')
197
198 time.sleep(1)
199 result = self.vm.qmp('query-block-jobs')
200 self.assert_qmp(result, 'return[0]/offset', offset)
201
202 result = self.vm.qmp('block-job-resume', device='drive0')
203 self.assert_qmp(result, 'return', {})
204
205 self.complete_and_wait()
206 self.vm.shutdown()
207 self.assertTrue(self.compare_images(test_img, target_img),
208 'target image does not match source after mirroring')
209
210 def test_small_buffer(self):
211 self.assert_no_active_mirrors()
212
213 # A small buffer is rounded up automatically
214 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
215 buf_size=4096, target=target_img)
216 self.assert_qmp(result, 'return', {})
217
218 self.complete_and_wait()
219 result = self.vm.qmp('query-block')
220 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
221 self.vm.shutdown()
222 self.assertTrue(self.compare_images(test_img, target_img),
223 'target image does not match source after mirroring')
224
225 def test_small_buffer2(self):
226 self.assert_no_active_mirrors()
227
228 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
229 % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img)
230 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
231 buf_size=65536, mode='existing', target=target_img)
232 self.assert_qmp(result, 'return', {})
233
234 self.complete_and_wait()
235 result = self.vm.qmp('query-block')
236 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
237 self.vm.shutdown()
238 self.assertTrue(self.compare_images(test_img, target_img),
239 'target image does not match source after mirroring')
240
241 def test_large_cluster(self):
242 self.assert_no_active_mirrors()
243
244 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
245 % (TestSingleDrive.image_len, backing_img), target_img)
246 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
247 mode='existing', target=target_img)
248 self.assert_qmp(result, 'return', {})
249
250 self.complete_and_wait()
251 result = self.vm.qmp('query-block')
252 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
253 self.vm.shutdown()
254 self.assertTrue(self.compare_images(test_img, target_img),
255 'target image does not match source after mirroring')
256
257 def test_medium_not_found(self):
258 result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
259 target=target_img)
260 self.assert_qmp(result, 'error/class', 'GenericError')
261
262 def test_image_not_found(self):
263 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
264 mode='existing', target=target_img)
265 self.assert_qmp(result, 'error/class', 'GenericError')
266
267 def test_device_not_found(self):
268 result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
269 target=target_img)
270 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
271
272 class TestMirrorNoBacking(ImageMirroringTestCase):
273 image_len = 2 * 1024 * 1024 # MB
274
275 def complete_and_wait(self, drive='drive0', wait_ready=True):
276 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
277 return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
278
279 def compare_images(self, img1, img2):
280 self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
281 return ImageMirroringTestCase.compare_images(self, img1, img2)
282
283 def setUp(self):
284 self.create_image(backing_img, TestMirrorNoBacking.image_len)
285 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
286 self.vm = iotests.VM().add_drive(test_img)
287 self.vm.launch()
288
289 def tearDown(self):
290 self.vm.shutdown()
291 os.remove(test_img)
292 os.remove(backing_img)
293 os.remove(target_backing_img)
294 os.remove(target_img)
295
296 def test_complete(self):
297 self.assert_no_active_mirrors()
298
299 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
300 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
301 mode='existing', target=target_img)
302 self.assert_qmp(result, 'return', {})
303
304 self.complete_and_wait()
305 result = self.vm.qmp('query-block')
306 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
307 self.vm.shutdown()
308 self.assertTrue(self.compare_images(test_img, target_img),
309 'target image does not match source after mirroring')
310
311 def test_cancel(self):
312 self.assert_no_active_mirrors()
313
314 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
315 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
316 mode='existing', target=target_img)
317 self.assert_qmp(result, 'return', {})
318
319 self.cancel_and_wait()
320 result = self.vm.qmp('query-block')
321 self.assert_qmp(result, 'return[0]/inserted/file', test_img)
322 self.vm.shutdown()
323 self.assertTrue(self.compare_images(test_img, target_img),
324 'target image does not match source after mirroring')
325
326 def test_large_cluster(self):
327 self.assert_no_active_mirrors()
328
329 # qemu-img create fails if the image is not there
330 qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
331 %(TestMirrorNoBacking.image_len), target_backing_img)
332 qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
333 % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
334 os.remove(target_backing_img)
335
336 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
337 mode='existing', target=target_img)
338 self.assert_qmp(result, 'return', {})
339
340 self.complete_and_wait()
341 result = self.vm.qmp('query-block')
342 self.assert_qmp(result, 'return[0]/inserted/file', target_img)
343 self.vm.shutdown()
344 self.assertTrue(self.compare_images(test_img, target_img),
345 'target image does not match source after mirroring')
346
347 class TestReadErrors(ImageMirroringTestCase):
348 image_len = 2 * 1024 * 1024 # MB
349
350 # this should be a multiple of twice the default granularity
351 # so that we hit this offset first in state 1
352 MIRROR_GRANULARITY = 1024 * 1024
353
354 def create_blkdebug_file(self, name, event, errno):
355 file = open(name, 'w')
356 file.write('''
357 [inject-error]
358 state = "1"
359 event = "%s"
360 errno = "%d"
361 immediately = "off"
362 once = "on"
363 sector = "%d"
364
365 [set-state]
366 state = "1"
367 event = "%s"
368 new_state = "2"
369
370 [set-state]
371 state = "2"
372 event = "%s"
373 new_state = "1"
374 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
375 file.close()
376
377 def setUp(self):
378 self.blkdebug_file = backing_img + ".blkdebug"
379 self.create_image(backing_img, TestReadErrors.image_len)
380 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
381 qemu_img('create', '-f', iotests.imgfmt,
382 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
383 % (self.blkdebug_file, backing_img),
384 test_img)
385 # Write something for tests that use sync='top'
386 qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
387 test_img)
388 self.vm = iotests.VM().add_drive(test_img)
389 self.vm.launch()
390
391 def tearDown(self):
392 self.vm.shutdown()
393 os.remove(test_img)
394 os.remove(backing_img)
395 os.remove(self.blkdebug_file)
396
397 def test_report_read(self):
398 self.assert_no_active_mirrors()
399
400 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
401 target=target_img)
402 self.assert_qmp(result, 'return', {})
403
404 completed = False
405 error = False
406 while not completed:
407 for event in self.vm.get_qmp_events(wait=True):
408 if event['event'] == 'BLOCK_JOB_ERROR':
409 self.assert_qmp(event, 'data/device', 'drive0')
410 self.assert_qmp(event, 'data/operation', 'read')
411 error = True
412 elif event['event'] == 'BLOCK_JOB_READY':
413 self.assertTrue(False, 'job completed unexpectedly')
414 elif event['event'] == 'BLOCK_JOB_COMPLETED':
415 self.assertTrue(error, 'job completed unexpectedly')
416 self.assert_qmp(event, 'data/type', 'mirror')
417 self.assert_qmp(event, 'data/device', 'drive0')
418 self.assert_qmp(event, 'data/error', 'Input/output error')
419 self.assert_qmp(event, 'data/len', self.image_len)
420 completed = True
421
422 self.assert_no_active_mirrors()
423 self.vm.shutdown()
424
425 def test_ignore_read(self):
426 self.assert_no_active_mirrors()
427
428 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
429 target=target_img, on_source_error='ignore')
430 self.assert_qmp(result, 'return', {})
431
432 event = self.vm.get_qmp_event(wait=True)
433 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
434 self.assert_qmp(event, 'data/device', 'drive0')
435 self.assert_qmp(event, 'data/operation', 'read')
436 result = self.vm.qmp('query-block-jobs')
437 self.assert_qmp(result, 'return[0]/paused', False)
438 self.complete_and_wait()
439 self.vm.shutdown()
440
441 def test_large_cluster(self):
442 self.assert_no_active_mirrors()
443
444 # Test COW into the target image. The first half of the
445 # cluster at MIRROR_GRANULARITY has to be copied from
446 # backing_img, even though sync='top'.
447 qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
448 result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
449 on_source_error='ignore',
450 mode='existing', target=target_img)
451 self.assert_qmp(result, 'return', {})
452
453 event = self.vm.get_qmp_event(wait=True)
454 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
455 self.assert_qmp(event, 'data/device', 'drive0')
456 self.assert_qmp(event, 'data/operation', 'read')
457 result = self.vm.qmp('query-block-jobs')
458 self.assert_qmp(result, 'return[0]/paused', False)
459 self.complete_and_wait()
460 self.vm.shutdown()
461
462 # Detach blkdebug to compare images successfully
463 qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
464 self.assertTrue(self.compare_images(test_img, target_img),
465 'target image does not match source after mirroring')
466
467 def test_stop_read(self):
468 self.assert_no_active_mirrors()
469
470 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
471 target=target_img, on_source_error='stop')
472 self.assert_qmp(result, 'return', {})
473
474 error = False
475 ready = False
476 while not ready:
477 for event in self.vm.get_qmp_events(wait=True):
478 if event['event'] == 'BLOCK_JOB_ERROR':
479 self.assert_qmp(event, 'data/device', 'drive0')
480 self.assert_qmp(event, 'data/operation', 'read')
481
482 result = self.vm.qmp('query-block-jobs')
483 self.assert_qmp(result, 'return[0]/paused', True)
484 self.assert_qmp(result, 'return[0]/io-status', 'failed')
485
486 result = self.vm.qmp('block-job-resume', device='drive0')
487 self.assert_qmp(result, 'return', {})
488 error = True
489 elif event['event'] == 'BLOCK_JOB_READY':
490 self.assertTrue(error, 'job completed unexpectedly')
491 self.assert_qmp(event, 'data/device', 'drive0')
492 ready = True
493
494 result = self.vm.qmp('query-block-jobs')
495 self.assert_qmp(result, 'return[0]/paused', False)
496 self.assert_qmp(result, 'return[0]/io-status', 'ok')
497
498 self.complete_and_wait(wait_ready=False)
499 self.assert_no_active_mirrors()
500 self.vm.shutdown()
501
502 class TestWriteErrors(ImageMirroringTestCase):
503 image_len = 2 * 1024 * 1024 # MB
504
505 # this should be a multiple of twice the default granularity
506 # so that we hit this offset first in state 1
507 MIRROR_GRANULARITY = 1024 * 1024
508
509 def create_blkdebug_file(self, name, event, errno):
510 file = open(name, 'w')
511 file.write('''
512 [inject-error]
513 state = "1"
514 event = "%s"
515 errno = "%d"
516 immediately = "off"
517 once = "on"
518 sector = "%d"
519
520 [set-state]
521 state = "1"
522 event = "%s"
523 new_state = "2"
524
525 [set-state]
526 state = "2"
527 event = "%s"
528 new_state = "1"
529 ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event))
530 file.close()
531
532 def setUp(self):
533 self.blkdebug_file = target_img + ".blkdebug"
534 self.create_image(backing_img, TestWriteErrors.image_len)
535 self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
536 qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
537 self.vm = iotests.VM().add_drive(test_img)
538 self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img)
539 qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img)
540 self.vm.launch()
541
542 def tearDown(self):
543 self.vm.shutdown()
544 os.remove(test_img)
545 os.remove(backing_img)
546 os.remove(self.blkdebug_file)
547
548 def test_report_write(self):
549 self.assert_no_active_mirrors()
550
551 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
552 mode='existing', target=self.target_img)
553 self.assert_qmp(result, 'return', {})
554
555 completed = False
556 error = False
557 while not completed:
558 for event in self.vm.get_qmp_events(wait=True):
559 if event['event'] == 'BLOCK_JOB_ERROR':
560 self.assert_qmp(event, 'data/device', 'drive0')
561 self.assert_qmp(event, 'data/operation', 'write')
562 error = True
563 elif event['event'] == 'BLOCK_JOB_READY':
564 self.assertTrue(False, 'job completed unexpectedly')
565 elif event['event'] == 'BLOCK_JOB_COMPLETED':
566 self.assertTrue(error, 'job completed unexpectedly')
567 self.assert_qmp(event, 'data/type', 'mirror')
568 self.assert_qmp(event, 'data/device', 'drive0')
569 self.assert_qmp(event, 'data/error', 'Input/output error')
570 self.assert_qmp(event, 'data/len', self.image_len)
571 completed = True
572
573 self.assert_no_active_mirrors()
574 self.vm.shutdown()
575
576 def test_ignore_write(self):
577 self.assert_no_active_mirrors()
578
579 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
580 mode='existing', target=self.target_img,
581 on_target_error='ignore')
582 self.assert_qmp(result, 'return', {})
583
584 event = self.vm.get_qmp_event(wait=True)
585 self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
586 self.assert_qmp(event, 'data/device', 'drive0')
587 self.assert_qmp(event, 'data/operation', 'write')
588 result = self.vm.qmp('query-block-jobs')
589 self.assert_qmp(result, 'return[0]/paused', False)
590 self.complete_and_wait()
591 self.vm.shutdown()
592
593 def test_stop_write(self):
594 self.assert_no_active_mirrors()
595
596 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
597 mode='existing', target=self.target_img,
598 on_target_error='stop')
599 self.assert_qmp(result, 'return', {})
600
601 error = False
602 ready = False
603 while not ready:
604 for event in self.vm.get_qmp_events(wait=True):
605 if event['event'] == 'BLOCK_JOB_ERROR':
606 self.assert_qmp(event, 'data/device', 'drive0')
607 self.assert_qmp(event, 'data/operation', 'write')
608
609 result = self.vm.qmp('query-block-jobs')
610 self.assert_qmp(result, 'return[0]/paused', True)
611 self.assert_qmp(result, 'return[0]/io-status', 'failed')
612
613 result = self.vm.qmp('block-job-resume', device='drive0')
614 self.assert_qmp(result, 'return', {})
615
616 result = self.vm.qmp('query-block-jobs')
617 self.assert_qmp(result, 'return[0]/paused', False)
618 self.assert_qmp(result, 'return[0]/io-status', 'ok')
619 error = True
620 elif event['event'] == 'BLOCK_JOB_READY':
621 self.assertTrue(error, 'job completed unexpectedly')
622 self.assert_qmp(event, 'data/device', 'drive0')
623 ready = True
624
625 self.complete_and_wait(wait_ready=False)
626 self.assert_no_active_mirrors()
627 self.vm.shutdown()
628
629 class TestSetSpeed(ImageMirroringTestCase):
630 image_len = 80 * 1024 * 1024 # MB
631
632 def setUp(self):
633 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
634 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
635 self.vm = iotests.VM().add_drive(test_img)
636 self.vm.launch()
637
638 def tearDown(self):
639 self.vm.shutdown()
640 os.remove(test_img)
641 os.remove(backing_img)
642 os.remove(target_img)
643
644 def test_set_speed(self):
645 self.assert_no_active_mirrors()
646
647 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
648 target=target_img)
649 self.assert_qmp(result, 'return', {})
650
651 # Default speed is 0
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', 0)
655
656 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
657 self.assert_qmp(result, 'return', {})
658
659 # Ensure the speed we set was accepted
660 result = self.vm.qmp('query-block-jobs')
661 self.assert_qmp(result, 'return[0]/device', 'drive0')
662 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
663
664 self.cancel_and_wait()
665
666 # Check setting speed in drive-mirror works
667 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
668 target=target_img, speed=4*1024*1024)
669 self.assert_qmp(result, 'return', {})
670
671 result = self.vm.qmp('query-block-jobs')
672 self.assert_qmp(result, 'return[0]/device', 'drive0')
673 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
674
675 self.cancel_and_wait()
676
677 def test_set_speed_invalid(self):
678 self.assert_no_active_mirrors()
679
680 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
681 target=target_img, speed=-1)
682 self.assert_qmp(result, 'error/class', 'GenericError')
683
684 self.assert_no_active_mirrors()
685
686 result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
687 target=target_img)
688 self.assert_qmp(result, 'return', {})
689
690 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
691 self.assert_qmp(result, 'error/class', 'GenericError')
692
693 self.cancel_and_wait()
694
695 if __name__ == '__main__':
696 iotests.main(supported_fmts=['qcow2', 'qed'])