Stefan Hajnoczi ffaf7f0376 testing and gdbstub updates:
- add a check-rust test to docker builds
   - re-factor the qtest logic to be cleaner
   - fix tests to not clock_step when no timers enabled
   - roll-up log prefix into qtest_send
   - cleaner error reporting when qtest_clock_set fails
   - revert old deadlock fix now tests are updated
   - only run full set of migration tests under HW acceleration
   - support late attachment to user-mode gdbstubs
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmeqBSsACgkQ+9DbCVqe
 KkQS/Af+K0hpdGc1msiuMsqmuESBvhoQniYZFLN1/pwe2KpG8i/+fq2fsCuxJhJ1
 2TzPH7aj54p9MGCZf2k9JLhO22XldN+oezZMc1crhoWK0AtrWhnLs58I2oEPIsUo
 NmGO6Zfm98ge89o2y8GCvd0QXAtUf+jduDKnW0mfnOnw+w/mky5KzWS7/1091VGW
 42LSY4KnqgdLSqLyuLBOrgADEjB1ChWS4/bSC+kEYSGrmNQB+n1KeIzzlJBGpOr0
 Z9yzmhMCm7TWdkFNPmnVfYH/7ZUNcpv6PtQSpkku4f6b/gybyvJBknHpM4i+Gpb5
 87wSjljrCpdNm/9KFRjiJuUWdS/jCg==
 =UF0n
 -----END PGP SIGNATURE-----

Merge tag 'pull-10.0-testing-and-gdstub-updates-100225-1' of https://gitlab.com/stsquad/qemu into staging

testing and gdbstub updates:

  - add a check-rust test to docker builds
  - re-factor the qtest logic to be cleaner
  - fix tests to not clock_step when no timers enabled
  - roll-up log prefix into qtest_send
  - cleaner error reporting when qtest_clock_set fails
  - revert old deadlock fix now tests are updated
  - only run full set of migration tests under HW acceleration
  - support late attachment to user-mode gdbstubs

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmeqBSsACgkQ+9DbCVqe
# KkQS/Af+K0hpdGc1msiuMsqmuESBvhoQniYZFLN1/pwe2KpG8i/+fq2fsCuxJhJ1
# 2TzPH7aj54p9MGCZf2k9JLhO22XldN+oezZMc1crhoWK0AtrWhnLs58I2oEPIsUo
# NmGO6Zfm98ge89o2y8GCvd0QXAtUf+jduDKnW0mfnOnw+w/mky5KzWS7/1091VGW
# 42LSY4KnqgdLSqLyuLBOrgADEjB1ChWS4/bSC+kEYSGrmNQB+n1KeIzzlJBGpOr0
# Z9yzmhMCm7TWdkFNPmnVfYH/7ZUNcpv6PtQSpkku4f6b/gybyvJBknHpM4i+Gpb5
# 87wSjljrCpdNm/9KFRjiJuUWdS/jCg==
# =UF0n
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 10 Feb 2025 08:54:51 EST
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.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: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* tag 'pull-10.0-testing-and-gdstub-updates-100225-1' of https://gitlab.com/stsquad/qemu:
  tests/tcg: Add late gdbstub attach test
  docs/user: Document the %d placeholder and suspend=n QEMU_GDB features
  gdbstub: Allow late attachment
  osdep: Introduce qemu_kill_thread()
  user: Introduce host_interrupt_signal
  user: Introduce user/signal.h
  gdbstub: Try unlinking the unix socket before binding
  gdbstub: Allow the %d placeholder in the socket path
  tests/qtest/migration: Pick smoke tests
  tests/qtest/migration: Add --full option
  Revert "util/timer: avoid deadlock when shutting down"
  tests/qtest: tighten up the checks on clock_step
  tests/qtest: rename qtest_send_prefix and roll-up into qtest_send
  tests/qtest: simplify qtest_process_inbuf
  tests/qtest: don't step clock at start of npcm7xx periodic IRQ test
  tests/qtest: don't attempt to clock_step while waiting for virtio ISR
  tests/docker: replicate the check-rust-tools-nightly CI job

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2025-02-10 13:26:17 -05:00

300 lines
8.0 KiB
C

/*
* QTest testcases for migration
*
* Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
* based on the vhost-user-test.c that is:
* Copyright (c) 2014 Virtual Open Systems Sarl.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qobject/qjson.h"
#include "libqtest.h"
#include "migration/framework.h"
#include "migration/migration-qmp.h"
#include "migration/migration-util.h"
#define ANALYZE_SCRIPT "scripts/analyze-migration.py"
static char *tmpfs;
static void test_baddest(void)
{
MigrateStart args = {
.hide_stderr = true
};
QTestState *from, *to;
if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
return;
}
migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}");
wait_for_migration_fail(from, false);
migrate_end(from, to, false);
}
#ifndef _WIN32
static void test_analyze_script(void)
{
MigrateStart args = {
.opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
};
QTestState *from, *to;
g_autofree char *uri = NULL;
g_autofree char *file = NULL;
int pid, wstatus;
const char *python = g_getenv("PYTHON");
if (!python) {
g_test_skip("PYTHON variable not set");
return;
}
/* dummy url */
if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args)) {
return;
}
/*
* Setting these two capabilities causes the "configuration"
* vmstate to include subsections for them. The script needs to
* parse those subsections properly.
*/
migrate_set_capability(from, "validate-uuid", true);
migrate_set_capability(from, "x-ignore-shared", true);
file = g_strdup_printf("%s/migfile", tmpfs);
uri = g_strdup_printf("exec:cat > %s", file);
migrate_ensure_converge(from);
migrate_qmp(from, to, uri, NULL, "{}");
wait_for_migration_complete(from);
pid = fork();
if (!pid) {
close(1);
open("/dev/null", O_WRONLY);
execl(python, python, ANALYZE_SCRIPT, "-f", file, NULL);
g_assert_not_reached();
}
g_assert(waitpid(pid, &wstatus, 0) == pid);
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
g_test_message("Failed to analyze the migration stream");
g_test_fail();
}
migrate_end(from, to, false);
unlink(file);
}
#endif
static void test_ignore_shared(void)
{
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
MigrateStart args = {
.use_shmem = true,
};
if (migrate_start(&from, &to, uri, &args)) {
return;
}
migrate_ensure_non_converge(from);
migrate_prepare_for_dirty_mem(from);
migrate_set_capability(from, "x-ignore-shared", true);
migrate_set_capability(to, "x-ignore-shared", true);
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
migrate_qmp(from, to, uri, NULL, "{}");
migrate_wait_for_dirty_mem(from, to);
wait_for_stop(from, get_src());
qtest_qmp_eventwait(to, "RESUME");
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
/* Check whether shared RAM has been really skipped */
g_assert_cmpint(
read_ram_property_int(from, "transferred"), <, 4 * 1024 * 1024);
migrate_end(from, to, true);
}
static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
{
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
if (migrate_start(&from, &to, uri, args)) {
return;
}
/*
* UUID validation is at the begin of migration. So, the main process of
* migration is not interesting for us here. Thus, set huge downtime for
* very fast migration.
*/
migrate_set_parameter_int(from, "downtime-limit", 1000000);
migrate_set_capability(from, "validate-uuid", true);
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
migrate_qmp(from, to, uri, NULL, "{}");
if (should_fail) {
qtest_set_expected_status(to, EXIT_FAILURE);
wait_for_migration_fail(from, true);
} else {
wait_for_migration_complete(from);
}
migrate_end(from, to, false);
}
static void test_validate_uuid(void)
{
MigrateStart args = {
.opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
.opts_target = "-uuid 11111111-1111-1111-1111-111111111111",
};
do_test_validate_uuid(&args, false);
}
static void test_validate_uuid_error(void)
{
MigrateStart args = {
.opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
.opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
.hide_stderr = true,
};
do_test_validate_uuid(&args, true);
}
static void test_validate_uuid_src_not_set(void)
{
MigrateStart args = {
.opts_target = "-uuid 22222222-2222-2222-2222-222222222222",
.hide_stderr = true,
};
do_test_validate_uuid(&args, false);
}
static void test_validate_uuid_dst_not_set(void)
{
MigrateStart args = {
.opts_source = "-uuid 11111111-1111-1111-1111-111111111111",
.hide_stderr = true,
};
do_test_validate_uuid(&args, false);
}
static void do_test_validate_uri_channel(MigrateCommon *args)
{
QTestState *from, *to;
QObject *channels;
if (migrate_start(&from, &to, args->listen_uri, &args->start)) {
return;
}
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
/*
* 'uri' and 'channels' validation is checked even before the migration
* starts.
*/
channels = args->connect_channels ?
qobject_from_json(args->connect_channels, &error_abort) :
NULL;
migrate_qmp_fail(from, args->connect_uri, channels, "{}");
migrate_end(from, to, false);
}
static void test_validate_uri_channels_both_set(void)
{
MigrateCommon args = {
.start = {
.hide_stderr = true,
},
.listen_uri = "defer",
.connect_uri = "tcp:127.0.0.1:0",
.connect_channels = ("[ { ""'channel-type': 'main',"
" 'addr': { 'transport': 'socket',"
" 'type': 'inet',"
" 'host': '127.0.0.1',"
" 'port': '0' } } ]"),
};
do_test_validate_uri_channel(&args);
}
static void test_validate_uri_channels_none_set(void)
{
MigrateCommon args = {
.start = {
.hide_stderr = true,
},
.listen_uri = "defer",
};
do_test_validate_uri_channel(&args);
}
static void migration_test_add_misc_smoke(MigrationTestEnv *env)
{
#ifndef _WIN32
migration_test_add("/migration/analyze-script", test_analyze_script);
#endif
}
void migration_test_add_misc(MigrationTestEnv *env)
{
tmpfs = env->tmpfs;
migration_test_add_misc_smoke(env);
if (!env->full_set) {
return;
}
migration_test_add("/migration/bad_dest", test_baddest);
/*
* Our CI system has problems with shared memory.
* Don't run this test until we find a workaround.
*/
if (getenv("QEMU_TEST_FLAKY_TESTS")) {
migration_test_add("/migration/ignore-shared", test_ignore_shared);
}
migration_test_add("/migration/validate_uuid", test_validate_uuid);
migration_test_add("/migration/validate_uuid_error",
test_validate_uuid_error);
migration_test_add("/migration/validate_uuid_src_not_set",
test_validate_uuid_src_not_set);
migration_test_add("/migration/validate_uuid_dst_not_set",
test_validate_uuid_dst_not_set);
migration_test_add("/migration/validate_uri/channels/both_set",
test_validate_uri_channels_both_set);
migration_test_add("/migration/validate_uri/channels/none_set",
test_validate_uri_channels_none_set);
}