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