]> git.proxmox.com Git - mirror_qemu.git/blob - tests/qtest/migration-helpers.c
9pfs: add link to 9p developer docs
[mirror_qemu.git] / tests / qtest / migration-helpers.c
1 /*
2 * QTest migration helpers
3 *
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.
7 *
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.
10 *
11 */
12
13 #include "qemu/osdep.h"
14 #include "qapi/qmp/qjson.h"
15
16 #include "migration-helpers.h"
17
18 bool got_stop;
19
20 static void check_stop_event(QTestState *who)
21 {
22 QDict *event = qtest_qmp_event_ref(who, "STOP");
23 if (event) {
24 got_stop = true;
25 qobject_unref(event);
26 }
27 }
28
29 /*
30 * Events can get in the way of responses we are actually waiting for.
31 */
32 QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
33 {
34 va_list ap;
35 QDict *resp, *ret;
36
37 va_start(ap, command);
38 qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
39 va_end(ap);
40
41 resp = qtest_qmp_receive(who);
42 check_stop_event(who);
43
44 g_assert(!qdict_haskey(resp, "error"));
45 g_assert(qdict_haskey(resp, "return"));
46
47 ret = qdict_get_qdict(resp, "return");
48 qobject_ref(ret);
49 qobject_unref(resp);
50
51 return ret;
52 }
53
54 /*
55 * Events can get in the way of responses we are actually waiting for.
56 */
57 QDict *wait_command(QTestState *who, const char *command, ...)
58 {
59 va_list ap;
60 QDict *resp, *ret;
61
62 va_start(ap, command);
63 resp = qtest_vqmp(who, command, ap);
64 va_end(ap);
65
66 check_stop_event(who);
67
68 g_assert(!qdict_haskey(resp, "error"));
69 g_assert(qdict_haskey(resp, "return"));
70
71 ret = qdict_get_qdict(resp, "return");
72 qobject_ref(ret);
73 qobject_unref(resp);
74
75 return ret;
76 }
77
78 /*
79 * Send QMP command "migrate".
80 * Arguments are built from @fmt... (formatted like
81 * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
82 */
83 void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
84 {
85 va_list ap;
86 QDict *args, *rsp;
87
88 va_start(ap, fmt);
89 args = qdict_from_vjsonf_nofail(fmt, ap);
90 va_end(ap);
91
92 g_assert(!qdict_haskey(args, "uri"));
93 qdict_put_str(args, "uri", uri);
94
95 rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
96
97 g_assert(qdict_haskey(rsp, "return"));
98 qobject_unref(rsp);
99 }
100
101 /*
102 * Note: caller is responsible to free the returned object via
103 * qobject_unref() after use
104 */
105 QDict *migrate_query(QTestState *who)
106 {
107 return wait_command(who, "{ 'execute': 'query-migrate' }");
108 }
109
110 /*
111 * Note: caller is responsible to free the returned object via
112 * g_free() after use
113 */
114 static gchar *migrate_query_status(QTestState *who)
115 {
116 QDict *rsp_return = migrate_query(who);
117 gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
118
119 g_assert(status);
120 qobject_unref(rsp_return);
121
122 return status;
123 }
124
125 static bool check_migration_status(QTestState *who, const char *goal,
126 const char **ungoals)
127 {
128 bool ready;
129 char *current_status;
130 const char **ungoal;
131
132 current_status = migrate_query_status(who);
133 ready = strcmp(current_status, goal) == 0;
134 if (!ungoals) {
135 g_assert_cmpstr(current_status, !=, "failed");
136 /*
137 * If looking for a state other than completed,
138 * completion of migration would cause the test to
139 * hang.
140 */
141 if (strcmp(goal, "completed") != 0) {
142 g_assert_cmpstr(current_status, !=, "completed");
143 }
144 } else {
145 for (ungoal = ungoals; *ungoal; ungoal++) {
146 g_assert_cmpstr(current_status, !=, *ungoal);
147 }
148 }
149 g_free(current_status);
150 return ready;
151 }
152
153 void wait_for_migration_status(QTestState *who,
154 const char *goal, const char **ungoals)
155 {
156 while (!check_migration_status(who, goal, ungoals)) {
157 usleep(1000);
158 }
159 }
160
161 void wait_for_migration_complete(QTestState *who)
162 {
163 wait_for_migration_status(who, "completed", NULL);
164 }
165
166 void wait_for_migration_fail(QTestState *from, bool allow_active)
167 {
168 QDict *rsp_return;
169 char *status;
170 bool failed;
171
172 do {
173 status = migrate_query_status(from);
174 bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
175 (allow_active && !strcmp(status, "active"));
176 if (!result) {
177 fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
178 __func__, status, allow_active);
179 }
180 g_assert(result);
181 failed = !strcmp(status, "failed");
182 g_free(status);
183 } while (!failed);
184
185 /* Is the machine currently running? */
186 rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
187 g_assert(qdict_haskey(rsp_return, "running"));
188 g_assert(qdict_get_bool(rsp_return, "running"));
189 qobject_unref(rsp_return);
190 }