qemu-iotests: make create_image() common
[qemu/ar7.git] / tests / qemu-iotests / 030
blobae56f3b8087fde592b3565726475fd1c996e032b
1 #!/usr/bin/env python
3 # Tests for image streaming.
5 # Copyright (C) 2012 IBM Corp.
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 mid_img = os.path.join(iotests.test_dir, 'mid.img')
28 test_img = os.path.join(iotests.test_dir, 'test.img')
30 class TestSingleDrive(iotests.QMPTestCase):
31 image_len = 1 * 1024 * 1024 # MB
33 def setUp(self):
34 iotests.create_image(backing_img, TestSingleDrive.image_len)
35 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
36 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
37 self.vm = iotests.VM().add_drive(test_img)
38 self.vm.launch()
40 def tearDown(self):
41 self.vm.shutdown()
42 os.remove(test_img)
43 os.remove(mid_img)
44 os.remove(backing_img)
46 def test_stream(self):
47 self.assert_no_active_block_jobs()
49 result = self.vm.qmp('block-stream', device='drive0')
50 self.assert_qmp(result, 'return', {})
52 completed = False
53 while not completed:
54 for event in self.vm.get_qmp_events(wait=True):
55 if event['event'] == 'BLOCK_JOB_COMPLETED':
56 self.assert_qmp(event, 'data/type', 'stream')
57 self.assert_qmp(event, 'data/device', 'drive0')
58 self.assert_qmp(event, 'data/offset', self.image_len)
59 self.assert_qmp(event, 'data/len', self.image_len)
60 completed = True
62 self.assert_no_active_block_jobs()
63 self.vm.shutdown()
65 self.assertEqual(qemu_io('-c', 'map', backing_img),
66 qemu_io('-c', 'map', test_img),
67 'image file map does not match backing file after streaming')
69 def test_stream_pause(self):
70 self.assert_no_active_block_jobs()
72 result = self.vm.qmp('block-stream', device='drive0')
73 self.assert_qmp(result, 'return', {})
75 result = self.vm.qmp('block-job-pause', device='drive0')
76 self.assert_qmp(result, 'return', {})
78 time.sleep(1)
79 result = self.vm.qmp('query-block-jobs')
80 offset = self.dictpath(result, 'return[0]/offset')
82 time.sleep(1)
83 result = self.vm.qmp('query-block-jobs')
84 self.assert_qmp(result, 'return[0]/offset', offset)
86 result = self.vm.qmp('block-job-resume', device='drive0')
87 self.assert_qmp(result, 'return', {})
89 completed = False
90 while not completed:
91 for event in self.vm.get_qmp_events(wait=True):
92 if event['event'] == 'BLOCK_JOB_COMPLETED':
93 self.assert_qmp(event, 'data/type', 'stream')
94 self.assert_qmp(event, 'data/device', 'drive0')
95 self.assert_qmp(event, 'data/offset', self.image_len)
96 self.assert_qmp(event, 'data/len', self.image_len)
97 completed = True
99 self.assert_no_active_block_jobs()
100 self.vm.shutdown()
102 self.assertEqual(qemu_io('-c', 'map', backing_img),
103 qemu_io('-c', 'map', test_img),
104 'image file map does not match backing file after streaming')
106 def test_stream_partial(self):
107 self.assert_no_active_block_jobs()
109 result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
110 self.assert_qmp(result, 'return', {})
112 completed = False
113 while not completed:
114 for event in self.vm.get_qmp_events(wait=True):
115 if event['event'] == 'BLOCK_JOB_COMPLETED':
116 self.assert_qmp(event, 'data/type', 'stream')
117 self.assert_qmp(event, 'data/device', 'drive0')
118 self.assert_qmp(event, 'data/offset', self.image_len)
119 self.assert_qmp(event, 'data/len', self.image_len)
120 completed = True
122 self.assert_no_active_block_jobs()
123 self.vm.shutdown()
125 self.assertEqual(qemu_io('-c', 'map', mid_img),
126 qemu_io('-c', 'map', test_img),
127 'image file map does not match backing file after streaming')
129 def test_device_not_found(self):
130 result = self.vm.qmp('block-stream', device='nonexistent')
131 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
134 class TestSmallerBackingFile(iotests.QMPTestCase):
135 backing_len = 1 * 1024 * 1024 # MB
136 image_len = 2 * backing_len
138 def setUp(self):
139 iotests.create_image(backing_img, self.backing_len)
140 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len))
141 self.vm = iotests.VM().add_drive(test_img)
142 self.vm.launch()
144 # If this hangs, then you are missing a fix to complete streaming when the
145 # end of the backing file is reached.
146 def test_stream(self):
147 self.assert_no_active_block_jobs()
149 result = self.vm.qmp('block-stream', device='drive0')
150 self.assert_qmp(result, 'return', {})
152 completed = False
153 while not completed:
154 for event in self.vm.get_qmp_events(wait=True):
155 if event['event'] == 'BLOCK_JOB_COMPLETED':
156 self.assert_qmp(event, 'data/type', 'stream')
157 self.assert_qmp(event, 'data/device', 'drive0')
158 self.assert_qmp(event, 'data/offset', self.image_len)
159 self.assert_qmp(event, 'data/len', self.image_len)
160 completed = True
162 self.assert_no_active_block_jobs()
163 self.vm.shutdown()
165 class TestErrors(iotests.QMPTestCase):
166 image_len = 2 * 1024 * 1024 # MB
168 # this should match STREAM_BUFFER_SIZE/512 in block/stream.c
169 STREAM_BUFFER_SIZE = 512 * 1024
171 def create_blkdebug_file(self, name, event, errno):
172 file = open(name, 'w')
173 file.write('''
174 [inject-error]
175 state = "1"
176 event = "%s"
177 errno = "%d"
178 immediately = "off"
179 once = "on"
180 sector = "%d"
182 [set-state]
183 state = "1"
184 event = "%s"
185 new_state = "2"
187 [set-state]
188 state = "2"
189 event = "%s"
190 new_state = "1"
191 ''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event))
192 file.close()
194 class TestEIO(TestErrors):
195 def setUp(self):
196 self.blkdebug_file = backing_img + ".blkdebug"
197 iotests.create_image(backing_img, TestErrors.image_len)
198 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
199 qemu_img('create', '-f', iotests.imgfmt,
200 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
201 % (self.blkdebug_file, backing_img),
202 test_img)
203 self.vm = iotests.VM().add_drive(test_img)
204 self.vm.launch()
206 def tearDown(self):
207 self.vm.shutdown()
208 os.remove(test_img)
209 os.remove(backing_img)
210 os.remove(self.blkdebug_file)
212 def test_report(self):
213 self.assert_no_active_block_jobs()
215 result = self.vm.qmp('block-stream', device='drive0')
216 self.assert_qmp(result, 'return', {})
218 completed = False
219 error = False
220 while not completed:
221 for event in self.vm.get_qmp_events(wait=True):
222 if event['event'] == 'BLOCK_JOB_ERROR':
223 self.assert_qmp(event, 'data/device', 'drive0')
224 self.assert_qmp(event, 'data/operation', 'read')
225 error = True
226 elif event['event'] == 'BLOCK_JOB_COMPLETED':
227 self.assertTrue(error, 'job completed unexpectedly')
228 self.assert_qmp(event, 'data/type', 'stream')
229 self.assert_qmp(event, 'data/device', 'drive0')
230 self.assert_qmp(event, 'data/error', 'Input/output error')
231 self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
232 self.assert_qmp(event, 'data/len', self.image_len)
233 completed = True
235 self.assert_no_active_block_jobs()
236 self.vm.shutdown()
238 def test_ignore(self):
239 self.assert_no_active_block_jobs()
241 result = self.vm.qmp('block-stream', device='drive0', on_error='ignore')
242 self.assert_qmp(result, 'return', {})
244 error = False
245 completed = False
246 while not completed:
247 for event in self.vm.get_qmp_events(wait=True):
248 if event['event'] == 'BLOCK_JOB_ERROR':
249 self.assert_qmp(event, 'data/device', 'drive0')
250 self.assert_qmp(event, 'data/operation', 'read')
251 result = self.vm.qmp('query-block-jobs')
252 self.assert_qmp(result, 'return[0]/paused', False)
253 error = True
254 elif event['event'] == 'BLOCK_JOB_COMPLETED':
255 self.assertTrue(error, 'job completed unexpectedly')
256 self.assert_qmp(event, 'data/type', 'stream')
257 self.assert_qmp(event, 'data/device', 'drive0')
258 self.assert_qmp(event, 'data/error', 'Input/output error')
259 self.assert_qmp(event, 'data/offset', self.image_len)
260 self.assert_qmp(event, 'data/len', self.image_len)
261 completed = True
263 self.assert_no_active_block_jobs()
264 self.vm.shutdown()
266 def test_stop(self):
267 self.assert_no_active_block_jobs()
269 result = self.vm.qmp('block-stream', device='drive0', on_error='stop')
270 self.assert_qmp(result, 'return', {})
272 error = False
273 completed = False
274 while not completed:
275 for event in self.vm.get_qmp_events(wait=True):
276 if event['event'] == 'BLOCK_JOB_ERROR':
277 self.assert_qmp(event, 'data/device', 'drive0')
278 self.assert_qmp(event, 'data/operation', 'read')
280 result = self.vm.qmp('query-block-jobs')
281 self.assert_qmp(result, 'return[0]/paused', True)
282 self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE)
283 self.assert_qmp(result, 'return[0]/io-status', 'failed')
285 result = self.vm.qmp('block-job-resume', device='drive0')
286 self.assert_qmp(result, 'return', {})
288 result = self.vm.qmp('query-block-jobs')
289 self.assert_qmp(result, 'return[0]/paused', False)
290 self.assert_qmp(result, 'return[0]/io-status', 'ok')
291 error = True
292 elif event['event'] == 'BLOCK_JOB_COMPLETED':
293 self.assertTrue(error, 'job completed unexpectedly')
294 self.assert_qmp(event, 'data/type', 'stream')
295 self.assert_qmp(event, 'data/device', 'drive0')
296 self.assert_qmp_absent(event, 'data/error')
297 self.assert_qmp(event, 'data/offset', self.image_len)
298 self.assert_qmp(event, 'data/len', self.image_len)
299 completed = True
301 self.assert_no_active_block_jobs()
302 self.vm.shutdown()
304 def test_enospc(self):
305 self.assert_no_active_block_jobs()
307 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
308 self.assert_qmp(result, 'return', {})
310 completed = False
311 error = False
312 while not completed:
313 for event in self.vm.get_qmp_events(wait=True):
314 if event['event'] == 'BLOCK_JOB_ERROR':
315 self.assert_qmp(event, 'data/device', 'drive0')
316 self.assert_qmp(event, 'data/operation', 'read')
317 error = True
318 elif event['event'] == 'BLOCK_JOB_COMPLETED':
319 self.assertTrue(error, 'job completed unexpectedly')
320 self.assert_qmp(event, 'data/type', 'stream')
321 self.assert_qmp(event, 'data/device', 'drive0')
322 self.assert_qmp(event, 'data/error', 'Input/output error')
323 self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
324 self.assert_qmp(event, 'data/len', self.image_len)
325 completed = True
327 self.assert_no_active_block_jobs()
328 self.vm.shutdown()
330 class TestENOSPC(TestErrors):
331 def setUp(self):
332 self.blkdebug_file = backing_img + ".blkdebug"
333 iotests.create_image(backing_img, TestErrors.image_len)
334 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28)
335 qemu_img('create', '-f', iotests.imgfmt,
336 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
337 % (self.blkdebug_file, backing_img),
338 test_img)
339 self.vm = iotests.VM().add_drive(test_img)
340 self.vm.launch()
342 def tearDown(self):
343 self.vm.shutdown()
344 os.remove(test_img)
345 os.remove(backing_img)
346 os.remove(self.blkdebug_file)
348 def test_enospc(self):
349 self.assert_no_active_block_jobs()
351 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
352 self.assert_qmp(result, 'return', {})
354 error = False
355 completed = False
356 while not completed:
357 for event in self.vm.get_qmp_events(wait=True):
358 if event['event'] == 'BLOCK_JOB_ERROR':
359 self.assert_qmp(event, 'data/device', 'drive0')
360 self.assert_qmp(event, 'data/operation', 'read')
362 result = self.vm.qmp('query-block-jobs')
363 self.assert_qmp(result, 'return[0]/paused', True)
364 self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE)
365 self.assert_qmp(result, 'return[0]/io-status', 'nospace')
367 result = self.vm.qmp('block-job-resume', device='drive0')
368 self.assert_qmp(result, 'return', {})
370 result = self.vm.qmp('query-block-jobs')
371 self.assert_qmp(result, 'return[0]/paused', False)
372 self.assert_qmp(result, 'return[0]/io-status', 'ok')
373 error = True
374 elif event['event'] == 'BLOCK_JOB_COMPLETED':
375 self.assertTrue(error, 'job completed unexpectedly')
376 self.assert_qmp(event, 'data/type', 'stream')
377 self.assert_qmp(event, 'data/device', 'drive0')
378 self.assert_qmp_absent(event, 'data/error')
379 self.assert_qmp(event, 'data/offset', self.image_len)
380 self.assert_qmp(event, 'data/len', self.image_len)
381 completed = True
383 self.assert_no_active_block_jobs()
384 self.vm.shutdown()
386 class TestStreamStop(iotests.QMPTestCase):
387 image_len = 8 * 1024 * 1024 * 1024 # GB
389 def setUp(self):
390 qemu_img('create', backing_img, str(TestStreamStop.image_len))
391 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
392 self.vm = iotests.VM().add_drive(test_img)
393 self.vm.launch()
395 def tearDown(self):
396 self.vm.shutdown()
397 os.remove(test_img)
398 os.remove(backing_img)
400 def test_stream_stop(self):
401 self.assert_no_active_block_jobs()
403 result = self.vm.qmp('block-stream', device='drive0')
404 self.assert_qmp(result, 'return', {})
406 time.sleep(0.1)
407 events = self.vm.get_qmp_events(wait=False)
408 self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
410 self.cancel_and_wait()
412 class TestSetSpeed(iotests.QMPTestCase):
413 image_len = 80 * 1024 * 1024 # MB
415 def setUp(self):
416 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
417 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
418 self.vm = iotests.VM().add_drive(test_img)
419 self.vm.launch()
421 def tearDown(self):
422 self.vm.shutdown()
423 os.remove(test_img)
424 os.remove(backing_img)
426 # This is a short performance test which is not run by default.
427 # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
428 def perf_test_throughput(self):
429 self.assert_no_active_block_jobs()
431 result = self.vm.qmp('block-stream', device='drive0')
432 self.assert_qmp(result, 'return', {})
434 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
435 self.assert_qmp(result, 'return', {})
437 completed = False
438 while not completed:
439 for event in self.vm.get_qmp_events(wait=True):
440 if event['event'] == 'BLOCK_JOB_COMPLETED':
441 self.assert_qmp(event, 'data/type', 'stream')
442 self.assert_qmp(event, 'data/device', 'drive0')
443 self.assert_qmp(event, 'data/offset', self.image_len)
444 self.assert_qmp(event, 'data/len', self.image_len)
445 completed = True
447 self.assert_no_active_block_jobs()
449 def test_set_speed(self):
450 self.assert_no_active_block_jobs()
452 result = self.vm.qmp('block-stream', device='drive0')
453 self.assert_qmp(result, 'return', {})
455 # Default speed is 0
456 result = self.vm.qmp('query-block-jobs')
457 self.assert_qmp(result, 'return[0]/device', 'drive0')
458 self.assert_qmp(result, 'return[0]/speed', 0)
460 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
461 self.assert_qmp(result, 'return', {})
463 # Ensure the speed we set was accepted
464 result = self.vm.qmp('query-block-jobs')
465 self.assert_qmp(result, 'return[0]/device', 'drive0')
466 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
468 self.cancel_and_wait()
470 # Check setting speed in block-stream works
471 result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
472 self.assert_qmp(result, 'return', {})
474 result = self.vm.qmp('query-block-jobs')
475 self.assert_qmp(result, 'return[0]/device', 'drive0')
476 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
478 self.cancel_and_wait()
480 def test_set_speed_invalid(self):
481 self.assert_no_active_block_jobs()
483 result = self.vm.qmp('block-stream', device='drive0', speed=-1)
484 self.assert_qmp(result, 'error/class', 'GenericError')
486 self.assert_no_active_block_jobs()
488 result = self.vm.qmp('block-stream', device='drive0')
489 self.assert_qmp(result, 'return', {})
491 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
492 self.assert_qmp(result, 'error/class', 'GenericError')
494 self.cancel_and_wait()
496 if __name__ == '__main__':
497 iotests.main(supported_fmts=['qcow2', 'qed'])