mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
tests/qtest/migration: Move qmp helpers to a separate file
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. Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
parent
537f23fb9e
commit
e6c5704043
7 changed files with 542 additions and 497 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue