We current have a bunch of non-test functions in migration-test.c and
some others in migration-helpers.c. In order to split migration-test.c
into separate test binaries, these helpers need to go somewhere
else.
To avoid making migration-helpers even larger, move all QMP-related
functions into a new migration-qmp.c file and put it under the
qtest/migration/ directory.
The new file holds everything that has as its main responsibility to
call into QMP.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
tests/qtest/meson.build | 1 +
tests/qtest/migration-helpers.c | 250 +------------
tests/qtest/migration-helpers.h | 18 +-
tests/qtest/migration-test.c | 237 +-----------
tests/qtest/migration/migration-qmp.c | 485 +++++++++++++++++++++++++
tests/qtest/migration/migration-util.h | 45 +++
tests/qtest/virtio-net-failover.c | 1 +
7 files changed, 541 insertions(+), 496 deletions(-)
create mode 100644 tests/qtest/migration/migration-qmp.c
create mode 100644 tests/qtest/migration/migration-util.h
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index f6001a0b0f..30dff3abe0 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -331,6 +331,7 @@ tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c']
migration_files = [files(
'migration-helpers.c',
'migration/bootfile.c',
+ 'migration/migration-qmp.c',
)]
if gnutls.found()
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index 2786f9c860..218ee4e59f 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "qemu/ctype.h"
-#include "qapi/qmp/qjson.h"
#include "qapi/qapi-visit-sockets.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/error.h"
@@ -23,14 +22,6 @@
#include "migration-helpers.h"
#include "migration/bootfile.h"
-/*
- * Number of seconds we wait when looking for migration
- * status changes, to avoid test suite hanging forever
- * when things go wrong. Needs to be higher enough to
- * avoid false positives on loaded hosts.
- */
-#define MIGRATION_STATUS_WAIT_TIMEOUT 120
-
static char *SocketAddress_to_str(SocketAddress *addr)
{
switch (addr->type) {
@@ -100,8 +91,7 @@ static SocketAddressList *migrate_get_socket_address(QTestState *who)
return addrs;
}
-static char *
-migrate_get_connect_uri(QTestState *who)
+char *migrate_get_connect_uri(QTestState *who)
{
SocketAddressList *addrs;
char *connect_uri;
@@ -126,7 +116,7 @@ migrate_get_connect_qdict(QTestState *who)
return connect_qdict;
}
-static void migrate_set_ports(QTestState *to, QList *channel_list)
+void migrate_set_ports(QTestState *to, QList *channel_list)
{
QDict *addr;
QListEntry *entry;
@@ -168,222 +158,6 @@ bool migrate_watch_for_events(QTestState *who, const char *name,
return false;
}
-void migrate_qmp_fail(QTestState *who, const char *uri,
- const char *channels, const char *fmt, ...)
-{
- va_list ap;
- QDict *args, *err;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- if (uri) {
- qdict_put_str(args, "uri", uri);
- }
-
- g_assert(!qdict_haskey(args, "channels"));
- if (channels) {
- QObject *channels_obj = qobject_from_json(channels, &error_abort);
- qdict_put_obj(args, "channels", channels_obj);
- }
-
- err = qtest_qmp_assert_failure_ref(
- who, "{ 'execute': 'migrate', 'arguments': %p}", args);
-
- g_assert(qdict_haskey(err, "desc"));
-
- qobject_unref(err);
-}
-
-/*
- * Send QMP command "migrate".
- * Arguments are built from @fmt... (formatted like
- * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
- */
-void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
- const char *channels, const char *fmt, ...)
-{
- va_list ap;
- QDict *args;
- g_autofree char *connect_uri = NULL;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- if (uri) {
- qdict_put_str(args, "uri", uri);
- } else if (!channels) {
- connect_uri = migrate_get_connect_uri(to);
- qdict_put_str(args, "uri", connect_uri);
- }
-
- g_assert(!qdict_haskey(args, "channels"));
- if (channels) {
- QObject *channels_obj = qobject_from_json(channels, &error_abort);
- QList *channel_list = qobject_to(QList, channels_obj);
- migrate_set_ports(to, channel_list);
- qdict_put_obj(args, "channels", channels_obj);
- }
-
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate', 'arguments': %p}", args);
-}
-
-void migrate_set_capability(QTestState *who, const char *capability,
- bool value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-capabilities',"
- "'arguments': { "
- "'capabilities': [ { "
- "'capability': %s, 'state': %i } ] } }",
- capability, value);
-}
-
-void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...)
-{
- va_list ap;
- QDict *args, *rsp;
-
- va_start(ap, fmt);
- args = qdict_from_vjsonf_nofail(fmt, ap);
- va_end(ap);
-
- g_assert(!qdict_haskey(args, "uri"));
- qdict_put_str(args, "uri", uri);
-
- /* This function relies on the event to work, make sure it's enabled */
- migrate_set_capability(to, "events", true);
-
- rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
- args);
-
- if (!qdict_haskey(rsp, "return")) {
- g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
- g_test_message("%s", s->str);
- }
-
- g_assert(qdict_haskey(rsp, "return"));
- qobject_unref(rsp);
-
- migration_event_wait(to, "setup");
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * qobject_unref() after use
- */
-QDict *migrate_query(QTestState *who)
-{
- return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
-}
-
-QDict *migrate_query_not_failed(QTestState *who)
-{
- const char *status;
- QDict *rsp = migrate_query(who);
- status = qdict_get_str(rsp, "status");
- if (g_str_equal(status, "failed")) {
- g_printerr("query-migrate shows failed migration: %s\n",
- qdict_get_str(rsp, "error-desc"));
- }
- g_assert(!g_str_equal(status, "failed"));
- return rsp;
-}
-
-/*
- * Note: caller is responsible to free the returned object via
- * g_free() after use
- */
-static gchar *migrate_query_status(QTestState *who)
-{
- QDict *rsp_return = migrate_query(who);
- gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
-
- g_assert(status);
- qobject_unref(rsp_return);
-
- return status;
-}
-
-static bool check_migration_status(QTestState *who, const char *goal,
- const char **ungoals)
-{
- bool ready;
- char *current_status;
- const char **ungoal;
-
- current_status = migrate_query_status(who);
- ready = strcmp(current_status, goal) == 0;
- if (!ungoals) {
- g_assert_cmpstr(current_status, !=, "failed");
- /*
- * If looking for a state other than completed,
- * completion of migration would cause the test to
- * hang.
- */
- if (strcmp(goal, "completed") != 0) {
- g_assert_cmpstr(current_status, !=, "completed");
- }
- } else {
- for (ungoal = ungoals; *ungoal; ungoal++) {
- g_assert_cmpstr(current_status, !=, *ungoal);
- }
- }
- g_free(current_status);
- return ready;
-}
-
-void wait_for_migration_status(QTestState *who,
- const char *goal, const char **ungoals)
-{
- g_test_timer_start();
- while (!check_migration_status(who, goal, ungoals)) {
- usleep(1000);
-
- g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
- }
-}
-
-void wait_for_migration_complete(QTestState *who)
-{
- wait_for_migration_status(who, "completed", NULL);
-}
-
-void wait_for_migration_fail(QTestState *from, bool allow_active)
-{
- g_test_timer_start();
- QDict *rsp_return;
- char *status;
- bool failed;
-
- do {
- status = migrate_query_status(from);
- bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
- (allow_active && !strcmp(status, "active"));
- if (!result) {
- fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
- __func__, status, allow_active);
- }
- g_assert(result);
- failed = !strcmp(status, "failed");
- g_free(status);
-
- g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
- } while (!failed);
-
- /* Is the machine currently running? */
- rsp_return = qtest_qmp_assert_success_ref(from,
- "{ 'execute': 'query-status' }");
- g_assert(qdict_haskey(rsp_return, "running"));
- g_assert(qdict_get_bool(rsp_return, "running"));
- qobject_unref(rsp_return);
-}
-
char *find_common_machine_version(const char *mtype, const char *var1,
const char *var2)
{
@@ -509,23 +283,3 @@ bool probe_o_direct_support(const char *tmpfs)
return true;
}
#endif
-
-/*
- * Wait for a "MIGRATION" event. This is what Libvirt uses to track
- * migration status changes.
- */
-void migration_event_wait(QTestState *s, const char *target)
-{
- QDict *response, *data;
- const char *status;
- bool found;
-
- do {
- response = qtest_qmp_eventwait_ref(s, "MIGRATION");
- data = qdict_get_qdict(response, "data");
- g_assert(data);
- status = qdict_get_str(data, "status");
- found = (strcmp(status, target) == 0);
- qobject_unref(response);
- } while (!found);
-}
diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h
index 72dba369fb..2cb1f78d9e 100644
--- a/tests/qtest/migration-helpers.h
+++ b/tests/qtest/migration-helpers.h
@@ -25,21 +25,6 @@ typedef struct QTestMigrationState {
bool migrate_watch_for_events(QTestState *who, const char *name,
QDict *event, void *opaque);
-G_GNUC_PRINTF(5, 6)
-void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
- const char *channels, const char *fmt, ...);
-
-G_GNUC_PRINTF(3, 4)
-void migrate_incoming_qmp(QTestState *who, const char *uri,
- const char *fmt, ...);
-
-G_GNUC_PRINTF(4, 5)
-void migrate_qmp_fail(QTestState *who, const char *uri,
- const char *channels, const char *fmt, ...);
-
-void migrate_set_capability(QTestState *who, const char *capability,
- bool value);
-
QDict *migrate_query(QTestState *who);
QDict *migrate_query_not_failed(QTestState *who);
@@ -63,6 +48,7 @@ static inline bool probe_o_direct_support(const char *tmpfs)
}
#endif
void migration_test_add(const char *path, void (*fn)(void));
-void migration_event_wait(QTestState *s, const char *target);
+char *migrate_get_connect_uri(QTestState *who);
+void migrate_set_ports(QTestState *to, QList *channel_list);
#endif /* MIGRATION_HELPERS_H */
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 599adc422c..f55423467d 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -13,18 +13,18 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/range.h"
#include "qemu/sockets.h"
#include "chardev/char.h"
#include "crypto/tlscredspsk.h"
-#include "qapi/qmp/qlist.h"
#include "ppc-util.h"
#include "migration-helpers.h"
#include "migration/bootfile.h"
+#include "migration/migration-util.h"
#ifdef CONFIG_GNUTLS
# include "tests/unit/crypto-tls-psk-helpers.h"
# ifdef CONFIG_TASN1
@@ -170,89 +170,6 @@ static void wait_for_serial(const char *side)
} while (true);
}
-static void wait_for_stop(QTestState *who, QTestMigrationState *state)
-{
- if (!state->stop_seen) {
- qtest_qmp_eventwait(who, "STOP");
- }
-}
-
-static void wait_for_resume(QTestState *who, QTestMigrationState *state)
-{
- if (!state->resume_seen) {
- qtest_qmp_eventwait(who, "RESUME");
- }
-}
-
-static void wait_for_suspend(QTestState *who, QTestMigrationState *state)
-{
- if (state->suspend_me && !state->suspend_seen) {
- qtest_qmp_eventwait(who, "SUSPEND");
- }
-}
-
-/*
- * It's tricky to use qemu's migration event capability with qtest,
- * events suddenly appearing confuse the qmp()/hmp() responses.
- */
-
-static int64_t read_ram_property_int(QTestState *who, const char *property)
-{
- QDict *rsp_return, *rsp_ram;
- int64_t result;
-
- rsp_return = migrate_query_not_failed(who);
- if (!qdict_haskey(rsp_return, "ram")) {
- /* Still in setup */
- result = 0;
- } else {
- rsp_ram = qdict_get_qdict(rsp_return, "ram");
- result = qdict_get_try_int(rsp_ram, property, 0);
- }
- qobject_unref(rsp_return);
- return result;
-}
-
-static int64_t read_migrate_property_int(QTestState *who, const char *property)
-{
- QDict *rsp_return;
- int64_t result;
-
- rsp_return = migrate_query_not_failed(who);
- result = qdict_get_try_int(rsp_return, property, 0);
- qobject_unref(rsp_return);
- return result;
-}
-
-static uint64_t get_migration_pass(QTestState *who)
-{
- return read_ram_property_int(who, "dirty-sync-count");
-}
-
-static void read_blocktime(QTestState *who)
-{
- QDict *rsp_return;
-
- rsp_return = migrate_query_not_failed(who);
- g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
- qobject_unref(rsp_return);
-}
-
-/*
- * Wait for two changes in the migration pass count, but bail if we stop.
- */
-static void wait_for_migration_pass(QTestState *who)
-{
- uint64_t pass, prev_pass = 0, changes = 0;
-
- while (changes < 2 && !src_state.stop_seen && !src_state.suspend_seen) {
- usleep(1000);
- pass = get_migration_pass(who);
- changes += (pass != prev_pass);
- prev_pass = pass;
- }
-}
-
static void check_guests_ram(QTestState *who)
{
/* Our ASM test will have been incrementing one byte from each page from
@@ -308,114 +225,6 @@ static void cleanup(const char *filename)
unlink(path);
}
-static long long migrate_get_parameter_int(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- long long result;
-
- rsp = qtest_qmp_assert_success_ref(
- who, "{ 'execute': 'query-migrate-parameters' }");
- result = qdict_get_int(rsp, parameter);
- qobject_unref(rsp);
- return result;
-}
-
-static void migrate_check_parameter_int(QTestState *who, const char *parameter,
- long long value)
-{
- long long result;
-
- result = migrate_get_parameter_int(who, parameter);
- g_assert_cmpint(result, ==, value);
-}
-
-static void migrate_set_parameter_int(QTestState *who, const char *parameter,
- long long value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %lld } }",
- parameter, value);
- migrate_check_parameter_int(who, parameter, value);
-}
-
-static char *migrate_get_parameter_str(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- char *result;
-
- rsp = qtest_qmp_assert_success_ref(
- who, "{ 'execute': 'query-migrate-parameters' }");
- result = g_strdup(qdict_get_str(rsp, parameter));
- qobject_unref(rsp);
- return result;
-}
-
-static void migrate_check_parameter_str(QTestState *who, const char *parameter,
- const char *value)
-{
- g_autofree char *result = migrate_get_parameter_str(who, parameter);
- g_assert_cmpstr(result, ==, value);
-}
-
-static void migrate_set_parameter_str(QTestState *who, const char *parameter,
- const char *value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %s } }",
- parameter, value);
- migrate_check_parameter_str(who, parameter, value);
-}
-
-static long long migrate_get_parameter_bool(QTestState *who,
- const char *parameter)
-{
- QDict *rsp;
- int result;
-
- rsp = qtest_qmp_assert_success_ref(
- who, "{ 'execute': 'query-migrate-parameters' }");
- result = qdict_get_bool(rsp, parameter);
- qobject_unref(rsp);
- return !!result;
-}
-
-static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
- int value)
-{
- int result;
-
- result = migrate_get_parameter_bool(who, parameter);
- g_assert_cmpint(result, ==, value);
-}
-
-static void migrate_set_parameter_bool(QTestState *who, const char *parameter,
- int value)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-set-parameters',"
- "'arguments': { %s: %i } }",
- parameter, value);
- migrate_check_parameter_bool(who, parameter, value);
-}
-
-static void migrate_ensure_non_converge(QTestState *who)
-{
- /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 1);
-}
-
-static void migrate_ensure_converge(QTestState *who)
-{
- /* Should converge with 30s downtime + 1 gbs bandwidth limit */
- migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
- migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
-}
-
/*
* Our goal is to ensure that we run a single full migration
* iteration, and also dirty memory, ensuring that at least
@@ -506,42 +315,6 @@ static void migrate_wait_for_dirty_mem(QTestState *from,
} while (qtest_readb(from, watch_address) == watch_byte);
}
-
-static void migrate_pause(QTestState *who)
-{
- qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
-}
-
-static void migrate_continue(QTestState *who, const char *state)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-continue',"
- " 'arguments': { 'state': %s } }",
- state);
-}
-
-static void migrate_recover(QTestState *who, const char *uri)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'migrate-recover', "
- " 'id': 'recover-cmd', "
- " 'arguments': { 'uri': %s } }",
- uri);
-}
-
-static void migrate_cancel(QTestState *who)
-{
- qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
-}
-
-static void migrate_postcopy_start(QTestState *from, QTestState *to)
-{
- qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
-
- wait_for_stop(from, &src_state);
- qtest_qmp_eventwait(to, "RESUME");
-}
-
typedef struct {
/*
* QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors
@@ -1277,7 +1050,7 @@ static void test_postcopy_common(MigrateCommon *args)
if (migrate_postcopy_prepare(&from, &to, args)) {
return;
}
- migrate_postcopy_start(from, to);
+ migrate_postcopy_start(from, to, &src_state);
migrate_postcopy_complete(from, to, args);
}
@@ -1464,7 +1237,7 @@ static void test_postcopy_recovery_common(MigrateCommon *args)
migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096);
/* Now we start the postcopy */
- migrate_postcopy_start(from, to);
+ migrate_postcopy_start(from, to, &src_state);
/*
* Wait until postcopy is really started; we can only run the
@@ -1704,7 +1477,7 @@ static void test_precopy_common(MigrateCommon *args)
* for some dirty mem before switching to converge
*/
while (args->iterations > 1) {
- wait_for_migration_pass(from);
+ wait_for_migration_pass(from, &src_state);
args->iterations--;
}
migrate_wait_for_dirty_mem(from, to);
diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c
new file mode 100644
index 0000000000..89e069e96b
--- /dev/null
+++ b/tests/qtest/migration/migration-qmp.c
@@ -0,0 +1,485 @@
+/*
+ * QTest QMP helpers 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 "libqtest.h"
+#include "migration-helpers.h"
+#include "migration-util.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qlist.h"
+
+/*
+ * Number of seconds we wait when looking for migration
+ * status changes, to avoid test suite hanging forever
+ * when things go wrong. Needs to be higher enough to
+ * avoid false positives on loaded hosts.
+ */
+#define MIGRATION_STATUS_WAIT_TIMEOUT 120
+
+/*
+ * Wait for a "MIGRATION" event. This is what Libvirt uses to track
+ * migration status changes.
+ */
+void migration_event_wait(QTestState *s, const char *target)
+{
+ QDict *response, *data;
+ const char *status;
+ bool found;
+
+ do {
+ response = qtest_qmp_eventwait_ref(s, "MIGRATION");
+ data = qdict_get_qdict(response, "data");
+ g_assert(data);
+ status = qdict_get_str(data, "status");
+ found = (strcmp(status, target) == 0);
+ qobject_unref(response);
+ } while (!found);
+}
+
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ const char *channels, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args, *err;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ QObject *channels_obj = qobject_from_json(channels, &error_abort);
+ qdict_put_obj(args, "channels", channels_obj);
+ }
+
+ err = qtest_qmp_assert_failure_ref(
+ who, "{ 'execute': 'migrate', 'arguments': %p}", args);
+
+ g_assert(qdict_haskey(err, "desc"));
+
+ qobject_unref(err);
+}
+
+/*
+ * Send QMP command "migrate".
+ * Arguments are built from @fmt... (formatted like
+ * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
+ */
+void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
+ const char *channels, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args;
+ g_autofree char *connect_uri = NULL;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ if (uri) {
+ qdict_put_str(args, "uri", uri);
+ } else if (!channels) {
+ connect_uri = migrate_get_connect_uri(to);
+ qdict_put_str(args, "uri", connect_uri);
+ }
+
+ g_assert(!qdict_haskey(args, "channels"));
+ if (channels) {
+ QObject *channels_obj = qobject_from_json(channels, &error_abort);
+ QList *channel_list = qobject_to(QList, channels_obj);
+ migrate_set_ports(to, channel_list);
+ qdict_put_obj(args, "channels", channels_obj);
+ }
+
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate', 'arguments': %p}", args);
+}
+
+void migrate_set_capability(QTestState *who, const char *capability,
+ bool value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-capabilities',"
+ "'arguments': { "
+ "'capabilities': [ { "
+ "'capability': %s, 'state': %i } ] } }",
+ capability, value);
+}
+
+void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...)
+{
+ va_list ap;
+ QDict *args, *rsp;
+
+ va_start(ap, fmt);
+ args = qdict_from_vjsonf_nofail(fmt, ap);
+ va_end(ap);
+
+ g_assert(!qdict_haskey(args, "uri"));
+ qdict_put_str(args, "uri", uri);
+
+ /* This function relies on the event to work, make sure it's enabled */
+ migrate_set_capability(to, "events", true);
+
+ rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
+ args);
+
+ if (!qdict_haskey(rsp, "return")) {
+ g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
+ g_test_message("%s", s->str);
+ }
+
+ g_assert(qdict_haskey(rsp, "return"));
+ qobject_unref(rsp);
+
+ migration_event_wait(to, "setup");
+}
+
+static bool check_migration_status(QTestState *who, const char *goal,
+ const char **ungoals)
+{
+ bool ready;
+ char *current_status;
+ const char **ungoal;
+
+ current_status = migrate_query_status(who);
+ ready = strcmp(current_status, goal) == 0;
+ if (!ungoals) {
+ g_assert_cmpstr(current_status, !=, "failed");
+ /*
+ * If looking for a state other than completed,
+ * completion of migration would cause the test to
+ * hang.
+ */
+ if (strcmp(goal, "completed") != 0) {
+ g_assert_cmpstr(current_status, !=, "completed");
+ }
+ } else {
+ for (ungoal = ungoals; *ungoal; ungoal++) {
+ g_assert_cmpstr(current_status, !=, *ungoal);
+ }
+ }
+ g_free(current_status);
+ return ready;
+}
+
+void wait_for_migration_status(QTestState *who,
+ const char *goal, const char **ungoals)
+{
+ g_test_timer_start();
+ while (!check_migration_status(who, goal, ungoals)) {
+ usleep(1000);
+
+ g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
+ }
+}
+
+void wait_for_migration_complete(QTestState *who)
+{
+ wait_for_migration_status(who, "completed", NULL);
+}
+
+void wait_for_migration_fail(QTestState *from, bool allow_active)
+{
+ g_test_timer_start();
+ QDict *rsp_return;
+ char *status;
+ bool failed;
+
+ do {
+ status = migrate_query_status(from);
+ bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
+ (allow_active && !strcmp(status, "active"));
+ if (!result) {
+ fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
+ __func__, status, allow_active);
+ }
+ g_assert(result);
+ failed = !strcmp(status, "failed");
+ g_free(status);
+
+ g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
+ } while (!failed);
+
+ /* Is the machine currently running? */
+ rsp_return = qtest_qmp_assert_success_ref(from,
+ "{ 'execute': 'query-status' }");
+ g_assert(qdict_haskey(rsp_return, "running"));
+ g_assert(qdict_get_bool(rsp_return, "running"));
+ qobject_unref(rsp_return);
+}
+
+void wait_for_stop(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->stop_seen) {
+ qtest_qmp_eventwait(who, "STOP");
+ }
+}
+
+void wait_for_resume(QTestState *who, QTestMigrationState *state)
+{
+ if (!state->resume_seen) {
+ qtest_qmp_eventwait(who, "RESUME");
+ }
+}
+
+void wait_for_suspend(QTestState *who, QTestMigrationState *state)
+{
+ if (state->suspend_me && !state->suspend_seen) {
+ qtest_qmp_eventwait(who, "SUSPEND");
+ }
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * qobject_unref() after use
+ */
+QDict *migrate_query(QTestState *who)
+{
+ return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
+}
+
+QDict *migrate_query_not_failed(QTestState *who)
+{
+ const char *status;
+ QDict *rsp = migrate_query(who);
+ status = qdict_get_str(rsp, "status");
+ if (g_str_equal(status, "failed")) {
+ g_printerr("query-migrate shows failed migration: %s\n",
+ qdict_get_str(rsp, "error-desc"));
+ }
+ g_assert(!g_str_equal(status, "failed"));
+ return rsp;
+}
+
+/*
+ * Note: caller is responsible to free the returned object via
+ * g_free() after use
+ */
+gchar *migrate_query_status(QTestState *who)
+{
+ QDict *rsp_return = migrate_query(who);
+ gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
+
+ g_assert(status);
+ qobject_unref(rsp_return);
+
+ return status;
+}
+
+int64_t read_ram_property_int(QTestState *who, const char *property)
+{
+ QDict *rsp_return, *rsp_ram;
+ int64_t result;
+
+ rsp_return = migrate_query_not_failed(who);
+ if (!qdict_haskey(rsp_return, "ram")) {
+ /* Still in setup */
+ result = 0;
+ } else {
+ rsp_ram = qdict_get_qdict(rsp_return, "ram");
+ result = qdict_get_try_int(rsp_ram, property, 0);
+ }
+ qobject_unref(rsp_return);
+ return result;
+}
+
+int64_t read_migrate_property_int(QTestState *who, const char *property)
+{
+ QDict *rsp_return;
+ int64_t result;
+
+ rsp_return = migrate_query_not_failed(who);
+ result = qdict_get_try_int(rsp_return, property, 0);
+ qobject_unref(rsp_return);
+ return result;
+}
+
+uint64_t get_migration_pass(QTestState *who)
+{
+ return read_ram_property_int(who, "dirty-sync-count");
+}
+
+void read_blocktime(QTestState *who)
+{
+ QDict *rsp_return;
+
+ rsp_return = migrate_query_not_failed(who);
+ g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
+ qobject_unref(rsp_return);
+}
+
+/*
+ * Wait for two changes in the migration pass count, but bail if we stop.
+ */
+void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state)
+{
+ uint64_t pass, prev_pass = 0, changes = 0;
+
+ while (changes < 2 && !src_state->stop_seen && !src_state->suspend_seen) {
+ usleep(1000);
+ pass = get_migration_pass(who);
+ changes += (pass != prev_pass);
+ prev_pass = pass;
+ }
+}
+
+static long long migrate_get_parameter_int(QTestState *who,
+ const char *parameter)
+{
+ QDict *rsp;
+ long long result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ who, "{ 'execute': 'query-migrate-parameters' }");
+ result = qdict_get_int(rsp, parameter);
+ qobject_unref(rsp);
+ return result;
+}
+
+static void migrate_check_parameter_int(QTestState *who, const char *parameter,
+ long long value)
+{
+ long long result;
+
+ result = migrate_get_parameter_int(who, parameter);
+ g_assert_cmpint(result, ==, value);
+}
+
+void migrate_set_parameter_int(QTestState *who, const char *parameter,
+ long long value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %lld } }",
+ parameter, value);
+ migrate_check_parameter_int(who, parameter, value);
+}
+
+static char *migrate_get_parameter_str(QTestState *who, const char *parameter)
+{
+ QDict *rsp;
+ char *result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ who, "{ 'execute': 'query-migrate-parameters' }");
+ result = g_strdup(qdict_get_str(rsp, parameter));
+ qobject_unref(rsp);
+ return result;
+}
+
+static void migrate_check_parameter_str(QTestState *who, const char *parameter,
+ const char *value)
+{
+ g_autofree char *result = migrate_get_parameter_str(who, parameter);
+ g_assert_cmpstr(result, ==, value);
+}
+
+void migrate_set_parameter_str(QTestState *who, const char *parameter,
+ const char *value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %s } }",
+ parameter, value);
+ migrate_check_parameter_str(who, parameter, value);
+}
+
+static long long migrate_get_parameter_bool(QTestState *who,
+ const char *parameter)
+{
+ QDict *rsp;
+ int result;
+
+ rsp = qtest_qmp_assert_success_ref(
+ who, "{ 'execute': 'query-migrate-parameters' }");
+ result = qdict_get_bool(rsp, parameter);
+ qobject_unref(rsp);
+ return !!result;
+}
+
+static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
+ int value)
+{
+ int result;
+
+ result = migrate_get_parameter_bool(who, parameter);
+ g_assert_cmpint(result, ==, value);
+}
+
+void migrate_set_parameter_bool(QTestState *who, const char *parameter,
+ int value)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-set-parameters',"
+ "'arguments': { %s: %i } }",
+ parameter, value);
+ migrate_check_parameter_bool(who, parameter, value);
+}
+
+void migrate_ensure_non_converge(QTestState *who)
+{
+ /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
+ migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 1);
+}
+
+void migrate_ensure_converge(QTestState *who)
+{
+ /* Should converge with 30s downtime + 1 gbs bandwidth limit */
+ migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
+ migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
+}
+
+void migrate_pause(QTestState *who)
+{
+ qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
+}
+
+void migrate_continue(QTestState *who, const char *state)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-continue',"
+ " 'arguments': { 'state': %s } }",
+ state);
+}
+
+void migrate_recover(QTestState *who, const char *uri)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'migrate-recover', "
+ " 'id': 'recover-cmd', "
+ " 'arguments': { 'uri': %s } }",
+ uri);
+}
+
+void migrate_cancel(QTestState *who)
+{
+ qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
+}
+
+void migrate_postcopy_start(QTestState *from, QTestState *to,
+ QTestMigrationState *src_state)
+{
+ qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
+
+ wait_for_stop(from, src_state);
+ qtest_qmp_eventwait(to, "RESUME");
+}
diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h
new file mode 100644
index 0000000000..e73fa5a70c
--- /dev/null
+++ b/tests/qtest/migration/migration-util.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef MIGRATION_UTIL_H
+#define MIGRATION_UTIL_H
+
+/* migration-qmp.c */
+G_GNUC_PRINTF(4, 5)
+void migrate_qmp_fail(QTestState *who, const char *uri,
+ const char *channels, const char *fmt, ...);
+
+G_GNUC_PRINTF(5, 6)
+void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
+ const char *channels, const char *fmt, ...);
+
+G_GNUC_PRINTF(3, 4)
+void migrate_incoming_qmp(QTestState *who, const char *uri,
+ const char *fmt, ...);
+
+void migration_event_wait(QTestState *s, const char *target);
+void migrate_set_capability(QTestState *who, const char *capability,
+ bool value);
+int64_t read_ram_property_int(QTestState *who, const char *property);
+void migrate_set_parameter_int(QTestState *who, const char *parameter,
+ long long value);
+void wait_for_stop(QTestState *who, QTestMigrationState *state);
+void wait_for_resume(QTestState *who, QTestMigrationState *state);
+void wait_for_suspend(QTestState *who, QTestMigrationState *state);
+gchar *migrate_query_status(QTestState *who);
+int64_t read_migrate_property_int(QTestState *who, const char *property);
+uint64_t get_migration_pass(QTestState *who);
+void read_blocktime(QTestState *who);
+void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state);
+void migrate_set_parameter_str(QTestState *who, const char *parameter,
+ const char *value);
+void migrate_set_parameter_bool(QTestState *who, const char *parameter,
+ int value);
+void migrate_ensure_non_converge(QTestState *who);
+void migrate_ensure_converge(QTestState *who);
+void migrate_pause(QTestState *who);
+void migrate_continue(QTestState *who, const char *state);
+void migrate_recover(QTestState *who, const char *uri);
+void migrate_cancel(QTestState *who);
+void migrate_postcopy_start(QTestState *from, QTestState *to,
+ QTestMigrationState *src_state);
+
+#endif /* MIGRATION_UTIL_H */
diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c
index 73dfabc272..a1c2c70c3a 100644
--- a/tests/qtest/virtio-net-failover.c
+++ b/tests/qtest/virtio-net-failover.c
@@ -12,6 +12,7 @@
#include "libqos/pci.h"
#include "libqos/pci-pc.h"
#include "migration-helpers.h"
+#include "migration/migration-util.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
#include "qapi/qmp/qjson.h"
--
2.35.3
On Tue, Nov 05, 2024 at 03:08:21PM -0300, Fabiano Rosas wrote: > We current have a bunch of non-test functions in migration-test.c and > some others in migration-helpers.c. In order to split migration-test.c > into separate test binaries, these helpers need to go somewhere > else. > > To avoid making migration-helpers even larger, move all QMP-related > functions into a new migration-qmp.c file and put it under the > qtest/migration/ directory. > > The new file holds everything that has as its main responsibility to > call into QMP. > > Signed-off-by: Fabiano Rosas <farosas@suse.de> > --- > tests/qtest/meson.build | 1 + > tests/qtest/migration-helpers.c | 250 +------------ > tests/qtest/migration-helpers.h | 18 +- > tests/qtest/migration-test.c | 237 +----------- > tests/qtest/migration/migration-qmp.c | 485 +++++++++++++++++++++++++ > tests/qtest/migration/migration-util.h | 45 +++ I would have expected the header to be named 'migration-qmp.h' to match the source file naming, and not merge all of migration-helpers.h into it in the next patch which seems to partially defeat the point of splitting up the files. > tests/qtest/virtio-net-failover.c | 1 + > 7 files changed, 541 insertions(+), 496 deletions(-) > create mode 100644 tests/qtest/migration/migration-qmp.c > create mode 100644 tests/qtest/migration/migration-util.h > > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > index f6001a0b0f..30dff3abe0 100644 > --- a/tests/qtest/meson.build > +++ b/tests/qtest/meson.build > @@ -331,6 +331,7 @@ tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c'] > migration_files = [files( > 'migration-helpers.c', > 'migration/bootfile.c', > + 'migration/migration-qmp.c', > )] > > if gnutls.found() > diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c > index 2786f9c860..218ee4e59f 100644 > --- a/tests/qtest/migration-helpers.c > +++ b/tests/qtest/migration-helpers.c > @@ -12,7 +12,6 @@ > > #include "qemu/osdep.h" > #include "qemu/ctype.h" > -#include "qapi/qmp/qjson.h" > #include "qapi/qapi-visit-sockets.h" > #include "qapi/qobject-input-visitor.h" > #include "qapi/error.h" > @@ -23,14 +22,6 @@ > #include "migration-helpers.h" > #include "migration/bootfile.h" > > -/* > - * Number of seconds we wait when looking for migration > - * status changes, to avoid test suite hanging forever > - * when things go wrong. Needs to be higher enough to > - * avoid false positives on loaded hosts. > - */ > -#define MIGRATION_STATUS_WAIT_TIMEOUT 120 > - > static char *SocketAddress_to_str(SocketAddress *addr) > { > switch (addr->type) { > @@ -100,8 +91,7 @@ static SocketAddressList *migrate_get_socket_address(QTestState *who) > return addrs; > } > > -static char * > -migrate_get_connect_uri(QTestState *who) > +char *migrate_get_connect_uri(QTestState *who) > { > SocketAddressList *addrs; > char *connect_uri; > @@ -126,7 +116,7 @@ migrate_get_connect_qdict(QTestState *who) > return connect_qdict; > } > > -static void migrate_set_ports(QTestState *to, QList *channel_list) > +void migrate_set_ports(QTestState *to, QList *channel_list) > { > QDict *addr; > QListEntry *entry; > @@ -168,222 +158,6 @@ bool migrate_watch_for_events(QTestState *who, const char *name, > return false; > } > > -void migrate_qmp_fail(QTestState *who, const char *uri, > - const char *channels, const char *fmt, ...) > -{ > - va_list ap; > - QDict *args, *err; > - > - va_start(ap, fmt); > - args = qdict_from_vjsonf_nofail(fmt, ap); > - va_end(ap); > - > - g_assert(!qdict_haskey(args, "uri")); > - if (uri) { > - qdict_put_str(args, "uri", uri); > - } > - > - g_assert(!qdict_haskey(args, "channels")); > - if (channels) { > - QObject *channels_obj = qobject_from_json(channels, &error_abort); > - qdict_put_obj(args, "channels", channels_obj); > - } > - > - err = qtest_qmp_assert_failure_ref( > - who, "{ 'execute': 'migrate', 'arguments': %p}", args); > - > - g_assert(qdict_haskey(err, "desc")); > - > - qobject_unref(err); > -} > - > -/* > - * Send QMP command "migrate". > - * Arguments are built from @fmt... (formatted like > - * qobject_from_jsonf_nofail()) with "uri": @uri spliced in. > - */ > -void migrate_qmp(QTestState *who, QTestState *to, const char *uri, > - const char *channels, const char *fmt, ...) > -{ > - va_list ap; > - QDict *args; > - g_autofree char *connect_uri = NULL; > - > - va_start(ap, fmt); > - args = qdict_from_vjsonf_nofail(fmt, ap); > - va_end(ap); > - > - g_assert(!qdict_haskey(args, "uri")); > - if (uri) { > - qdict_put_str(args, "uri", uri); > - } else if (!channels) { > - connect_uri = migrate_get_connect_uri(to); > - qdict_put_str(args, "uri", connect_uri); > - } > - > - g_assert(!qdict_haskey(args, "channels")); > - if (channels) { > - QObject *channels_obj = qobject_from_json(channels, &error_abort); > - QList *channel_list = qobject_to(QList, channels_obj); > - migrate_set_ports(to, channel_list); > - qdict_put_obj(args, "channels", channels_obj); > - } > - > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate', 'arguments': %p}", args); > -} > - > -void migrate_set_capability(QTestState *who, const char *capability, > - bool value) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-set-capabilities'," > - "'arguments': { " > - "'capabilities': [ { " > - "'capability': %s, 'state': %i } ] } }", > - capability, value); > -} > - > -void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...) > -{ > - va_list ap; > - QDict *args, *rsp; > - > - va_start(ap, fmt); > - args = qdict_from_vjsonf_nofail(fmt, ap); > - va_end(ap); > - > - g_assert(!qdict_haskey(args, "uri")); > - qdict_put_str(args, "uri", uri); > - > - /* This function relies on the event to work, make sure it's enabled */ > - migrate_set_capability(to, "events", true); > - > - rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}", > - args); > - > - if (!qdict_haskey(rsp, "return")) { > - g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true); > - g_test_message("%s", s->str); > - } > - > - g_assert(qdict_haskey(rsp, "return")); > - qobject_unref(rsp); > - > - migration_event_wait(to, "setup"); > -} > - > -/* > - * Note: caller is responsible to free the returned object via > - * qobject_unref() after use > - */ > -QDict *migrate_query(QTestState *who) > -{ > - return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }"); > -} > - > -QDict *migrate_query_not_failed(QTestState *who) > -{ > - const char *status; > - QDict *rsp = migrate_query(who); > - status = qdict_get_str(rsp, "status"); > - if (g_str_equal(status, "failed")) { > - g_printerr("query-migrate shows failed migration: %s\n", > - qdict_get_str(rsp, "error-desc")); > - } > - g_assert(!g_str_equal(status, "failed")); > - return rsp; > -} > - > -/* > - * Note: caller is responsible to free the returned object via > - * g_free() after use > - */ > -static gchar *migrate_query_status(QTestState *who) > -{ > - QDict *rsp_return = migrate_query(who); > - gchar *status = g_strdup(qdict_get_str(rsp_return, "status")); > - > - g_assert(status); > - qobject_unref(rsp_return); > - > - return status; > -} > - > -static bool check_migration_status(QTestState *who, const char *goal, > - const char **ungoals) > -{ > - bool ready; > - char *current_status; > - const char **ungoal; > - > - current_status = migrate_query_status(who); > - ready = strcmp(current_status, goal) == 0; > - if (!ungoals) { > - g_assert_cmpstr(current_status, !=, "failed"); > - /* > - * If looking for a state other than completed, > - * completion of migration would cause the test to > - * hang. > - */ > - if (strcmp(goal, "completed") != 0) { > - g_assert_cmpstr(current_status, !=, "completed"); > - } > - } else { > - for (ungoal = ungoals; *ungoal; ungoal++) { > - g_assert_cmpstr(current_status, !=, *ungoal); > - } > - } > - g_free(current_status); > - return ready; > -} > - > -void wait_for_migration_status(QTestState *who, > - const char *goal, const char **ungoals) > -{ > - g_test_timer_start(); > - while (!check_migration_status(who, goal, ungoals)) { > - usleep(1000); > - > - g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); > - } > -} > - > -void wait_for_migration_complete(QTestState *who) > -{ > - wait_for_migration_status(who, "completed", NULL); > -} > - > -void wait_for_migration_fail(QTestState *from, bool allow_active) > -{ > - g_test_timer_start(); > - QDict *rsp_return; > - char *status; > - bool failed; > - > - do { > - status = migrate_query_status(from); > - bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || > - (allow_active && !strcmp(status, "active")); > - if (!result) { > - fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", > - __func__, status, allow_active); > - } > - g_assert(result); > - failed = !strcmp(status, "failed"); > - g_free(status); > - > - g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); > - } while (!failed); > - > - /* Is the machine currently running? */ > - rsp_return = qtest_qmp_assert_success_ref(from, > - "{ 'execute': 'query-status' }"); > - g_assert(qdict_haskey(rsp_return, "running")); > - g_assert(qdict_get_bool(rsp_return, "running")); > - qobject_unref(rsp_return); > -} > - > char *find_common_machine_version(const char *mtype, const char *var1, > const char *var2) > { > @@ -509,23 +283,3 @@ bool probe_o_direct_support(const char *tmpfs) > return true; > } > #endif > - > -/* > - * Wait for a "MIGRATION" event. This is what Libvirt uses to track > - * migration status changes. > - */ > -void migration_event_wait(QTestState *s, const char *target) > -{ > - QDict *response, *data; > - const char *status; > - bool found; > - > - do { > - response = qtest_qmp_eventwait_ref(s, "MIGRATION"); > - data = qdict_get_qdict(response, "data"); > - g_assert(data); > - status = qdict_get_str(data, "status"); > - found = (strcmp(status, target) == 0); > - qobject_unref(response); > - } while (!found); > -} > diff --git a/tests/qtest/migration-helpers.h b/tests/qtest/migration-helpers.h > index 72dba369fb..2cb1f78d9e 100644 > --- a/tests/qtest/migration-helpers.h > +++ b/tests/qtest/migration-helpers.h > @@ -25,21 +25,6 @@ typedef struct QTestMigrationState { > bool migrate_watch_for_events(QTestState *who, const char *name, > QDict *event, void *opaque); > > -G_GNUC_PRINTF(5, 6) > -void migrate_qmp(QTestState *who, QTestState *to, const char *uri, > - const char *channels, const char *fmt, ...); > - > -G_GNUC_PRINTF(3, 4) > -void migrate_incoming_qmp(QTestState *who, const char *uri, > - const char *fmt, ...); > - > -G_GNUC_PRINTF(4, 5) > -void migrate_qmp_fail(QTestState *who, const char *uri, > - const char *channels, const char *fmt, ...); > - > -void migrate_set_capability(QTestState *who, const char *capability, > - bool value); > - > QDict *migrate_query(QTestState *who); > QDict *migrate_query_not_failed(QTestState *who); > > @@ -63,6 +48,7 @@ static inline bool probe_o_direct_support(const char *tmpfs) > } > #endif > void migration_test_add(const char *path, void (*fn)(void)); > -void migration_event_wait(QTestState *s, const char *target); > +char *migrate_get_connect_uri(QTestState *who); > +void migrate_set_ports(QTestState *to, QList *channel_list); > > #endif /* MIGRATION_HELPERS_H */ > diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c > index 599adc422c..f55423467d 100644 > --- a/tests/qtest/migration-test.c > +++ b/tests/qtest/migration-test.c > @@ -13,18 +13,18 @@ > #include "qemu/osdep.h" > > #include "libqtest.h" > -#include "qapi/qmp/qdict.h" > +#include "qapi/qmp/qlist.h" > #include "qemu/module.h" > #include "qemu/option.h" > #include "qemu/range.h" > #include "qemu/sockets.h" > #include "chardev/char.h" > #include "crypto/tlscredspsk.h" > -#include "qapi/qmp/qlist.h" > #include "ppc-util.h" > > #include "migration-helpers.h" > #include "migration/bootfile.h" > +#include "migration/migration-util.h" > #ifdef CONFIG_GNUTLS > # include "tests/unit/crypto-tls-psk-helpers.h" > # ifdef CONFIG_TASN1 > @@ -170,89 +170,6 @@ static void wait_for_serial(const char *side) > } while (true); > } > > -static void wait_for_stop(QTestState *who, QTestMigrationState *state) > -{ > - if (!state->stop_seen) { > - qtest_qmp_eventwait(who, "STOP"); > - } > -} > - > -static void wait_for_resume(QTestState *who, QTestMigrationState *state) > -{ > - if (!state->resume_seen) { > - qtest_qmp_eventwait(who, "RESUME"); > - } > -} > - > -static void wait_for_suspend(QTestState *who, QTestMigrationState *state) > -{ > - if (state->suspend_me && !state->suspend_seen) { > - qtest_qmp_eventwait(who, "SUSPEND"); > - } > -} > - > -/* > - * It's tricky to use qemu's migration event capability with qtest, > - * events suddenly appearing confuse the qmp()/hmp() responses. > - */ > - > -static int64_t read_ram_property_int(QTestState *who, const char *property) > -{ > - QDict *rsp_return, *rsp_ram; > - int64_t result; > - > - rsp_return = migrate_query_not_failed(who); > - if (!qdict_haskey(rsp_return, "ram")) { > - /* Still in setup */ > - result = 0; > - } else { > - rsp_ram = qdict_get_qdict(rsp_return, "ram"); > - result = qdict_get_try_int(rsp_ram, property, 0); > - } > - qobject_unref(rsp_return); > - return result; > -} > - > -static int64_t read_migrate_property_int(QTestState *who, const char *property) > -{ > - QDict *rsp_return; > - int64_t result; > - > - rsp_return = migrate_query_not_failed(who); > - result = qdict_get_try_int(rsp_return, property, 0); > - qobject_unref(rsp_return); > - return result; > -} > - > -static uint64_t get_migration_pass(QTestState *who) > -{ > - return read_ram_property_int(who, "dirty-sync-count"); > -} > - > -static void read_blocktime(QTestState *who) > -{ > - QDict *rsp_return; > - > - rsp_return = migrate_query_not_failed(who); > - g_assert(qdict_haskey(rsp_return, "postcopy-blocktime")); > - qobject_unref(rsp_return); > -} > - > -/* > - * Wait for two changes in the migration pass count, but bail if we stop. > - */ > -static void wait_for_migration_pass(QTestState *who) > -{ > - uint64_t pass, prev_pass = 0, changes = 0; > - > - while (changes < 2 && !src_state.stop_seen && !src_state.suspend_seen) { > - usleep(1000); > - pass = get_migration_pass(who); > - changes += (pass != prev_pass); > - prev_pass = pass; > - } > -} > - > static void check_guests_ram(QTestState *who) > { > /* Our ASM test will have been incrementing one byte from each page from > @@ -308,114 +225,6 @@ static void cleanup(const char *filename) > unlink(path); > } > > -static long long migrate_get_parameter_int(QTestState *who, > - const char *parameter) > -{ > - QDict *rsp; > - long long result; > - > - rsp = qtest_qmp_assert_success_ref( > - who, "{ 'execute': 'query-migrate-parameters' }"); > - result = qdict_get_int(rsp, parameter); > - qobject_unref(rsp); > - return result; > -} > - > -static void migrate_check_parameter_int(QTestState *who, const char *parameter, > - long long value) > -{ > - long long result; > - > - result = migrate_get_parameter_int(who, parameter); > - g_assert_cmpint(result, ==, value); > -} > - > -static void migrate_set_parameter_int(QTestState *who, const char *parameter, > - long long value) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-set-parameters'," > - "'arguments': { %s: %lld } }", > - parameter, value); > - migrate_check_parameter_int(who, parameter, value); > -} > - > -static char *migrate_get_parameter_str(QTestState *who, > - const char *parameter) > -{ > - QDict *rsp; > - char *result; > - > - rsp = qtest_qmp_assert_success_ref( > - who, "{ 'execute': 'query-migrate-parameters' }"); > - result = g_strdup(qdict_get_str(rsp, parameter)); > - qobject_unref(rsp); > - return result; > -} > - > -static void migrate_check_parameter_str(QTestState *who, const char *parameter, > - const char *value) > -{ > - g_autofree char *result = migrate_get_parameter_str(who, parameter); > - g_assert_cmpstr(result, ==, value); > -} > - > -static void migrate_set_parameter_str(QTestState *who, const char *parameter, > - const char *value) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-set-parameters'," > - "'arguments': { %s: %s } }", > - parameter, value); > - migrate_check_parameter_str(who, parameter, value); > -} > - > -static long long migrate_get_parameter_bool(QTestState *who, > - const char *parameter) > -{ > - QDict *rsp; > - int result; > - > - rsp = qtest_qmp_assert_success_ref( > - who, "{ 'execute': 'query-migrate-parameters' }"); > - result = qdict_get_bool(rsp, parameter); > - qobject_unref(rsp); > - return !!result; > -} > - > -static void migrate_check_parameter_bool(QTestState *who, const char *parameter, > - int value) > -{ > - int result; > - > - result = migrate_get_parameter_bool(who, parameter); > - g_assert_cmpint(result, ==, value); > -} > - > -static void migrate_set_parameter_bool(QTestState *who, const char *parameter, > - int value) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-set-parameters'," > - "'arguments': { %s: %i } }", > - parameter, value); > - migrate_check_parameter_bool(who, parameter, value); > -} > - > -static void migrate_ensure_non_converge(QTestState *who) > -{ > - /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */ > - migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000); > - migrate_set_parameter_int(who, "downtime-limit", 1); > -} > - > -static void migrate_ensure_converge(QTestState *who) > -{ > - /* Should converge with 30s downtime + 1 gbs bandwidth limit */ > - migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000); > - migrate_set_parameter_int(who, "downtime-limit", 30 * 1000); > -} > - > /* > * Our goal is to ensure that we run a single full migration > * iteration, and also dirty memory, ensuring that at least > @@ -506,42 +315,6 @@ static void migrate_wait_for_dirty_mem(QTestState *from, > } while (qtest_readb(from, watch_address) == watch_byte); > } > > - > -static void migrate_pause(QTestState *who) > -{ > - qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }"); > -} > - > -static void migrate_continue(QTestState *who, const char *state) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-continue'," > - " 'arguments': { 'state': %s } }", > - state); > -} > - > -static void migrate_recover(QTestState *who, const char *uri) > -{ > - qtest_qmp_assert_success(who, > - "{ 'execute': 'migrate-recover', " > - " 'id': 'recover-cmd', " > - " 'arguments': { 'uri': %s } }", > - uri); > -} > - > -static void migrate_cancel(QTestState *who) > -{ > - qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }"); > -} > - > -static void migrate_postcopy_start(QTestState *from, QTestState *to) > -{ > - qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }"); > - > - wait_for_stop(from, &src_state); > - qtest_qmp_eventwait(to, "RESUME"); > -} > - > typedef struct { > /* > * QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors > @@ -1277,7 +1050,7 @@ static void test_postcopy_common(MigrateCommon *args) > if (migrate_postcopy_prepare(&from, &to, args)) { > return; > } > - migrate_postcopy_start(from, to); > + migrate_postcopy_start(from, to, &src_state); > migrate_postcopy_complete(from, to, args); > } > > @@ -1464,7 +1237,7 @@ static void test_postcopy_recovery_common(MigrateCommon *args) > migrate_set_parameter_int(from, "max-postcopy-bandwidth", 4096); > > /* Now we start the postcopy */ > - migrate_postcopy_start(from, to); > + migrate_postcopy_start(from, to, &src_state); > > /* > * Wait until postcopy is really started; we can only run the > @@ -1704,7 +1477,7 @@ static void test_precopy_common(MigrateCommon *args) > * for some dirty mem before switching to converge > */ > while (args->iterations > 1) { > - wait_for_migration_pass(from); > + wait_for_migration_pass(from, &src_state); > args->iterations--; > } > migrate_wait_for_dirty_mem(from, to); > diff --git a/tests/qtest/migration/migration-qmp.c b/tests/qtest/migration/migration-qmp.c > new file mode 100644 > index 0000000000..89e069e96b > --- /dev/null > +++ b/tests/qtest/migration/migration-qmp.c > @@ -0,0 +1,485 @@ > +/* > + * QTest QMP helpers 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 "libqtest.h" > +#include "migration-helpers.h" > +#include "migration-util.h" > +#include "qapi/error.h" > +#include "qapi/qmp/qdict.h" > +#include "qapi/qmp/qjson.h" > +#include "qapi/qmp/qlist.h" > + > +/* > + * Number of seconds we wait when looking for migration > + * status changes, to avoid test suite hanging forever > + * when things go wrong. Needs to be higher enough to > + * avoid false positives on loaded hosts. > + */ > +#define MIGRATION_STATUS_WAIT_TIMEOUT 120 > + > +/* > + * Wait for a "MIGRATION" event. This is what Libvirt uses to track > + * migration status changes. > + */ > +void migration_event_wait(QTestState *s, const char *target) > +{ > + QDict *response, *data; > + const char *status; > + bool found; > + > + do { > + response = qtest_qmp_eventwait_ref(s, "MIGRATION"); > + data = qdict_get_qdict(response, "data"); > + g_assert(data); > + status = qdict_get_str(data, "status"); > + found = (strcmp(status, target) == 0); > + qobject_unref(response); > + } while (!found); > +} > + > +void migrate_qmp_fail(QTestState *who, const char *uri, > + const char *channels, const char *fmt, ...) > +{ > + va_list ap; > + QDict *args, *err; > + > + va_start(ap, fmt); > + args = qdict_from_vjsonf_nofail(fmt, ap); > + va_end(ap); > + > + g_assert(!qdict_haskey(args, "uri")); > + if (uri) { > + qdict_put_str(args, "uri", uri); > + } > + > + g_assert(!qdict_haskey(args, "channels")); > + if (channels) { > + QObject *channels_obj = qobject_from_json(channels, &error_abort); > + qdict_put_obj(args, "channels", channels_obj); > + } > + > + err = qtest_qmp_assert_failure_ref( > + who, "{ 'execute': 'migrate', 'arguments': %p}", args); > + > + g_assert(qdict_haskey(err, "desc")); > + > + qobject_unref(err); > +} > + > +/* > + * Send QMP command "migrate". > + * Arguments are built from @fmt... (formatted like > + * qobject_from_jsonf_nofail()) with "uri": @uri spliced in. > + */ > +void migrate_qmp(QTestState *who, QTestState *to, const char *uri, > + const char *channels, const char *fmt, ...) > +{ > + va_list ap; > + QDict *args; > + g_autofree char *connect_uri = NULL; > + > + va_start(ap, fmt); > + args = qdict_from_vjsonf_nofail(fmt, ap); > + va_end(ap); > + > + g_assert(!qdict_haskey(args, "uri")); > + if (uri) { > + qdict_put_str(args, "uri", uri); > + } else if (!channels) { > + connect_uri = migrate_get_connect_uri(to); > + qdict_put_str(args, "uri", connect_uri); > + } > + > + g_assert(!qdict_haskey(args, "channels")); > + if (channels) { > + QObject *channels_obj = qobject_from_json(channels, &error_abort); > + QList *channel_list = qobject_to(QList, channels_obj); > + migrate_set_ports(to, channel_list); > + qdict_put_obj(args, "channels", channels_obj); > + } > + > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate', 'arguments': %p}", args); > +} > + > +void migrate_set_capability(QTestState *who, const char *capability, > + bool value) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-set-capabilities'," > + "'arguments': { " > + "'capabilities': [ { " > + "'capability': %s, 'state': %i } ] } }", > + capability, value); > +} > + > +void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...) > +{ > + va_list ap; > + QDict *args, *rsp; > + > + va_start(ap, fmt); > + args = qdict_from_vjsonf_nofail(fmt, ap); > + va_end(ap); > + > + g_assert(!qdict_haskey(args, "uri")); > + qdict_put_str(args, "uri", uri); > + > + /* This function relies on the event to work, make sure it's enabled */ > + migrate_set_capability(to, "events", true); > + > + rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}", > + args); > + > + if (!qdict_haskey(rsp, "return")) { > + g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true); > + g_test_message("%s", s->str); > + } > + > + g_assert(qdict_haskey(rsp, "return")); > + qobject_unref(rsp); > + > + migration_event_wait(to, "setup"); > +} > + > +static bool check_migration_status(QTestState *who, const char *goal, > + const char **ungoals) > +{ > + bool ready; > + char *current_status; > + const char **ungoal; > + > + current_status = migrate_query_status(who); > + ready = strcmp(current_status, goal) == 0; > + if (!ungoals) { > + g_assert_cmpstr(current_status, !=, "failed"); > + /* > + * If looking for a state other than completed, > + * completion of migration would cause the test to > + * hang. > + */ > + if (strcmp(goal, "completed") != 0) { > + g_assert_cmpstr(current_status, !=, "completed"); > + } > + } else { > + for (ungoal = ungoals; *ungoal; ungoal++) { > + g_assert_cmpstr(current_status, !=, *ungoal); > + } > + } > + g_free(current_status); > + return ready; > +} > + > +void wait_for_migration_status(QTestState *who, > + const char *goal, const char **ungoals) > +{ > + g_test_timer_start(); > + while (!check_migration_status(who, goal, ungoals)) { > + usleep(1000); > + > + g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); > + } > +} > + > +void wait_for_migration_complete(QTestState *who) > +{ > + wait_for_migration_status(who, "completed", NULL); > +} > + > +void wait_for_migration_fail(QTestState *from, bool allow_active) > +{ > + g_test_timer_start(); > + QDict *rsp_return; > + char *status; > + bool failed; > + > + do { > + status = migrate_query_status(from); > + bool result = !strcmp(status, "setup") || !strcmp(status, "failed") || > + (allow_active && !strcmp(status, "active")); > + if (!result) { > + fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n", > + __func__, status, allow_active); > + } > + g_assert(result); > + failed = !strcmp(status, "failed"); > + g_free(status); > + > + g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT); > + } while (!failed); > + > + /* Is the machine currently running? */ > + rsp_return = qtest_qmp_assert_success_ref(from, > + "{ 'execute': 'query-status' }"); > + g_assert(qdict_haskey(rsp_return, "running")); > + g_assert(qdict_get_bool(rsp_return, "running")); > + qobject_unref(rsp_return); > +} > + > +void wait_for_stop(QTestState *who, QTestMigrationState *state) > +{ > + if (!state->stop_seen) { > + qtest_qmp_eventwait(who, "STOP"); > + } > +} > + > +void wait_for_resume(QTestState *who, QTestMigrationState *state) > +{ > + if (!state->resume_seen) { > + qtest_qmp_eventwait(who, "RESUME"); > + } > +} > + > +void wait_for_suspend(QTestState *who, QTestMigrationState *state) > +{ > + if (state->suspend_me && !state->suspend_seen) { > + qtest_qmp_eventwait(who, "SUSPEND"); > + } > +} > + > +/* > + * Note: caller is responsible to free the returned object via > + * qobject_unref() after use > + */ > +QDict *migrate_query(QTestState *who) > +{ > + return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }"); > +} > + > +QDict *migrate_query_not_failed(QTestState *who) > +{ > + const char *status; > + QDict *rsp = migrate_query(who); > + status = qdict_get_str(rsp, "status"); > + if (g_str_equal(status, "failed")) { > + g_printerr("query-migrate shows failed migration: %s\n", > + qdict_get_str(rsp, "error-desc")); > + } > + g_assert(!g_str_equal(status, "failed")); > + return rsp; > +} > + > +/* > + * Note: caller is responsible to free the returned object via > + * g_free() after use > + */ > +gchar *migrate_query_status(QTestState *who) > +{ > + QDict *rsp_return = migrate_query(who); > + gchar *status = g_strdup(qdict_get_str(rsp_return, "status")); > + > + g_assert(status); > + qobject_unref(rsp_return); > + > + return status; > +} > + > +int64_t read_ram_property_int(QTestState *who, const char *property) > +{ > + QDict *rsp_return, *rsp_ram; > + int64_t result; > + > + rsp_return = migrate_query_not_failed(who); > + if (!qdict_haskey(rsp_return, "ram")) { > + /* Still in setup */ > + result = 0; > + } else { > + rsp_ram = qdict_get_qdict(rsp_return, "ram"); > + result = qdict_get_try_int(rsp_ram, property, 0); > + } > + qobject_unref(rsp_return); > + return result; > +} > + > +int64_t read_migrate_property_int(QTestState *who, const char *property) > +{ > + QDict *rsp_return; > + int64_t result; > + > + rsp_return = migrate_query_not_failed(who); > + result = qdict_get_try_int(rsp_return, property, 0); > + qobject_unref(rsp_return); > + return result; > +} > + > +uint64_t get_migration_pass(QTestState *who) > +{ > + return read_ram_property_int(who, "dirty-sync-count"); > +} > + > +void read_blocktime(QTestState *who) > +{ > + QDict *rsp_return; > + > + rsp_return = migrate_query_not_failed(who); > + g_assert(qdict_haskey(rsp_return, "postcopy-blocktime")); > + qobject_unref(rsp_return); > +} > + > +/* > + * Wait for two changes in the migration pass count, but bail if we stop. > + */ > +void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state) > +{ > + uint64_t pass, prev_pass = 0, changes = 0; > + > + while (changes < 2 && !src_state->stop_seen && !src_state->suspend_seen) { > + usleep(1000); > + pass = get_migration_pass(who); > + changes += (pass != prev_pass); > + prev_pass = pass; > + } > +} > + > +static long long migrate_get_parameter_int(QTestState *who, > + const char *parameter) > +{ > + QDict *rsp; > + long long result; > + > + rsp = qtest_qmp_assert_success_ref( > + who, "{ 'execute': 'query-migrate-parameters' }"); > + result = qdict_get_int(rsp, parameter); > + qobject_unref(rsp); > + return result; > +} > + > +static void migrate_check_parameter_int(QTestState *who, const char *parameter, > + long long value) > +{ > + long long result; > + > + result = migrate_get_parameter_int(who, parameter); > + g_assert_cmpint(result, ==, value); > +} > + > +void migrate_set_parameter_int(QTestState *who, const char *parameter, > + long long value) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-set-parameters'," > + "'arguments': { %s: %lld } }", > + parameter, value); > + migrate_check_parameter_int(who, parameter, value); > +} > + > +static char *migrate_get_parameter_str(QTestState *who, const char *parameter) > +{ > + QDict *rsp; > + char *result; > + > + rsp = qtest_qmp_assert_success_ref( > + who, "{ 'execute': 'query-migrate-parameters' }"); > + result = g_strdup(qdict_get_str(rsp, parameter)); > + qobject_unref(rsp); > + return result; > +} > + > +static void migrate_check_parameter_str(QTestState *who, const char *parameter, > + const char *value) > +{ > + g_autofree char *result = migrate_get_parameter_str(who, parameter); > + g_assert_cmpstr(result, ==, value); > +} > + > +void migrate_set_parameter_str(QTestState *who, const char *parameter, > + const char *value) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-set-parameters'," > + "'arguments': { %s: %s } }", > + parameter, value); > + migrate_check_parameter_str(who, parameter, value); > +} > + > +static long long migrate_get_parameter_bool(QTestState *who, > + const char *parameter) > +{ > + QDict *rsp; > + int result; > + > + rsp = qtest_qmp_assert_success_ref( > + who, "{ 'execute': 'query-migrate-parameters' }"); > + result = qdict_get_bool(rsp, parameter); > + qobject_unref(rsp); > + return !!result; > +} > + > +static void migrate_check_parameter_bool(QTestState *who, const char *parameter, > + int value) > +{ > + int result; > + > + result = migrate_get_parameter_bool(who, parameter); > + g_assert_cmpint(result, ==, value); > +} > + > +void migrate_set_parameter_bool(QTestState *who, const char *parameter, > + int value) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-set-parameters'," > + "'arguments': { %s: %i } }", > + parameter, value); > + migrate_check_parameter_bool(who, parameter, value); > +} > + > +void migrate_ensure_non_converge(QTestState *who) > +{ > + /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */ > + migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000); > + migrate_set_parameter_int(who, "downtime-limit", 1); > +} > + > +void migrate_ensure_converge(QTestState *who) > +{ > + /* Should converge with 30s downtime + 1 gbs bandwidth limit */ > + migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000); > + migrate_set_parameter_int(who, "downtime-limit", 30 * 1000); > +} > + > +void migrate_pause(QTestState *who) > +{ > + qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }"); > +} > + > +void migrate_continue(QTestState *who, const char *state) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-continue'," > + " 'arguments': { 'state': %s } }", > + state); > +} > + > +void migrate_recover(QTestState *who, const char *uri) > +{ > + qtest_qmp_assert_success(who, > + "{ 'execute': 'migrate-recover', " > + " 'id': 'recover-cmd', " > + " 'arguments': { 'uri': %s } }", > + uri); > +} > + > +void migrate_cancel(QTestState *who) > +{ > + qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }"); > +} > + > +void migrate_postcopy_start(QTestState *from, QTestState *to, > + QTestMigrationState *src_state) > +{ > + qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }"); > + > + wait_for_stop(from, src_state); > + qtest_qmp_eventwait(to, "RESUME"); > +} > diff --git a/tests/qtest/migration/migration-util.h b/tests/qtest/migration/migration-util.h > new file mode 100644 > index 0000000000..e73fa5a70c > --- /dev/null > +++ b/tests/qtest/migration/migration-util.h > @@ -0,0 +1,45 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +#ifndef MIGRATION_UTIL_H > +#define MIGRATION_UTIL_H > + > +/* migration-qmp.c */ > +G_GNUC_PRINTF(4, 5) > +void migrate_qmp_fail(QTestState *who, const char *uri, > + const char *channels, const char *fmt, ...); > + > +G_GNUC_PRINTF(5, 6) > +void migrate_qmp(QTestState *who, QTestState *to, const char *uri, > + const char *channels, const char *fmt, ...); > + > +G_GNUC_PRINTF(3, 4) > +void migrate_incoming_qmp(QTestState *who, const char *uri, > + const char *fmt, ...); > + > +void migration_event_wait(QTestState *s, const char *target); > +void migrate_set_capability(QTestState *who, const char *capability, > + bool value); > +int64_t read_ram_property_int(QTestState *who, const char *property); > +void migrate_set_parameter_int(QTestState *who, const char *parameter, > + long long value); > +void wait_for_stop(QTestState *who, QTestMigrationState *state); > +void wait_for_resume(QTestState *who, QTestMigrationState *state); > +void wait_for_suspend(QTestState *who, QTestMigrationState *state); > +gchar *migrate_query_status(QTestState *who); > +int64_t read_migrate_property_int(QTestState *who, const char *property); > +uint64_t get_migration_pass(QTestState *who); > +void read_blocktime(QTestState *who); > +void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state); > +void migrate_set_parameter_str(QTestState *who, const char *parameter, > + const char *value); > +void migrate_set_parameter_bool(QTestState *who, const char *parameter, > + int value); > +void migrate_ensure_non_converge(QTestState *who); > +void migrate_ensure_converge(QTestState *who); > +void migrate_pause(QTestState *who); > +void migrate_continue(QTestState *who, const char *state); > +void migrate_recover(QTestState *who, const char *uri); > +void migrate_cancel(QTestState *who); > +void migrate_postcopy_start(QTestState *from, QTestState *to, > + QTestMigrationState *src_state); > + > +#endif /* MIGRATION_UTIL_H */ > diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c > index 73dfabc272..a1c2c70c3a 100644 > --- a/tests/qtest/virtio-net-failover.c > +++ b/tests/qtest/virtio-net-failover.c > @@ -12,6 +12,7 @@ > #include "libqos/pci.h" > #include "libqos/pci-pc.h" > #include "migration-helpers.h" > +#include "migration/migration-util.h" > #include "qapi/qmp/qdict.h" > #include "qapi/qmp/qlist.h" > #include "qapi/qmp/qjson.h" > -- > 2.35.3 > With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
Daniel P. Berrangé <berrange@redhat.com> writes: > On Tue, Nov 05, 2024 at 03:08:21PM -0300, Fabiano Rosas wrote: >> We current have a bunch of non-test functions in migration-test.c and >> some others in migration-helpers.c. In order to split migration-test.c >> into separate test binaries, these helpers need to go somewhere >> else. >> >> To avoid making migration-helpers even larger, move all QMP-related >> functions into a new migration-qmp.c file and put it under the >> qtest/migration/ directory. >> >> The new file holds everything that has as its main responsibility to >> call into QMP. >> >> Signed-off-by: Fabiano Rosas <farosas@suse.de> >> --- >> tests/qtest/meson.build | 1 + >> tests/qtest/migration-helpers.c | 250 +------------ >> tests/qtest/migration-helpers.h | 18 +- >> tests/qtest/migration-test.c | 237 +----------- >> tests/qtest/migration/migration-qmp.c | 485 +++++++++++++++++++++++++ >> tests/qtest/migration/migration-util.h | 45 +++ > > I would have expected the header to be named 'migration-qmp.h' to match > the source file naming, and not merge all of migration-helpers.h into > it in the next patch which seems to partially defeat the point of splitting > up the files. > Ok, I can change that.
© 2016 - 2024 Red Hat, Inc.