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
26 bool migrate_watch_for_stop(QTestState
*who
, const char *name
,
27 QDict
*event
, void *opaque
)
31 if (g_str_equal(name
, "STOP")) {
39 bool migrate_watch_for_resume(QTestState
*who
, const char *name
,
40 QDict
*event
, void *opaque
)
44 if (g_str_equal(name
, "RESUME")) {
52 void migrate_qmp_fail(QTestState
*who
, const char *uri
, const char *fmt
, ...)
58 args
= qdict_from_vjsonf_nofail(fmt
, ap
);
61 g_assert(!qdict_haskey(args
, "uri"));
62 qdict_put_str(args
, "uri", uri
);
64 err
= qtest_qmp_assert_failure_ref(
65 who
, "{ 'execute': 'migrate', 'arguments': %p}", args
);
67 g_assert(qdict_haskey(err
, "desc"));
73 * Send QMP command "migrate".
74 * Arguments are built from @fmt... (formatted like
75 * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
77 void migrate_qmp(QTestState
*who
, const char *uri
, const char *fmt
, ...)
83 args
= qdict_from_vjsonf_nofail(fmt
, ap
);
86 g_assert(!qdict_haskey(args
, "uri"));
87 qdict_put_str(args
, "uri", uri
);
89 qtest_qmp_assert_success(who
,
90 "{ 'execute': 'migrate', 'arguments': %p}", args
);
93 void migrate_set_capability(QTestState
*who
, const char *capability
,
96 qtest_qmp_assert_success(who
,
97 "{ 'execute': 'migrate-set-capabilities',"
99 "'capabilities': [ { "
100 "'capability': %s, 'state': %i } ] } }",
104 void migrate_incoming_qmp(QTestState
*to
, const char *uri
, const char *fmt
, ...)
107 QDict
*args
, *rsp
, *data
;
110 args
= qdict_from_vjsonf_nofail(fmt
, ap
);
113 g_assert(!qdict_haskey(args
, "uri"));
114 qdict_put_str(args
, "uri", uri
);
116 migrate_set_capability(to
, "events", true);
118 rsp
= qtest_qmp(to
, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
120 g_assert(qdict_haskey(rsp
, "return"));
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");
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
)
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
= 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
);