]> Git Repo - qemu.git/blame - tests/qemu-iotests/219
iotests: Add qemu_io_log()
[qemu.git] / tests / qemu-iotests / 219
CommitLineData
bdebdc71
KW
1#!/usr/bin/env python
2#
3# Copyright (C) 2018 Red Hat, Inc.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18# Creator/Owner: Kevin Wolf <[email protected]>
19#
20# Check using the job-* QMP commands with block jobs
21
22import iotests
23
24iotests.verify_image_format(supported_fmts=['qcow2'])
25
d9efe938
HR
26img_size = 4 * 1024 * 1024
27
bdebdc71
KW
28def pause_wait(vm, job_id):
29 with iotests.Timeout(3, "Timeout waiting for job to pause"):
30 while True:
31 result = vm.qmp('query-jobs')
32 for job in result['return']:
33 if job['id'] == job_id and job['status'] in ['paused', 'standby']:
34 return job
35
36# Test that block-job-pause/resume and job-pause/resume can be mixed
37def test_pause_resume(vm):
38 for pause_cmd, pause_arg in [('block-job-pause', 'device'),
39 ('job-pause', 'id')]:
40 for resume_cmd, resume_arg in [('block-job-resume', 'device'),
41 ('job-resume', 'id')]:
42 iotests.log('=== Testing %s/%s ===' % (pause_cmd, resume_cmd))
43
44 iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'}))
45 pause_wait(vm, 'job0')
46 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
83f90b53
HR
47 result = vm.qmp('query-jobs')
48 iotests.log(result)
49
50 old_progress = result['return'][0]['current-progress']
51 total_progress = result['return'][0]['total-progress']
bdebdc71
KW
52
53 iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'}))
54 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
83f90b53
HR
55 if old_progress < total_progress:
56 # Wait for the job to advance
57 while result['return'][0]['current-progress'] == old_progress:
58 result = vm.qmp('query-jobs')
59 iotests.log(result)
60 else:
61 # Already reached the end, so the job cannot advance
62 # any further; therefore, the query-jobs result can be
63 # logged immediately
64 iotests.log(vm.qmp('query-jobs'))
bdebdc71
KW
65
66def test_job_lifecycle(vm, job, job_args, has_ready=False):
d9efe938
HR
67 global img_size
68
bdebdc71
KW
69 iotests.log('')
70 iotests.log('')
71 iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
72 (job,
73 job_args.get('auto-finalize', True),
74 job_args.get('auto-dismiss', True)))
75 iotests.log(vm.qmp(job, job_id='job0', **job_args))
76
77 # Depending on the storage, the first request may or may not have completed
83f90b53
HR
78 # yet (and the total progress may not have been fully determined yet), so
79 # filter out the progress. Later query-job calls don't need the filtering
80 # because the progress is made deterministic by the block job speed
bdebdc71
KW
81 result = vm.qmp('query-jobs')
82 for j in result['return']:
83f90b53
HR
83 j['current-progress'] = 'FILTERED'
84 j['total-progress'] = 'FILTERED'
bdebdc71
KW
85 iotests.log(result)
86
87 # undefined -> created -> running
88 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
89 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
90
d9efe938
HR
91 # Wait for total-progress to stabilize
92 while vm.qmp('query-jobs')['return'][0]['total-progress'] < img_size:
93 pass
94
bdebdc71
KW
95 # RUNNING state:
96 # pause/resume should work, complete/finalize/dismiss should error out
97 iotests.log('')
98 iotests.log('Pause/resume in RUNNING')
99 test_pause_resume(vm)
100
101 iotests.log(vm.qmp('job-complete', id='job0'))
102 iotests.log(vm.qmp('job-finalize', id='job0'))
103 iotests.log(vm.qmp('job-dismiss', id='job0'))
104
105 iotests.log(vm.qmp('block-job-complete', device='job0'))
106 iotests.log(vm.qmp('block-job-finalize', id='job0'))
107 iotests.log(vm.qmp('block-job-dismiss', id='job0'))
108
109 # Let the job complete (or transition to READY if it supports that)
110 iotests.log(vm.qmp('block-job-set-speed', device='job0', speed=0))
111 if has_ready:
112 iotests.log('')
113 iotests.log('Waiting for READY state...')
114 vm.event_wait('BLOCK_JOB_READY')
115 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
116 iotests.log(vm.qmp('query-jobs'))
117
118 # READY state:
119 # pause/resume/complete should work, finalize/dismiss should error out
120 iotests.log('')
121 iotests.log('Pause/resume in READY')
122 test_pause_resume(vm)
123
124 iotests.log(vm.qmp('job-finalize', id='job0'))
125 iotests.log(vm.qmp('job-dismiss', id='job0'))
126
127 iotests.log(vm.qmp('block-job-finalize', id='job0'))
128 iotests.log(vm.qmp('block-job-dismiss', id='job0'))
129
130 # Transition to WAITING
131 iotests.log(vm.qmp('job-complete', id='job0'))
132
133 # Move to WAITING and PENDING state
134 iotests.log('')
135 iotests.log('Waiting for PENDING state...')
136 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
137 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
138
139 if not job_args.get('auto-finalize', True):
140 # PENDING state:
141 # finalize should work, pause/complete/dismiss should error out
142 iotests.log(vm.qmp('query-jobs'))
143
144 iotests.log(vm.qmp('job-pause', id='job0'))
145 iotests.log(vm.qmp('job-complete', id='job0'))
146 iotests.log(vm.qmp('job-dismiss', id='job0'))
147
148 iotests.log(vm.qmp('block-job-pause', device='job0'))
149 iotests.log(vm.qmp('block-job-complete', device='job0'))
150 iotests.log(vm.qmp('block-job-dismiss', id='job0'))
151
152 # Transition to CONCLUDED
153 iotests.log(vm.qmp('job-finalize', id='job0'))
154
155
156 # Move to CONCLUDED state
157 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
158
159 if not job_args.get('auto-dismiss', True):
160 # CONCLUDED state:
161 # dismiss should work, pause/complete/finalize should error out
162 iotests.log(vm.qmp('query-jobs'))
163
164 iotests.log(vm.qmp('job-pause', id='job0'))
165 iotests.log(vm.qmp('job-complete', id='job0'))
166 iotests.log(vm.qmp('job-finalize', id='job0'))
167
168 iotests.log(vm.qmp('block-job-pause', device='job0'))
169 iotests.log(vm.qmp('block-job-complete', device='job0'))
170 iotests.log(vm.qmp('block-job-finalize', id='job0'))
171
172 # Transition to NULL
173 iotests.log(vm.qmp('job-dismiss', id='job0'))
174
175 # Move to NULL state
176 iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
177 iotests.log(vm.qmp('query-jobs'))
178
179
180with iotests.FilePath('disk.img') as disk_path, \
181 iotests.FilePath('copy.img') as copy_path, \
182 iotests.VM() as vm:
183
d9efe938
HR
184 iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, str(img_size))
185 iotests.qemu_io('-c', 'write 0 %i' % (img_size),
bdebdc71
KW
186 '-f', iotests.imgfmt, disk_path)
187
188 iotests.log('Launching VM...')
189 vm.add_blockdev(vm.qmp_to_opts({
190 'driver': iotests.imgfmt,
191 'node-name': 'drive0-node',
192 'file': {
193 'driver': 'file',
194 'filename': disk_path,
195 },
196 }))
197 vm.launch()
198
199 # In order to keep things deterministic (especially progress in query-job,
200 # but related to this also automatic state transitions like job
201 # completion), but still get pause points often enough to avoid making this
202 # test very slow, it's important to have the right ratio between speed and
203 # buf_size.
204 #
205 # For backup, buf_size is hard-coded to the source image cluster size (64k),
206 # so we'll pick the same for mirror. The slice time, i.e. the granularity
207 # of the rate limiting is 100ms. With a speed of 256k per second, we can
208 # get four pause points per second. This gives us 250ms per iteration,
209 # which should be enough to stay deterministic.
210
211 test_job_lifecycle(vm, 'drive-mirror', has_ready=True, job_args={
212 'device': 'drive0-node',
213 'target': copy_path,
214 'sync': 'full',
215 'speed': 262144,
216 'buf_size': 65536,
217 })
218
219 for auto_finalize in [True, False]:
220 for auto_dismiss in [True, False]:
221 test_job_lifecycle(vm, 'drive-backup', job_args={
222 'device': 'drive0-node',
223 'target': copy_path,
224 'sync': 'full',
225 'speed': 262144,
226 'auto-finalize': auto_finalize,
227 'auto-dismiss': auto_dismiss,
228 })
229
230 vm.shutdown()
This page took 0.16048 seconds and 4 git commands to generate.