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:
parent
bef7e9e2c7
commit
aae12d4baa
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user