Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge tag 'migration-20230602-pull-request' of https://gitlab.com/jua…
…n.quintela/qemu into staging

Migration Pull request (20230602 vintage)

This PULL request get:
- All migration-test patches except last one (daniel)
- Documentation about live test cases (peter)

Please apply.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmR5yRwACgkQ9IfvGFhy
# 1yOLQQ/+NsrXEj7Bwp2PdGo+wBRkq4Gah/mc9F00pqtJc2CGNWgfgDohhZjBrhRv
# cTABsfEcIKgCYqGYwVCklJGlUMzxlJPPcMfvou5SWN59E4FBFSg4DWaBfDPCS8LW
# yjnz0JcpxJ+Ge0eqP6xpTPKQ0YGisdav/PjF8GZewBCjyrhZop062a92B2t59D8Y
# shJYKaZZU/5/4zx6KqOm9OClD/yJ+w5q6cGn89/rFE0RMSVywZ3Y1O8/LwIAEP6U
# oj88rczh3geGlsmtPIeyhA3BdnYuPonmyLz8CINFH9+y2tR9l1dN59q1uwEOIvff
# BhJvxTNmkTvsi5zeAmbp2CYmRTwhBmlanh8v2OLNj8zlt0cHYNpiYUZO9qxCHIyT
# LnNTTYhrpqAqINdm+Z8c3ymDKkTz0KECBa45hdFtNB4ZOXPDQTHVqkQRfe3CxDKz
# f/WM4TxHEzVMw/Ow1K9Kbk7/AEwIV6Ol2BSf9D+ZcU4ydmu6ENhV9G4cQ9Orlv8I
# opychxf+O/b6yhVFq7J1ufDhfn3aWQmUQC06npEgfrIV/fLrXhYfs2CXkNZs78v6
# MTMNPNBN/UasM8hx+ldsjZEHf625lO3eNWoNY1Xxog5YICnNLA+tG6n69uybew2+
# UOVyoHwX7iqaToK6bQNCS4H/PjCp3v7fzw1Nsz48Pfaklpivz/k=
# =4exy
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 02 Jun 2023 03:49:00 AM PDT
# gpg:                using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [unknown]
# gpg:                 aka "Juan Quintela <quintela@trasno.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03  4B82 F487 EF18 5872 D723

* tag 'migration-20230602-pull-request' of https://gitlab.com/juan.quintela/qemu:
  qtest/migration: Document live=true cases
  tests/qtest: make more migration pre-copy scenarios run non-live
  tests/qtest: distinguish src/dst migration VM stop/resume events
  tests/qtest: capture RESUME events during migration
  tests/qtest: replace wait_command() with qtest_qmp_assert_success
  tests/qtest: switch to using event callbacks for STOP event
  tests/qtest: get rid of some 'qtest_qmp' usage in migration test
  tests/qtest: get rid of 'qmp_command' helper in migration test
  tests/qtest: add support for callback to receive QMP events
  tests/qtest: add various qtest_qmp_assert_success() variants

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed Jun 3, 2023
2 parents 24bc242 + b861383 commit 848a6ca
Show file tree
Hide file tree
Showing 5 changed files with 501 additions and 275 deletions.
115 changes: 106 additions & 9 deletions tests/qtest/libqtest.c
Expand Up @@ -82,6 +82,8 @@ struct QTestState
GString *rx;
QTestTransportOps ops;
GList *pending_events;
QTestQMPEventCallback eventCB;
void *eventData;
};

static GHookList abrt_hooks;
Expand Down Expand Up @@ -703,8 +705,13 @@ QDict *qtest_qmp_receive(QTestState *s)
if (!qdict_get_try_str(response, "event")) {
return response;
}
/* Stash the event for a later consumption */
s->pending_events = g_list_append(s->pending_events, response);

if (!s->eventCB ||
!s->eventCB(s, qdict_get_str(response, "event"),
response, s->eventData)) {
/* Stash the event for a later consumption */
s->pending_events = g_list_append(s->pending_events, response);
}
}
}

Expand Down Expand Up @@ -808,6 +815,13 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
va_end(ap);
}

void qtest_qmp_set_event_callback(QTestState *s,
QTestQMPEventCallback cb, void *opaque)
{
s->eventCB = cb;
s->eventData = opaque;
}

QDict *qtest_qmp_event_ref(QTestState *s, const char *event)
{
while (s->pending_events) {
Expand Down Expand Up @@ -1229,24 +1243,107 @@ void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
qtest_rsp(s);
}

void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
QDict *qtest_vqmp_assert_success_ref(QTestState *qts,
const char *fmt, va_list args)
{
va_list ap;
QDict *response;
QDict *ret;

va_start(ap, fmt);
response = qtest_vqmp(qts, fmt, ap);
va_end(ap);
response = qtest_vqmp(qts, fmt, args);

g_assert(response);
if (!qdict_haskey(response, "return")) {
g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(response), true);
g_test_message("%s", s->str);
}
g_assert(qdict_haskey(response, "return"));
ret = qdict_get_qdict(response, "return");
qobject_ref(ret);
qobject_unref(response);

return ret;
}

void qtest_vqmp_assert_success(QTestState *qts,
const char *fmt, va_list args)
{
QDict *response;

response = qtest_vqmp_assert_success_ref(qts, fmt, args);

qobject_unref(response);
}

#ifndef _WIN32
QDict *qtest_vqmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
const char *fmt, va_list args)
{
QDict *response;
QDict *ret;

response = qtest_vqmp_fds(qts, fds, nfds, fmt, args);

g_assert(response);
if (!qdict_haskey(response, "return")) {
GString *s = qobject_to_json_pretty(QOBJECT(response), true);
g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(response), true);
g_test_message("%s", s->str);
g_string_free(s, true);
}
g_assert(qdict_haskey(response, "return"));
ret = qdict_get_qdict(response, "return");
qobject_ref(ret);
qobject_unref(response);

return ret;
}

void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
const char *fmt, va_list args)
{
QDict *response;
response = qtest_vqmp_fds_assert_success_ref(qts, fds, nfds, fmt, args);
qobject_unref(response);
}
#endif /* !_WIN32 */

QDict *qtest_qmp_assert_success_ref(QTestState *qts, const char *fmt, ...)
{
QDict *response;
va_list ap;
va_start(ap, fmt);
response = qtest_vqmp_assert_success_ref(qts, fmt, ap);
va_end(ap);
return response;
}

void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
qtest_vqmp_assert_success(qts, fmt, ap);
va_end(ap);
}

#ifndef _WIN32
QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
const char *fmt, ...)
{
QDict *response;
va_list ap;
va_start(ap, fmt);
response = qtest_vqmp_fds_assert_success_ref(qts, fds, nfds, fmt, ap);
va_end(ap);
return response;
}

void qtest_qmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
qtest_vqmp_fds_assert_success(qts, fds, nfds, fmt, ap);
va_end(ap);
}
#endif /* !_WIN32 */

bool qtest_big_endian(QTestState *s)
{
Expand Down
158 changes: 156 additions & 2 deletions tests/qtest/libqtest.h
Expand Up @@ -238,17 +238,52 @@ QDict *qtest_qmp_receive_dict(QTestState *s);
* @s: #QTestState instance to operate on.
*
* Reads a QMP message from QEMU and returns the response.
* Buffers all the events received meanwhile, until a
* call to qtest_qmp_eventwait
*
* If a callback is registered with qtest_qmp_set_event_callback,
* it will be invoked for every event seen, otherwise events
* will be buffered until a call to one of the qtest_qmp_eventwait
* family of functions.
*/
QDict *qtest_qmp_receive(QTestState *s);

/*
* QTestQMPEventCallback:
* @s: #QTestState instance event was received on
* @name: name of the event type
* @event: #QDict for the event details
* @opaque: opaque data from time of callback registration
*
* This callback will be invoked whenever an event is received.
* If the callback returns true the event will be consumed,
* otherwise it will be put on the list of pending events.
* Pending events can be later handled by calling either
* qtest_qmp_eventwait or qtest_qmp_eventwait_ref.
*
* Return: true to consume the event, false to let it be queued
*/
typedef bool (*QTestQMPEventCallback)(QTestState *s, const char *name,
QDict *event, void *opaque);

/**
* qtest_qmp_set_event_callback:
* @s: #QTestSTate instance to operate on
* @cb: callback to invoke for events
* @opaque: data to pass to @cb
*
* Register a callback to be invoked whenever an event arrives
*/
void qtest_qmp_set_event_callback(QTestState *s,
QTestQMPEventCallback cb, void *opaque);

/**
* qtest_qmp_eventwait:
* @s: #QTestState instance to operate on.
* @event: event to wait for.
*
* Continuously polls for QMP responses until it receives the desired event.
*
* Any callback registered with qtest_qmp_set_event_callback will
* be invoked for every event seen.
*/
void qtest_qmp_eventwait(QTestState *s, const char *event);

Expand All @@ -258,6 +293,10 @@ void qtest_qmp_eventwait(QTestState *s, const char *event);
* @event: event to wait for.
*
* Continuously polls for QMP responses until it receives the desired event.
*
* Any callback registered with qtest_qmp_set_event_callback will
* be invoked for every event seen.
*
* Returns a copy of the event for further investigation.
*/
QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
Expand Down Expand Up @@ -693,6 +732,86 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data);
*/
void qtest_remove_abrt_handler(void *data);

/**
* qtest_vqmp_assert_success_ref:
* @qts: QTestState instance to operate on
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @args: variable arguments for @fmt
*
* Sends a QMP message to QEMU, asserts that a 'return' key is present in
* the response, and returns the response.
*/
QDict *qtest_vqmp_assert_success_ref(QTestState *qts,
const char *fmt, va_list args)
G_GNUC_PRINTF(2, 0);

/**
* qtest_vqmp_assert_success:
* @qts: QTestState instance to operate on
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @args: variable arguments for @fmt
*
* Sends a QMP message to QEMU and asserts that a 'return' key is present in
* the response.
*/
void qtest_vqmp_assert_success(QTestState *qts,
const char *fmt, va_list args)
G_GNUC_PRINTF(2, 0);

#ifndef _WIN32
/**
* qtest_vqmp_fds_assert_success_ref:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @args: variable arguments for @fmt
*
* Sends a QMP message with file descriptors to QEMU,
* asserts that a 'return' key is present in the response,
* and returns the response.
*/
QDict *qtest_vqmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
const char *fmt, va_list args)
G_GNUC_PRINTF(4, 0);

/**
* qtest_vqmp_fds_assert_success:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
* @args: variable arguments for @fmt
*
* Sends a QMP message with file descriptors to QEMU and
* asserts that a 'return' key is present in the response.
*/
void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
const char *fmt, va_list args)
G_GNUC_PRINTF(4, 0);
#endif /* !_WIN32 */

/**
* qtest_qmp_assert_success_ref:
* @qts: QTestState instance to operate on
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message to QEMU, asserts that a 'return' key is present in
* the response, and returns the response.
*/
QDict *qtest_qmp_assert_success_ref(QTestState *qts, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);

/**
* qtest_qmp_assert_success:
* @qts: QTestState instance to operate on
Expand All @@ -706,6 +825,41 @@ void qtest_remove_abrt_handler(void *data);
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
G_GNUC_PRINTF(2, 3);

#ifndef _WIN32
/**
* qtest_qmp_fd_assert_success_ref:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message with file descriptors to QEMU,
* asserts that a 'return' key is present in the response,
* and returns the response.
*/
QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
const char *fmt, ...)
G_GNUC_PRINTF(4, 5);

/**
* qtest_qmp_fd_assert_success:
* @qts: QTestState instance to operate on
* @fds: the file descriptors to send
* @nfds: number of @fds to send
* @fmt: QMP message to send to qemu, formatted like
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
* supported after '%'.
*
* Sends a QMP message with file descriptors to QEMU and
* asserts that a 'return' key is present in the response.
*/
void qtest_qmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
const char *fmt, ...)
G_GNUC_PRINTF(4, 5);
#endif /* !_WIN32 */

/**
* qtest_cb_for_every_machine:
* @cb: Pointer to the callback function
Expand Down

0 comments on commit 848a6ca

Please sign in to comment.