iotests: add support for capturing and matching QMP events

When using the _launch_qemu and _send_qemu_cmd functions from
common.qemu, any QMP events get mixed in with the output from
the commands and responses.

This makes it difficult to write a test case as the ordering
of events in the output is not stable.

This introduces a variable 'capture_events' which can be set
to a list of event names. Any events listed in this variable
will not be printed, instead collected in the $QEMU_EVENTS
environment variable.

A new '_wait_event' function can be invoked to collect events
at a fixed point in time. The function will first pull events
cached in $QEMU_EVENTS variable, and if none are found, will
then read more from QMP.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20210204124834.774401-11-berrange@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2021-02-04 12:48:32 +00:00 committed by Dr. David Alan Gilbert
parent bef7e9e2c7
commit aae12d4baa
1 changed files with 105 additions and 1 deletions

View File

@ -53,6 +53,15 @@ _in_fd=4
# If $mismatch_only is set, only non-matching responses will
# be echoed.
#
# If $capture_events is non-empty, then any QMP event names it lists
# will not be echoed out, but instead collected in the $QEMU_EVENTS
# variable. The _wait_event function can later be used to receive
# the cached events.
#
# If $only_capture_events is set to anything but an empty string,
# then an error will be raised if a QMP message is seen which is
# not an event listed in $capture_events.
#
# If $success_or_failure is set, the meaning of the arguments is
# changed as follows:
# $2: A string to search for in the response; if found, this indicates
@ -78,6 +87,31 @@ _timed_wait_for()
QEMU_STATUS[$h]=0
while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
do
if [ -n "$capture_events" ]; then
capture=0
local evname
for evname in $capture_events
do
case ${resp} in
*\"event\":\ \"${evname}\"* ) capture=1 ;;
esac
done
if [ $capture = 1 ];
then
ev=$(echo "${resp}" | tr -d '\r' | tr % .)
QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}"
if [ -n "$only_capture_events" ]; then
return
else
continue
fi
fi
fi
if [ -n "$only_capture_events" ]; then
echo "Only expected $capture_events but got ${resp}"
exit 1
fi
if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then
echo "${resp}" | _filter_testdir | _filter_qemu \
| _filter_qemu_io | _filter_qmp | _filter_hmp
@ -172,12 +206,82 @@ _send_qemu_cmd()
let count--;
done
if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then
echo "Timeout waiting for ${1} on handle ${h}"
echo "Timeout waiting for command ${1} response on handle ${h}"
exit 1 #Timeout means the test failed
fi
}
# Check event cache for a named QMP event
#
# Input parameters:
# $1: Name of the QMP event to check for
#
# Checks if the named QMP event that was previously captured
# into $QEMU_EVENTS. When matched, the QMP event will be echoed
# and the $matched variable set to 1.
#
# _wait_event is more suitable for test usage in most cases
_check_cached_events()
{
local evname=${1}
local match="\"event\": \"$evname\""
matched=0
if [ -n "$QEMU_EVENTS" ]; then
CURRENT_QEMU_EVENTS=$QEMU_EVENTS
QEMU_EVENTS=
old_IFS=$IFS
IFS="%"
for ev in $CURRENT_QEMU_EVENTS
do
grep -q "$match" < <(echo "${ev}")
if [ $? -eq 0 ] && [ $matched = 0 ]; then
echo "${ev}" | _filter_testdir | _filter_qemu \
| _filter_qemu_io | _filter_qmp | _filter_hmp
matched=1
else
QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}"
fi
done
IFS=$old_IFS
fi
}
# Wait for a named QMP event
#
# Input parameters:
# $1: QEMU handle to use
# $2: Name of the QMP event to wait for
#
# Checks if the named QMP even was previously captured
# into $QEMU_EVENTS. If none are present, then waits for the
# event to arrive on the QMP channel. When matched, the QMP
# event will be echoed
_wait_event()
{
local h=${1}
local evname=${2}
while true
do
_check_cached_events $evname
if [ $matched = 1 ];
then
return
fi
only_capture_events=1 qemu_error_no_exit=1 _timed_wait_for ${h}
if [ ${QEMU_STATUS[$h]} -ne 0 ] ; then
echo "Timeout waiting for event ${evname} on handle ${h}"
exit 1 #Timeout means the test failed
fi
done
}
# Launch a QEMU process.
#
# Input parameters: