mirror of
https://github.com/qemu/qemu.git
synced 2026-05-06 20:38:55 +00:00
With the upcoming addition of the config QDict, the tests will need a better way of managing the memory of the test data than putting the test arguments on the stack of the test functions. The config QDict will need to be merged into the arguments of migrate_qmp* functions, which causes a refcount increment, so the test functions would need to allocate and deref the config QDict themselves. A better approach is to already pass the arguments into the test functions and do the memory management in the existing wrapper. There is already migration_test_destroy(), which is called for every test. Do the following: - merge the two existing wrappers, migration_test_wrapper() and migration_test_wrapper_full(). The latter was pioneer in passing data into the tests, but now all tests will receive data, so we don't need it anymore. The usage of migration_test_wrapper_full() was in passing a slightly different test name string into the cancel tests, so still keep the migration_test_add_suffix() function. - add (char *name, MigrateCommon *args) to the signature of all test functions. - alter any code to stop allocating args on the stack and instead use the object that came as parameter. - pass args around as needed. - while here, order args (MigrateCommon) before args->start (MigrateStart) and put a blank like in between. No functional change. Signed-off-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20251215220041.12657-26-farosas@suse.de [peterx: fix a conflict with newly added mapped-ram+ignore-share test] Signed-off-by: Peter Xu <peterx@redhat.com>
280 lines
8.0 KiB
C
280 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(char *name, MigrateCommon *args)
|
|
{
|
|
QTestState *from, *to;
|
|
|
|
args->start.hide_stderr = true;
|
|
|
|
if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
|
|
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(char *name, MigrateCommon *args)
|
|
{
|
|
QTestState *from, *to;
|
|
g_autofree char *uri = NULL;
|
|
g_autofree char *file = NULL;
|
|
int pid, wstatus;
|
|
const char *python = g_getenv("PYTHON");
|
|
|
|
args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
|
|
|
|
if (!python) {
|
|
g_test_skip("PYTHON variable not set");
|
|
return;
|
|
}
|
|
|
|
/* dummy url */
|
|
if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) {
|
|
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(char *name, MigrateCommon *args)
|
|
{
|
|
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
|
QTestState *from, *to;
|
|
|
|
args->start.mem_type = MEM_TYPE_SHMEM;
|
|
args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true;
|
|
|
|
if (migrate_start(&from, &to, uri, &args->start)) {
|
|
return;
|
|
}
|
|
|
|
migrate_ensure_non_converge(from);
|
|
migrate_prepare_for_dirty_mem(from);
|
|
|
|
/* 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(char *name, MigrateCommon *args)
|
|
{
|
|
args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
|
|
args->start.opts_target = "-uuid 11111111-1111-1111-1111-111111111111";
|
|
|
|
do_test_validate_uuid(&args->start, false);
|
|
}
|
|
|
|
static void test_validate_uuid_error(char *name, MigrateCommon *args)
|
|
{
|
|
args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
|
|
args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
|
|
args->start.hide_stderr = true;
|
|
|
|
do_test_validate_uuid(&args->start, true);
|
|
}
|
|
|
|
static void test_validate_uuid_src_not_set(char *name, MigrateCommon *args)
|
|
{
|
|
args->start.opts_target = "-uuid 22222222-2222-2222-2222-222222222222";
|
|
args->start.hide_stderr = true;
|
|
|
|
do_test_validate_uuid(&args->start, false);
|
|
}
|
|
|
|
static void test_validate_uuid_dst_not_set(char *name, MigrateCommon *args)
|
|
{
|
|
args->start.opts_source = "-uuid 11111111-1111-1111-1111-111111111111";
|
|
args->start.hide_stderr = true;
|
|
|
|
do_test_validate_uuid(&args->start, 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(char *name, MigrateCommon *args)
|
|
{
|
|
args->listen_uri = "defer",
|
|
args->connect_uri = "tcp:127.0.0.1:0",
|
|
args->connect_channels = ("[ { ""'channel-type': 'main',"
|
|
" 'addr': { 'transport': 'socket',"
|
|
" 'type': 'inet',"
|
|
" 'host': '127.0.0.1',"
|
|
" 'port': '0' } } ]"),
|
|
|
|
args->start.hide_stderr = true;
|
|
|
|
do_test_validate_uri_channel(args);
|
|
}
|
|
|
|
static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args)
|
|
{
|
|
args->listen_uri = "defer";
|
|
args->start.hide_stderr = true;
|
|
|
|
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);
|
|
}
|