]> git.proxmox.com Git - qemu.git/blame - tests/qemu-iotests/030
Merge remote-tracking branch 'bonzini/scsi-next' into staging
[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
25
26backing_img = os.path.join(iotests.test_dir, 'backing.img')
6e343609 27mid_img = os.path.join(iotests.test_dir, 'mid.img')
37ce63eb
SH
28test_img = os.path.join(iotests.test_dir, 'test.img')
29
2499a096 30class TestSingleDrive(iotests.QMPTestCase):
37ce63eb
SH
31 image_len = 1 * 1024 * 1024 # MB
32
33 def setUp(self):
2499a096 34 iotests.create_image(backing_img, TestSingleDrive.image_len)
6e343609
PB
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)
37ce63eb
SH
37 self.vm = iotests.VM().add_drive(test_img)
38 self.vm.launch()
39
40 def tearDown(self):
41 self.vm.shutdown()
42 os.remove(test_img)
6e343609 43 os.remove(mid_img)
37ce63eb
SH
44 os.remove(backing_img)
45
46 def test_stream(self):
ecc1c88e 47 self.assert_no_active_block_jobs()
37ce63eb 48
db58f9c0 49 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
50 self.assert_qmp(result, 'return', {})
51
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
61
ecc1c88e 62 self.assert_no_active_block_jobs()
863a5d04 63 self.vm.shutdown()
37ce63eb 64
efcc7a23
PB
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')
37ce63eb 68
0c817347 69 def test_stream_pause(self):
ecc1c88e 70 self.assert_no_active_block_jobs()
0c817347
PB
71
72 result = self.vm.qmp('block-stream', device='drive0')
73 self.assert_qmp(result, 'return', {})
74
75 result = self.vm.qmp('block-job-pause', device='drive0')
76 self.assert_qmp(result, 'return', {})
77
78 time.sleep(1)
79 result = self.vm.qmp('query-block-jobs')
80 offset = self.dictpath(result, 'return[0]/offset')
81
82 time.sleep(1)
83 result = self.vm.qmp('query-block-jobs')
84 self.assert_qmp(result, 'return[0]/offset', offset)
85
86 result = self.vm.qmp('block-job-resume', device='drive0')
87 self.assert_qmp(result, 'return', {})
88
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
98
ecc1c88e 99 self.assert_no_active_block_jobs()
0c817347
PB
100 self.vm.shutdown()
101
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')
105
6e343609 106 def test_stream_partial(self):
ecc1c88e 107 self.assert_no_active_block_jobs()
6e343609
PB
108
109 result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
110 self.assert_qmp(result, 'return', {})
111
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
121
ecc1c88e 122 self.assert_no_active_block_jobs()
6e343609
PB
123 self.vm.shutdown()
124
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')
128
37ce63eb 129 def test_device_not_found(self):
db58f9c0 130 result = self.vm.qmp('block-stream', device='nonexistent')
37ce63eb
SH
131 self.assert_qmp(result, 'error/class', 'DeviceNotFound')
132
774a8850 133
2499a096 134class TestSmallerBackingFile(iotests.QMPTestCase):
774a8850
SH
135 backing_len = 1 * 1024 * 1024 # MB
136 image_len = 2 * backing_len
137
138 def setUp(self):
2499a096 139 iotests.create_image(backing_img, self.backing_len)
774a8850
SH
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()
143
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):
ecc1c88e 147 self.assert_no_active_block_jobs()
774a8850
SH
148
149 result = self.vm.qmp('block-stream', device='drive0')
150 self.assert_qmp(result, 'return', {})
151
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
161
ecc1c88e 162 self.assert_no_active_block_jobs()
774a8850
SH
163 self.vm.shutdown()
164
2499a096 165class TestErrors(iotests.QMPTestCase):
90f0b711
PB
166 image_len = 2 * 1024 * 1024 # MB
167
168 # this should match STREAM_BUFFER_SIZE/512 in block/stream.c
169 STREAM_BUFFER_SIZE = 512 * 1024
170
171 def create_blkdebug_file(self, name, event, errno):
172 file = open(name, 'w')
173 file.write('''
174[inject-error]
175state = "1"
176event = "%s"
177errno = "%d"
178immediately = "off"
179once = "on"
180sector = "%d"
181
182[set-state]
183state = "1"
184event = "%s"
185new_state = "2"
186
187[set-state]
188state = "2"
189event = "%s"
190new_state = "1"
191''' % (event, errno, self.STREAM_BUFFER_SIZE / 512, event, event))
192 file.close()
193
194class TestEIO(TestErrors):
195 def setUp(self):
196 self.blkdebug_file = backing_img + ".blkdebug"
2499a096 197 iotests.create_image(backing_img, TestErrors.image_len)
90f0b711
PB
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()
205
206 def tearDown(self):
207 self.vm.shutdown()
208 os.remove(test_img)
209 os.remove(backing_img)
210 os.remove(self.blkdebug_file)
211
212 def test_report(self):
ecc1c88e 213 self.assert_no_active_block_jobs()
90f0b711
PB
214
215 result = self.vm.qmp('block-stream', device='drive0')
216 self.assert_qmp(result, 'return', {})
217
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
234
ecc1c88e 235 self.assert_no_active_block_jobs()
90f0b711
PB
236 self.vm.shutdown()
237
238 def test_ignore(self):
ecc1c88e 239 self.assert_no_active_block_jobs()
90f0b711
PB
240
241 result = self.vm.qmp('block-stream', device='drive0', on_error='ignore')
242 self.assert_qmp(result, 'return', {})
243
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
262
ecc1c88e 263 self.assert_no_active_block_jobs()
90f0b711
PB
264 self.vm.shutdown()
265
266 def test_stop(self):
ecc1c88e 267 self.assert_no_active_block_jobs()
90f0b711
PB
268
269 result = self.vm.qmp('block-stream', device='drive0', on_error='stop')
270 self.assert_qmp(result, 'return', {})
271
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')
279
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')
284
285 result = self.vm.qmp('block-job-resume', device='drive0')
286 self.assert_qmp(result, 'return', {})
287
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
300
ecc1c88e 301 self.assert_no_active_block_jobs()
90f0b711
PB
302 self.vm.shutdown()
303
304 def test_enospc(self):
ecc1c88e 305 self.assert_no_active_block_jobs()
90f0b711
PB
306
307 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
308 self.assert_qmp(result, 'return', {})
309
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
326
ecc1c88e 327 self.assert_no_active_block_jobs()
90f0b711
PB
328 self.vm.shutdown()
329
330class TestENOSPC(TestErrors):
331 def setUp(self):
332 self.blkdebug_file = backing_img + ".blkdebug"
2499a096 333 iotests.create_image(backing_img, TestErrors.image_len)
90f0b711
PB
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()
341
342 def tearDown(self):
343 self.vm.shutdown()
344 os.remove(test_img)
345 os.remove(backing_img)
346 os.remove(self.blkdebug_file)
347
348 def test_enospc(self):
ecc1c88e 349 self.assert_no_active_block_jobs()
90f0b711
PB
350
351 result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
352 self.assert_qmp(result, 'return', {})
353
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')
361
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')
366
367 result = self.vm.qmp('block-job-resume', device='drive0')
368 self.assert_qmp(result, 'return', {})
369
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
382
ecc1c88e 383 self.assert_no_active_block_jobs()
90f0b711 384 self.vm.shutdown()
774a8850 385
2499a096 386class TestStreamStop(iotests.QMPTestCase):
37ce63eb
SH
387 image_len = 8 * 1024 * 1024 * 1024 # GB
388
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()
394
395 def tearDown(self):
396 self.vm.shutdown()
397 os.remove(test_img)
398 os.remove(backing_img)
399
400 def test_stream_stop(self):
ecc1c88e 401 self.assert_no_active_block_jobs()
37ce63eb 402
db58f9c0 403 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
404 self.assert_qmp(result, 'return', {})
405
0fd05e8d 406 time.sleep(0.1)
37ce63eb
SH
407 events = self.vm.get_qmp_events(wait=False)
408 self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
409
e425306a 410 self.cancel_and_wait()
37ce63eb 411
2499a096 412class TestSetSpeed(iotests.QMPTestCase):
37ce63eb
SH
413 image_len = 80 * 1024 * 1024 # MB
414
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()
420
421 def tearDown(self):
422 self.vm.shutdown()
423 os.remove(test_img)
424 os.remove(backing_img)
425
e425306a
SH
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):
ecc1c88e 429 self.assert_no_active_block_jobs()
37ce63eb 430
db58f9c0 431 result = self.vm.qmp('block-stream', device='drive0')
37ce63eb
SH
432 self.assert_qmp(result, 'return', {})
433
e425306a 434 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
37ce63eb
SH
435 self.assert_qmp(result, 'return', {})
436
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
446
ecc1c88e 447 self.assert_no_active_block_jobs()
37ce63eb 448
e425306a 449 def test_set_speed(self):
ecc1c88e 450 self.assert_no_active_block_jobs()
e425306a
SH
451
452 result = self.vm.qmp('block-stream', device='drive0')
453 self.assert_qmp(result, 'return', {})
454
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)
459
460 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
461 self.assert_qmp(result, 'return', {})
462
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)
467
468 self.cancel_and_wait()
469
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', {})
473
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)
477
478 self.cancel_and_wait()
479
480 def test_set_speed_invalid(self):
ecc1c88e 481 self.assert_no_active_block_jobs()
e425306a
SH
482
483 result = self.vm.qmp('block-stream', device='drive0', speed=-1)
58c8cce2 484 self.assert_qmp(result, 'error/class', 'GenericError')
e425306a 485
ecc1c88e 486 self.assert_no_active_block_jobs()
e425306a
SH
487
488 result = self.vm.qmp('block-stream', device='drive0')
489 self.assert_qmp(result, 'return', {})
490
491 result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
58c8cce2 492 self.assert_qmp(result, 'error/class', 'GenericError')
e425306a
SH
493
494 self.cancel_and_wait()
495
37ce63eb
SH
496if __name__ == '__main__':
497 iotests.main(supported_fmts=['qcow2', 'qed'])