]> git.proxmox.com Git - qemu.git/blame - tests/qemu-iotests/030
virtio-balloon: cleanup: remove qdev field.
[qemu.git] / tests / qemu-iotests / 030
CommitLineData
37ce63eb
SH
1#!/usr/bin/env python
2#
3# Tests for image streaming.
4#
5# Copyright (C) 2012 IBM Corp.
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
0c817347 21import time
37ce63eb
SH
22import os
23import iotests
24from iotests import qemu_img, qemu_io
ab68cdfa 25import struct
37ce63eb
SH
26
27backing_img = os.path.join(iotests.test_dir, 'backing.img')
6e343609 28mid_img = os.path.join(iotests.test_dir, 'mid.img')
37ce63eb
SH
29test_img = os.path.join(iotests.test_dir, 'test.img')
30
31class ImageStreamingTestCase(iotests.QMPTestCase):
32 '''Abstract base class for image streaming test cases'''
33
34 def assert_no_active_streams(self):
35 result = self.vm.qmp('query-block-jobs')
36 self.assert_qmp(result, 'return', [])
37
e425306a
SH
38 def cancel_and_wait(self, drive='drive0'):
39 '''Cancel a block job and wait for it to finish'''
40 result = self.vm.qmp('block-job-cancel', device=drive)
41 self.assert_qmp(result, 'return', {})
42
43 cancelled = False
44 while not cancelled:
45 for event in self.vm.get_qmp_events(wait=True):
46 if event['event'] == 'BLOCK_JOB_CANCELLED':
47 self.assert_qmp(event, 'data/type', 'stream')
48 self.assert_qmp(event, 'data/device', drive)
49 cancelled = True
50
51 self.assert_no_active_streams()
52
ab68cdfa
PB
53 def create_image(self, name, size):
54 file = open(name, 'w')
55 i = 0
56 while i < size:
57 sector = struct.pack('>l504xl', i / 512, i / 512)
58 file.write(sector)
59 i = i + 512
60 file.close()
61
62
37ce63eb
SH
63class TestSingleDrive(ImageStreamingTestCase):
64 image_len = 1 * 1024 * 1024 # MB
65
66 def setUp(self):
ab68cdfa 67 self.create_image(backing_img, TestSingleDrive.image_len)
6e343609
PB
68 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
69 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
37ce63eb
SH
70 self.vm = iotests.VM().add_drive(test_img)
71 self.vm.launch()
72
73 def tearDown(self):
74 self.vm.shutdown()
75 os.remove(test_img)
6e343609 76 os.remove(mid_img)
37ce63eb
SH
77 os.remove(backing_img)
78
79 def test_stream(self):
80 self.assert_no_active_streams()
81
db58f9c0 82 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
83 self.assert_qmp(result, 'return', {})
84
85 completed = False
86 while not completed:
87 for event in self.vm.get_qmp_events(wait=True):
88 if event['event'] == 'BLOCK_JOB_COMPLETED':
89 self.assert_qmp(event, 'data/type', 'stream')
90 self.assert_qmp(event, 'data/device', 'drive0')
91 self.assert_qmp(event, 'data/offset', self.image_len)
92 self.assert_qmp(event, 'data/len', self.image_len)
93 completed = True
94
95 self.assert_no_active_streams()
863a5d04 96 self.vm.shutdown()
37ce63eb 97
efcc7a23
PB
98 self.assertEqual(qemu_io('-c', 'map', backing_img),
99 qemu_io('-c', 'map', test_img),
100 'image file map does not match backing file after streaming')
37ce63eb 101
0c817347
PB
102 def test_stream_pause(self):
103 self.assert_no_active_streams()
104
105 result = self.vm.qmp('block-stream', device='drive0')
106 self.assert_qmp(result, 'return', {})
107
108 result = self.vm.qmp('block-job-pause', device='drive0')
109 self.assert_qmp(result, 'return', {})
110
111 time.sleep(1)
112 result = self.vm.qmp('query-block-jobs')
113 offset = self.dictpath(result, 'return[0]/offset')
114
115 time.sleep(1)
116 result = self.vm.qmp('query-block-jobs')
117 self.assert_qmp(result, 'return[0]/offset', offset)
118
119 result = self.vm.qmp('block-job-resume', device='drive0')
120 self.assert_qmp(result, 'return', {})
121
122 completed = False
123 while not completed:
124 for event in self.vm.get_qmp_events(wait=True):
125 if event['event'] == 'BLOCK_JOB_COMPLETED':
126 self.assert_qmp(event, 'data/type', 'stream')
127 self.assert_qmp(event, 'data/device', 'drive0')
128 self.assert_qmp(event, 'data/offset', self.image_len)
129 self.assert_qmp(event, 'data/len', self.image_len)
130 completed = True
131
132 self.assert_no_active_streams()
133 self.vm.shutdown()
134
135 self.assertEqual(qemu_io('-c', 'map', backing_img),
136 qemu_io('-c', 'map', test_img),
137 'image file map does not match backing file after streaming')
138
6e343609
PB
139 def test_stream_partial(self):
140 self.assert_no_active_streams()
141
142 result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
143 self.assert_qmp(result, 'return', {})
144
145 completed = False
146 while not completed:
147 for event in self.vm.get_qmp_events(wait=True):
148 if event['event'] == 'BLOCK_JOB_COMPLETED':
149 self.assert_qmp(event, 'data/type', 'stream')
150 self.assert_qmp(event, 'data/device', 'drive0')
151 self.assert_qmp(event, 'data/offset', self.image_len)
152 self.assert_qmp(event, 'data/len', self.image_len)
153 completed = True
154
155 self.assert_no_active_streams()
156 self.vm.shutdown()
157
158 self.assertEqual(qemu_io('-c', 'map', mid_img),
159 qemu_io('-c', 'map', test_img),
160 'image file map does not match backing file after streaming')
161
37ce63eb 162 def test_device_not_found(self):
db58f9c0 163 result = self.vm.qmp('block-stream', device='nonexistent')
37ce63eb
SH
164 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
165
774a8850
SH
166
167class TestSmallerBackingFile(ImageStreamingTestCase):
168 backing_len = 1 * 1024 * 1024 # MB
169 image_len = 2 * backing_len
170
171 def setUp(self):
172 self.create_image(backing_img, self.backing_len)
173 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len))
174 self.vm = iotests.VM().add_drive(test_img)
175 self.vm.launch()
176
177 # If this hangs, then you are missing a fix to complete streaming when the
178 # end of the backing file is reached.
179 def test_stream(self):
180 self.assert_no_active_streams()
181
182 result = self.vm.qmp('block-stream', device='drive0')
183 self.assert_qmp(result, 'return', {})
184
185 completed = False
186 while not completed:
187 for event in self.vm.get_qmp_events(wait=True):
188 if event['event'] == 'BLOCK_JOB_COMPLETED':
189 self.assert_qmp(event, 'data/type', 'stream')
190 self.assert_qmp(event, 'data/device', 'drive0')
191 self.assert_qmp(event, 'data/offset', self.image_len)
192 self.assert_qmp(event, 'data/len', self.image_len)
193 completed = True
194
195 self.assert_no_active_streams()
196 self.vm.shutdown()
197
90f0b711
PB
198class TestErrors(ImageStreamingTestCase):
199 image_len = 2 * 1024 * 1024 # MB
200
201 # this should match STREAM_BUFFER_SIZE/512 in block/stream.c
202 STREAM_BUFFER_SIZE = 512 * 1024
203
204 def create_blkdebug_file(self, name, event, errno):
205 file = open(name, 'w')
206 file.write('''
207[inject-error]
208state = "1"
209event = "%s"
210errno = "%d"
211immediately = "off"
212once = "on"
213sector = "%d"
214
215[set-state]
216state = "1"
217event = "%s"
218new_state = "2"
219
220[set-state]
221state = "2"
222event = "%s"
223new_state = "1"
224''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event))
225 file.close()
226
227class TestEIO(TestErrors):
228 def setUp(self):
229 self.blkdebug_file = backing_img + ".blkdebug"
230 self.create_image(backing_img, TestErrors.image_len)
231 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
232 qemu_img('create', '-f', iotests.imgfmt,
233 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
234 % (self.blkdebug_file, backing_img),
235 test_img)
236 self.vm = iotests.VM().add_drive(test_img)
237 self.vm.launch()
238
239 def tearDown(self):
240 self.vm.shutdown()
241 os.remove(test_img)
242 os.remove(backing_img)
243 os.remove(self.blkdebug_file)
244
245 def test_report(self):
246 self.assert_no_active_streams()
247
248 result = self.vm.qmp('block-stream', device='drive0')
249 self.assert_qmp(result, 'return', {})
250
251 completed = False
252 error = False
253 while not completed:
254 for event in self.vm.get_qmp_events(wait=True):
255 if event['event'] == 'BLOCK_JOB_ERROR':
256 self.assert_qmp(event, 'data/device', 'drive0')
257 self.assert_qmp(event, 'data/operation', 'read')
258 error = True
259 elif event['event'] == 'BLOCK_JOB_COMPLETED':
260 self.assertTrue(error, 'job completed unexpectedly')
261 self.assert_qmp(event, 'data/type', 'stream')
262 self.assert_qmp(event, 'data/device', 'drive0')
263 self.assert_qmp(event, 'data/error', 'Input/output error')
264 self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
265 self.assert_qmp(event, 'data/len', self.image_len)
266 completed = True
267
268 self.assert_no_active_streams()
269 self.vm.shutdown()
270
271 def test_ignore(self):
272 self.assert_no_active_streams()
273
274 result = self.vm.qmp('block-stream', device='drive0', on_error='ignore')
275 self.assert_qmp(result, 'return', {})
276
277 error = False
278 completed = False
279 while not completed:
280 for event in self.vm.get_qmp_events(wait=True):
281 if event['event'] == 'BLOCK_JOB_ERROR':
282 self.assert_qmp(event, 'data/device', 'drive0')
283 self.assert_qmp(event, 'data/operation', 'read')
284 result = self.vm.qmp('query-block-jobs')
285 self.assert_qmp(result, 'return[0]/paused', False)
286 error = True
287 elif event['event'] == 'BLOCK_JOB_COMPLETED':
288 self.assertTrue(error, 'job completed unexpectedly')
289 self.assert_qmp(event, 'data/type', 'stream')
290 self.assert_qmp(event, 'data/device', 'drive0')
291 self.assert_qmp(event, 'data/error', 'Input/output error')
292 self.assert_qmp(event, 'data/offset', self.image_len)
293 self.assert_qmp(event, 'data/len', self.image_len)
294 completed = True
295
296 self.assert_no_active_streams()
297 self.vm.shutdown()
298
299 def test_stop(self):
300 self.assert_no_active_streams()
301
302 result = self.vm.qmp('block-stream', device='drive0', on_error='stop')
303 self.assert_qmp(result, 'return', {})
304
305 error = False
306 completed = False
307 while not completed:
308 for event in self.vm.get_qmp_events(wait=True):
309 if event['event'] == 'BLOCK_JOB_ERROR':
310 self.assert_qmp(event, 'data/device', 'drive0')
311 self.assert_qmp(event, 'data/operation', 'read')
312
313 result = self.vm.qmp('query-block-jobs')
314 self.assert_qmp(result, 'return[0]/paused', True)
315 self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE)
316 self.assert_qmp(result, 'return[0]/io-status', 'failed')
317
318 result = self.vm.qmp('block-job-resume', device='drive0')
319 self.assert_qmp(result, 'return', {})
320
321 result = self.vm.qmp('query-block-jobs')
322 self.assert_qmp(result, 'return[0]/paused', False)
323 self.assert_qmp(result, 'return[0]/io-status', 'ok')
324 error = True
325 elif event['event'] == 'BLOCK_JOB_COMPLETED':
326 self.assertTrue(error, 'job completed unexpectedly')
327 self.assert_qmp(event, 'data/type', 'stream')
328 self.assert_qmp(event, 'data/device', 'drive0')
329 self.assert_qmp_absent(event, 'data/error')
330 self.assert_qmp(event, 'data/offset', self.image_len)
331 self.assert_qmp(event, 'data/len', self.image_len)
332 completed = True
333
334 self.assert_no_active_streams()
335 self.vm.shutdown()
336
337 def test_enospc(self):
338 self.assert_no_active_streams()
339
340 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
341 self.assert_qmp(result, 'return', {})
342
343 completed = False
344 error = False
345 while not completed:
346 for event in self.vm.get_qmp_events(wait=True):
347 if event['event'] == 'BLOCK_JOB_ERROR':
348 self.assert_qmp(event, 'data/device', 'drive0')
349 self.assert_qmp(event, 'data/operation', 'read')
350 error = True
351 elif event['event'] == 'BLOCK_JOB_COMPLETED':
352 self.assertTrue(error, 'job completed unexpectedly')
353 self.assert_qmp(event, 'data/type', 'stream')
354 self.assert_qmp(event, 'data/device', 'drive0')
355 self.assert_qmp(event, 'data/error', 'Input/output error')
356 self.assert_qmp(event, 'data/offset', self.STREAM_BUFFER_SIZE)
357 self.assert_qmp(event, 'data/len', self.image_len)
358 completed = True
359
360 self.assert_no_active_streams()
361 self.vm.shutdown()
362
363class TestENOSPC(TestErrors):
364 def setUp(self):
365 self.blkdebug_file = backing_img + ".blkdebug"
366 self.create_image(backing_img, TestErrors.image_len)
367 self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28)
368 qemu_img('create', '-f', iotests.imgfmt,
369 '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
370 % (self.blkdebug_file, backing_img),
371 test_img)
372 self.vm = iotests.VM().add_drive(test_img)
373 self.vm.launch()
374
375 def tearDown(self):
376 self.vm.shutdown()
377 os.remove(test_img)
378 os.remove(backing_img)
379 os.remove(self.blkdebug_file)
380
381 def test_enospc(self):
382 self.assert_no_active_streams()
383
384 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
385 self.assert_qmp(result, 'return', {})
386
387 error = False
388 completed = False
389 while not completed:
390 for event in self.vm.get_qmp_events(wait=True):
391 if event['event'] == 'BLOCK_JOB_ERROR':
392 self.assert_qmp(event, 'data/device', 'drive0')
393 self.assert_qmp(event, 'data/operation', 'read')
394
395 result = self.vm.qmp('query-block-jobs')
396 self.assert_qmp(result, 'return[0]/paused', True)
397 self.assert_qmp(result, 'return[0]/offset', self.STREAM_BUFFER_SIZE)
398 self.assert_qmp(result, 'return[0]/io-status', 'nospace')
399
400 result = self.vm.qmp('block-job-resume', device='drive0')
401 self.assert_qmp(result, 'return', {})
402
403 result = self.vm.qmp('query-block-jobs')
404 self.assert_qmp(result, 'return[0]/paused', False)
405 self.assert_qmp(result, 'return[0]/io-status', 'ok')
406 error = True
407 elif event['event'] == 'BLOCK_JOB_COMPLETED':
408 self.assertTrue(error, 'job completed unexpectedly')
409 self.assert_qmp(event, 'data/type', 'stream')
410 self.assert_qmp(event, 'data/device', 'drive0')
411 self.assert_qmp_absent(event, 'data/error')
412 self.assert_qmp(event, 'data/offset', self.image_len)
413 self.assert_qmp(event, 'data/len', self.image_len)
414 completed = True
415
416 self.assert_no_active_streams()
417 self.vm.shutdown()
774a8850 418
37ce63eb
SH
419class TestStreamStop(ImageStreamingTestCase):
420 image_len = 8 * 1024 * 1024 * 1024 # GB
421
422 def setUp(self):
423 qemu_img('create', backing_img, str(TestStreamStop.image_len))
424 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
425 self.vm = iotests.VM().add_drive(test_img)
426 self.vm.launch()
427
428 def tearDown(self):
429 self.vm.shutdown()
430 os.remove(test_img)
431 os.remove(backing_img)
432
433 def test_stream_stop(self):
37ce63eb
SH
434 self.assert_no_active_streams()
435
db58f9c0 436 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
437 self.assert_qmp(result, 'return', {})
438
0fd05e8d 439 time.sleep(0.1)
37ce63eb
SH
440 events = self.vm.get_qmp_events(wait=False)
441 self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
442
e425306a 443 self.cancel_and_wait()
37ce63eb 444
37ce63eb
SH
445class TestSetSpeed(ImageStreamingTestCase):
446 image_len = 80 * 1024 * 1024 # MB
447
448 def setUp(self):
449 qemu_img('create', backing_img, str(TestSetSpeed.image_len))
450 qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
451 self.vm = iotests.VM().add_drive(test_img)
452 self.vm.launch()
453
454 def tearDown(self):
455 self.vm.shutdown()
456 os.remove(test_img)
457 os.remove(backing_img)
458
e425306a
SH
459 # This is a short performance test which is not run by default.
460 # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
461 def perf_test_throughput(self):
37ce63eb
SH
462 self.assert_no_active_streams()
463
db58f9c0 464 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
465 self.assert_qmp(result, 'return', {})
466
e425306a 467 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
37ce63eb
SH
468 self.assert_qmp(result, 'return', {})
469
470 completed = False
471 while not completed:
472 for event in self.vm.get_qmp_events(wait=True):
473 if event['event'] == 'BLOCK_JOB_COMPLETED':
474 self.assert_qmp(event, 'data/type', 'stream')
475 self.assert_qmp(event, 'data/device', 'drive0')
476 self.assert_qmp(event, 'data/offset', self.image_len)
477 self.assert_qmp(event, 'data/len', self.image_len)
478 completed = True
479
480 self.assert_no_active_streams()
481
e425306a
SH
482 def test_set_speed(self):
483 self.assert_no_active_streams()
484
485 result = self.vm.qmp('block-stream', device='drive0')
486 self.assert_qmp(result, 'return', {})
487
488 # Default speed is 0
489 result = self.vm.qmp('query-block-jobs')
490 self.assert_qmp(result, 'return[0]/device', 'drive0')
491 self.assert_qmp(result, 'return[0]/speed', 0)
492
493 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
494 self.assert_qmp(result, 'return', {})
495
496 # Ensure the speed we set was accepted
497 result = self.vm.qmp('query-block-jobs')
498 self.assert_qmp(result, 'return[0]/device', 'drive0')
499 self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
500
501 self.cancel_and_wait()
502
503 # Check setting speed in block-stream works
504 result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
505 self.assert_qmp(result, 'return', {})
506
507 result = self.vm.qmp('query-block-jobs')
508 self.assert_qmp(result, 'return[0]/device', 'drive0')
509 self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
510
511 self.cancel_and_wait()
512
513 def test_set_speed_invalid(self):
514 self.assert_no_active_streams()
515
516 result = self.vm.qmp('block-stream', device='drive0', speed=-1)
58c8cce2 517 self.assert_qmp(result, 'error/class', 'GenericError')
e425306a
SH
518
519 self.assert_no_active_streams()
520
521 result = self.vm.qmp('block-stream', device='drive0')
522 self.assert_qmp(result, 'return', {})
523
524 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
58c8cce2 525 self.assert_qmp(result, 'error/class', 'GenericError')
e425306a
SH
526
527 self.cancel_and_wait()
528
37ce63eb
SH
529if __name__ == '__main__':
530 iotests.main(supported_fmts=['qcow2', 'qed'])