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