From 5357ef823a1f53673eae3e0a9a0d626bc104f8a7 Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Wed, 15 Jan 2025 11:00:45 -0800 Subject: [PATCH] tests/qtest: defer connection Add an option to defer making the connecting to the monitor and qtest sockets when calling qtest_init_with_env. The client makes the connection later by calling qtest_connect and qtest_qmp_handshake. Signed-off-by: Steve Sistare Reviewed-by: Peter Xu Link: https://lore.kernel.org/r/1736967650-129648-20-git-send-email-steven.sistare@oracle.com [plumb capabilities list into qtest_qmp_handshake] Signed-off-by: Fabiano Rosas --- tests/qtest/libqtest.c | 99 ++++++++++++++++++++----------- tests/qtest/libqtest.h | 24 +++++++- tests/qtest/migration/framework.c | 7 ++- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index a1e105f27f..fbb51e3e55 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -75,6 +75,8 @@ struct QTestState { int fd; int qmp_fd; + int sock; + int qmpsock; pid_t qemu_pid; /* our child QEMU process */ int wstatus; #ifdef _WIN32 @@ -458,18 +460,19 @@ static QTestState *G_GNUC_PRINTF(2, 3) qtest_spawn_qemu(const char *qemu_bin, return s; } +static char *qtest_socket_path(const char *suffix) +{ + return g_strdup_printf("%s/qtest-%d.%s", g_get_tmp_dir(), getpid(), suffix); +} + static QTestState *qtest_init_internal(const char *qemu_bin, - const char *extra_args) + const char *extra_args, + bool do_connect) { QTestState *s; int sock, qmpsock, i; - gchar *socket_path; - gchar *qmp_socket_path; - - socket_path = g_strdup_printf("%s/qtest-%d.sock", - g_get_tmp_dir(), getpid()); - qmp_socket_path = g_strdup_printf("%s/qtest-%d.qmp", - g_get_tmp_dir(), getpid()); + g_autofree gchar *socket_path = qtest_socket_path("sock"); + g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp"); /* * It's possible that if an earlier test run crashed it might @@ -501,22 +504,19 @@ static QTestState *qtest_init_internal(const char *qemu_bin, qtest_client_set_rx_handler(s, qtest_client_socket_recv_line); qtest_client_set_tx_handler(s, qtest_client_socket_send); - s->fd = socket_accept(sock); - if (s->fd >= 0) { - s->qmp_fd = socket_accept(qmpsock); - } - unlink(socket_path); - unlink(qmp_socket_path); - g_free(socket_path); - g_free(qmp_socket_path); - - g_assert(s->fd >= 0 && s->qmp_fd >= 0); - s->rx = g_string_new(""); for (i = 0; i < MAX_IRQ; i++) { s->irq_level[i] = false; } + s->fd = -1; + s->qmp_fd = -1; + s->sock = sock; + s->qmpsock = qmpsock; + if (do_connect) { + qtest_connect(s); + } + /* * Stopping QEMU for debugging is not supported on Windows. * @@ -531,28 +531,38 @@ static QTestState *qtest_init_internal(const char *qemu_bin, } #endif - /* ask endianness of the target */ + return s; +} - s->big_endian = qtest_query_target_endianness(s); +void qtest_connect(QTestState *s) +{ + g_autofree gchar *socket_path = qtest_socket_path("sock"); + g_autofree gchar *qmp_socket_path = qtest_socket_path("qmp"); - return s; + g_assert(s->sock >= 0 && s->qmpsock >= 0); + s->fd = socket_accept(s->sock); + if (s->fd >= 0) { + s->qmp_fd = socket_accept(s->qmpsock); + } + unlink(socket_path); + unlink(qmp_socket_path); + g_assert(s->fd >= 0 && s->qmp_fd >= 0); + s->sock = s->qmpsock = -1; + /* ask endianness of the target */ + s->big_endian = qtest_query_target_endianness(s); } QTestState *qtest_init_without_qmp_handshake(const char *extra_args) { - return qtest_init_internal(qtest_qemu_binary(NULL), extra_args); + return qtest_init_internal(qtest_qemu_binary(NULL), extra_args, true); } -QTestState *qtest_init_with_env_and_capabilities(const char *var, - const char *extra_args, - QList *capabilities) +void qtest_qmp_handshake(QTestState *s, QList *capabilities) { - QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args); - QDict *greeting; - /* Read the QMP greeting and then do the handshake */ - greeting = qtest_qmp_receive(s); + QDict *greeting = qtest_qmp_receive(s); qobject_unref(greeting); + if (capabilities) { qtest_qmp_assert_success(s, "{ 'execute': 'qmp_capabilities', " @@ -561,18 +571,37 @@ QTestState *qtest_init_with_env_and_capabilities(const char *var, } else { qtest_qmp_assert_success(s, "{ 'execute': 'qmp_capabilities' }"); } +} + +QTestState *qtest_init_with_env_and_capabilities(const char *var, + const char *extra_args, + QList *capabilities, + bool do_connect) +{ + QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args, + do_connect); + if (do_connect) { + qtest_qmp_handshake(s, capabilities); + } else { + /* + * If the connection is delayed, the capabilities must be set + * at that moment. + */ + assert(!capabilities); + } return s; } -QTestState *qtest_init_with_env(const char *var, const char *extra_args) +QTestState *qtest_init_with_env(const char *var, const char *extra_args, + bool do_connect) { - return qtest_init_with_env_and_capabilities(var, extra_args, NULL); + return qtest_init_with_env_and_capabilities(var, extra_args, NULL, true); } QTestState *qtest_init(const char *extra_args) { - return qtest_init_with_env(NULL, extra_args); + return qtest_init_with_env(NULL, extra_args, true); } QTestState *qtest_vinitf(const char *fmt, va_list ap) @@ -1580,7 +1609,7 @@ static struct MachInfo *qtest_get_machines(const char *var) silence_spawn_log = !g_test_verbose(); - qts = qtest_init_with_env(qemu_var, "-machine none"); + qts = qtest_init_with_env(qemu_var, "-machine none", true); response = qtest_qmp(qts, "{ 'execute': 'query-machines' }"); g_assert(response); list = qdict_get_qlist(response, "return"); @@ -1635,7 +1664,7 @@ static struct CpuModel *qtest_get_cpu_models(void) silence_spawn_log = !g_test_verbose(); - qts = qtest_init_with_env(NULL, "-machine none"); + qts = qtest_init_with_env(NULL, "-machine none", true); response = qtest_qmp(qts, "{ 'execute': 'query-cpu-definitions' }"); g_assert(response); list = qdict_get_qlist(response, "return"); diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index ce88d23eae..29f123e281 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -61,13 +61,15 @@ QTestState *qtest_init(const char *extra_args); * @var: Environment variable from where to take the QEMU binary * @extra_args: Other arguments to pass to QEMU. CAUTION: these * arguments are subject to word splitting and shell evaluation. + * @do_connect: connect to qemu monitor and qtest socket. * * Like qtest_init(), but use a different environment variable for the * QEMU binary. * * Returns: #QTestState instance. */ -QTestState *qtest_init_with_env(const char *var, const char *extra_args); +QTestState *qtest_init_with_env(const char *var, const char *extra_args, + bool do_connect); /** * qtest_init_with_env_and_capabilities: @@ -75,6 +77,7 @@ QTestState *qtest_init_with_env(const char *var, const char *extra_args); * @extra_args: Other arguments to pass to QEMU. CAUTION: these * arguments are subject to word splitting and shell evaluation. * @capabilities: list of QMP capabilities (strings) to enable + * @do_connect: connect to qemu monitor and qtest socket. * * Like qtest_init_with_env(), but enable specified capabilities during * hadshake. @@ -83,7 +86,8 @@ QTestState *qtest_init_with_env(const char *var, const char *extra_args); */ QTestState *qtest_init_with_env_and_capabilities(const char *var, const char *extra_args, - QList *capabilities); + QList *capabilities, + bool do_connect); /** * qtest_init_without_qmp_handshake: @@ -94,6 +98,22 @@ QTestState *qtest_init_with_env_and_capabilities(const char *var, */ QTestState *qtest_init_without_qmp_handshake(const char *extra_args); +/** + * qtest_connect + * @s: #QTestState instance to connect + * Connect to qemu monitor and qtest socket, after skipping them in + * qtest_init_with_env. Does not handshake with the monitor. + */ +void qtest_connect(QTestState *s); + +/** + * qtest_qmp_handshake: + * @s: #QTestState instance to operate on. + * @capabilities: list of QMP capabilities (strings) to enable + * Perform handshake after connecting to qemu monitor. + */ +void qtest_qmp_handshake(QTestState *s, QList *capabilities); + /** * qtest_init_with_serial: * @extra_args: other arguments to pass to QEMU. CAUTION: these diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index 758e14abab..f7add75ed5 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -196,9 +196,10 @@ static void cleanup(const char *filename) static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args) { - QList *capabilities = qlist_new(); + QList *capabilities = NULL; if (args->oob) { + capabilities = qlist_new(); qlist_append_str(capabilities, "oob"); } return capabilities; @@ -333,7 +334,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri, ignore_stderr); if (!args->only_target) { *from = qtest_init_with_env_and_capabilities(QEMU_ENV_SRC, cmd_source, - capabilities); + capabilities, true); qtest_qmp_set_event_callback(*from, migrate_watch_for_events, &src_state); @@ -354,7 +355,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri, args->opts_target ? args->opts_target : "", ignore_stderr); *to = qtest_init_with_env_and_capabilities(QEMU_ENV_DST, cmd_target, - capabilities); + capabilities, true); qtest_qmp_set_event_callback(*to, migrate_watch_for_events, &dst_state); -- 2.30.2