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