tests/qemu-iotests: Restrict tests using "--blockdev file" to the file protocol
[qemu/kevin.git] / tests / qtest / migration-helpers.c
blobe451dbdbed136571e0da2de7d194d4adb8ddfdb2
1 /*
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 "qemu/ctype.h"
15 #include "qapi/qmp/qjson.h"
17 #include "migration-helpers.h"
20 * Number of seconds we wait when looking for migration
21 * status changes, to avoid test suite hanging forever
22 * when things go wrong. Needs to be higher enough to
23 * avoid false positives on loaded hosts.
25 #define MIGRATION_STATUS_WAIT_TIMEOUT 120
27 bool migrate_watch_for_events(QTestState *who, const char *name,
28 QDict *event, void *opaque)
30 QTestMigrationState *state = opaque;
32 if (g_str_equal(name, "STOP")) {
33 state->stop_seen = true;
34 return true;
35 } else if (g_str_equal(name, "SUSPEND")) {
36 state->suspend_seen = true;
37 return true;
38 } else if (g_str_equal(name, "RESUME")) {
39 state->resume_seen = true;
40 return true;
43 return false;
46 void migrate_qmp_fail(QTestState *who, const char *uri, const char *fmt, ...)
48 va_list ap;
49 QDict *args, *err;
51 va_start(ap, fmt);
52 args = qdict_from_vjsonf_nofail(fmt, ap);
53 va_end(ap);
55 g_assert(!qdict_haskey(args, "uri"));
56 qdict_put_str(args, "uri", uri);
58 err = qtest_qmp_assert_failure_ref(
59 who, "{ 'execute': 'migrate', 'arguments': %p}", args);
61 g_assert(qdict_haskey(err, "desc"));
63 qobject_unref(err);
67 * Send QMP command "migrate".
68 * Arguments are built from @fmt... (formatted like
69 * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
71 void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
73 va_list ap;
74 QDict *args;
76 va_start(ap, fmt);
77 args = qdict_from_vjsonf_nofail(fmt, ap);
78 va_end(ap);
80 g_assert(!qdict_haskey(args, "uri"));
81 qdict_put_str(args, "uri", uri);
83 qtest_qmp_assert_success(who,
84 "{ 'execute': 'migrate', 'arguments': %p}", args);
87 void migrate_set_capability(QTestState *who, const char *capability,
88 bool value)
90 qtest_qmp_assert_success(who,
91 "{ 'execute': 'migrate-set-capabilities',"
92 "'arguments': { "
93 "'capabilities': [ { "
94 "'capability': %s, 'state': %i } ] } }",
95 capability, value);
98 void migrate_incoming_qmp(QTestState *to, const char *uri, const char *fmt, ...)
100 va_list ap;
101 QDict *args, *rsp, *data;
103 va_start(ap, fmt);
104 args = qdict_from_vjsonf_nofail(fmt, ap);
105 va_end(ap);
107 g_assert(!qdict_haskey(args, "uri"));
108 qdict_put_str(args, "uri", uri);
110 migrate_set_capability(to, "events", true);
112 rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
113 args);
115 if (!qdict_haskey(rsp, "return")) {
116 g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
117 g_test_message("%s", s->str);
120 g_assert(qdict_haskey(rsp, "return"));
121 qobject_unref(rsp);
123 rsp = qtest_qmp_eventwait_ref(to, "MIGRATION");
124 g_assert(qdict_haskey(rsp, "data"));
126 data = qdict_get_qdict(rsp, "data");
127 g_assert(qdict_haskey(data, "status"));
128 g_assert_cmpstr(qdict_get_str(data, "status"), ==, "setup");
130 qobject_unref(rsp);
134 * Note: caller is responsible to free the returned object via
135 * qobject_unref() after use
137 QDict *migrate_query(QTestState *who)
139 return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
142 QDict *migrate_query_not_failed(QTestState *who)
144 const char *status;
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"));
152 return rsp;
156 * Note: caller is responsible to free the returned object via
157 * g_free() after use
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"));
164 g_assert(status);
165 qobject_unref(rsp_return);
167 return status;
170 static bool check_migration_status(QTestState *who, const char *goal,
171 const char **ungoals)
173 bool ready;
174 char *current_status;
175 const char **ungoal;
177 current_status = migrate_query_status(who);
178 ready = strcmp(current_status, goal) == 0;
179 if (!ungoals) {
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
184 * hang.
186 if (strcmp(goal, "completed") != 0) {
187 g_assert_cmpstr(current_status, !=, "completed");
189 } else {
190 for (ungoal = ungoals; *ungoal; ungoal++) {
191 g_assert_cmpstr(current_status, !=, *ungoal);
194 g_free(current_status);
195 return ready;
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)) {
203 usleep(1000);
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();
217 QDict *rsp_return;
218 char *status;
219 bool failed;
221 do {
222 status = migrate_query_status(from);
223 bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
224 (allow_active && !strcmp(status, "active"));
225 if (!result) {
226 fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
227 __func__, status, allow_active);
229 g_assert(result);
230 failed = !strcmp(status, "failed");
231 g_free(status);
233 g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
234 } while (!failed);
236 /* Is the machine currently running? */
237 rsp_return = qtest_qmp_assert_success_ref(from,
238 "{ 'execute': 'query-status' }");
239 g_assert(qdict_haskey(rsp_return, "running"));
240 g_assert(qdict_get_bool(rsp_return, "running"));
241 qobject_unref(rsp_return);
244 char *find_common_machine_version(const char *mtype, const char *var1,
245 const char *var2)
247 g_autofree char *type1 = qtest_resolve_machine_alias(var1, mtype);
248 g_autofree char *type2 = qtest_resolve_machine_alias(var2, mtype);
250 g_assert(type1 && type2);
252 if (g_str_equal(type1, type2)) {
253 /* either can be used */
254 return g_strdup(type1);
257 if (qtest_has_machine_with_env(var2, type1)) {
258 return g_strdup(type1);
261 if (qtest_has_machine_with_env(var1, type2)) {
262 return g_strdup(type2);
265 g_test_message("No common machine version for machine type '%s' between "
266 "binaries %s and %s", mtype, getenv(var1), getenv(var2));
267 g_assert_not_reached();
270 char *resolve_machine_version(const char *alias, const char *var1,
271 const char *var2)
273 const char *mname = g_getenv("QTEST_QEMU_MACHINE_TYPE");
274 g_autofree char *machine_name = NULL;
276 if (mname) {
277 const char *dash = strrchr(mname, '-');
278 const char *dot = strrchr(mname, '.');
280 machine_name = g_strdup(mname);
282 if (dash && dot) {
283 assert(qtest_has_machine(machine_name));
284 return g_steal_pointer(&machine_name);
286 /* else: probably an alias, let it be resolved below */
287 } else {
288 /* use the hardcoded alias */
289 machine_name = g_strdup(alias);
292 return find_common_machine_version(machine_name, var1, var2);
295 typedef struct {
296 char *name;
297 void (*func)(void);
298 } MigrationTest;
300 static void migration_test_destroy(gpointer data)
302 MigrationTest *test = (MigrationTest *)data;
304 g_free(test->name);
305 g_free(test);
308 static void migration_test_wrapper(const void *data)
310 MigrationTest *test = (MigrationTest *)data;
312 g_test_message("Running /%s%s", qtest_get_arch(), test->name);
313 test->func();
316 void migration_test_add(const char *path, void (*fn)(void))
318 MigrationTest *test = g_new0(MigrationTest, 1);
320 test->func = fn;
321 test->name = g_strdup(path);
323 qtest_add_data_func_full(path, test, migration_test_wrapper,
324 migration_test_destroy);