2 * QTest migration helpers
4 * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5 * based on the vhost-user-test.c that is:
6 * Copyright (c) 2014 Virtual Open Systems Sarl.
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "qapi/qmp/qjson.h"
16 #include "migration-helpers.h"
19 * Number of seconds we wait when looking for migration
20 * status changes, to avoid test suite hanging forever
21 * when things go wrong. Needs to be higher enough to
22 * avoid false positives on loaded hosts.
24 #define MIGRATION_STATUS_WAIT_TIMEOUT 120
28 static void check_stop_event(QTestState
*who
)
30 QDict
*event
= qtest_qmp_event_ref(who
, "STOP");
39 * Events can get in the way of responses we are actually waiting for.
41 QDict
*wait_command_fd(QTestState
*who
, int fd
, const char *command
, ...)
46 va_start(ap
, command
);
47 qtest_qmp_vsend_fds(who
, &fd
, 1, command
, ap
);
50 resp
= qtest_qmp_receive(who
);
51 check_stop_event(who
);
53 g_assert(!qdict_haskey(resp
, "error"));
54 g_assert(qdict_haskey(resp
, "return"));
56 ret
= qdict_get_qdict(resp
, "return");
65 * Events can get in the way of responses we are actually waiting for.
67 QDict
*wait_command(QTestState
*who
, const char *command
, ...)
72 va_start(ap
, command
);
73 resp
= qtest_vqmp(who
, command
, ap
);
76 check_stop_event(who
);
78 g_assert(!qdict_haskey(resp
, "error"));
79 g_assert(qdict_haskey(resp
, "return"));
81 ret
= qdict_get_qdict(resp
, "return");
89 * Execute the qmp command only
91 QDict
*qmp_command(QTestState
*who
, const char *command
, ...)
96 va_start(ap
, command
);
97 resp
= qtest_vqmp(who
, command
, ap
);
100 g_assert(!qdict_haskey(resp
, "error"));
101 g_assert(qdict_haskey(resp
, "return"));
103 ret
= qdict_get_qdict(resp
, "return");
111 * Send QMP command "migrate".
112 * Arguments are built from @fmt... (formatted like
113 * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
115 void migrate_qmp(QTestState
*who
, const char *uri
, const char *fmt
, ...)
121 args
= qdict_from_vjsonf_nofail(fmt
, ap
);
124 g_assert(!qdict_haskey(args
, "uri"));
125 qdict_put_str(args
, "uri", uri
);
127 rsp
= qtest_qmp(who
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
129 g_assert(qdict_haskey(rsp
, "return"));
134 * Note: caller is responsible to free the returned object via
135 * qobject_unref() after use
137 QDict
*migrate_query(QTestState
*who
)
139 return wait_command(who
, "{ 'execute': 'query-migrate' }");
142 QDict
*migrate_query_not_failed(QTestState
*who
)
145 QDict
*rsp
= migrate_query(who
);
146 status
= qdict_get_str(rsp
, "status");
147 if (g_str_equal(status
, "failed")) {
148 g_printerr("query-migrate shows failed migration: %s\n",
149 qdict_get_str(rsp
, "error-desc"));
151 g_assert(!g_str_equal(status
, "failed"));
156 * Note: caller is responsible to free the returned object via
159 static gchar
*migrate_query_status(QTestState
*who
)
161 QDict
*rsp_return
= migrate_query(who
);
162 gchar
*status
= g_strdup(qdict_get_str(rsp_return
, "status"));
165 qobject_unref(rsp_return
);
170 static bool check_migration_status(QTestState
*who
, const char *goal
,
171 const char **ungoals
)
174 char *current_status
;
177 current_status
= migrate_query_status(who
);
178 ready
= strcmp(current_status
, goal
) == 0;
180 g_assert_cmpstr(current_status
, !=, "failed");
182 * If looking for a state other than completed,
183 * completion of migration would cause the test to
186 if (strcmp(goal
, "completed") != 0) {
187 g_assert_cmpstr(current_status
, !=, "completed");
190 for (ungoal
= ungoals
; *ungoal
; ungoal
++) {
191 g_assert_cmpstr(current_status
, !=, *ungoal
);
194 g_free(current_status
);
198 void wait_for_migration_status(QTestState
*who
,
199 const char *goal
, const char **ungoals
)
201 g_test_timer_start();
202 while (!check_migration_status(who
, goal
, ungoals
)) {
205 g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT
);
209 void wait_for_migration_complete(QTestState
*who
)
211 wait_for_migration_status(who
, "completed", NULL
);
214 void wait_for_migration_fail(QTestState
*from
, bool allow_active
)
216 g_test_timer_start();
222 status
= migrate_query_status(from
);
223 bool result
= !strcmp(status
, "setup") || !strcmp(status
, "failed") ||
224 (allow_active
&& !strcmp(status
, "active"));
226 fprintf(stderr
, "%s: unexpected status status=%s allow_active=%d\n",
227 __func__
, status
, allow_active
);
230 failed
= !strcmp(status
, "failed");
233 g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT
);
236 /* Is the machine currently running? */
237 rsp_return
= wait_command(from
, "{ 'execute': 'query-status' }");
238 g_assert(qdict_haskey(rsp_return
, "running"));
239 g_assert(qdict_get_bool(rsp_return
, "running"));
240 qobject_unref(rsp_return
);