xref: /openbmc/qemu/tests/qtest/migration/migration-qmp.c (revision 54e91d1523b412b4cff7cb36c898fa9dc133e886)
1e6c57040SFabiano Rosas /*
2e6c57040SFabiano Rosas  * QTest QMP helpers for migration
3e6c57040SFabiano Rosas  *
4e6c57040SFabiano Rosas  * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
5e6c57040SFabiano Rosas  *   based on the vhost-user-test.c that is:
6e6c57040SFabiano Rosas  *      Copyright (c) 2014 Virtual Open Systems Sarl.
7e6c57040SFabiano Rosas  *
8e6c57040SFabiano Rosas  * This work is licensed under the terms of the GNU GPL, version 2 or later.
9e6c57040SFabiano Rosas  * See the COPYING file in the top-level directory.
10e6c57040SFabiano Rosas  *
11e6c57040SFabiano Rosas  */
12e6c57040SFabiano Rosas 
13e6c57040SFabiano Rosas #include "qemu/osdep.h"
14e6c57040SFabiano Rosas #include "libqtest.h"
15e6c57040SFabiano Rosas #include "migration-qmp.h"
16b7d7f723SFabiano Rosas #include "migration-util.h"
17e6c57040SFabiano Rosas #include "qapi/error.h"
1843ca9d18SSteve Sistare #include "qapi/qapi-types-migration.h"
1943ca9d18SSteve Sistare #include "qapi/qapi-visit-migration.h"
20*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
21*407bc4bfSDaniel P. Berrangé #include "qobject/qjson.h"
22*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h"
2343ca9d18SSteve Sistare #include "qapi/qobject-input-visitor.h"
2443ca9d18SSteve Sistare #include "qapi/qobject-output-visitor.h"
25e6c57040SFabiano Rosas 
26e6c57040SFabiano Rosas /*
27e6c57040SFabiano Rosas  * Number of seconds we wait when looking for migration
28e6c57040SFabiano Rosas  * status changes, to avoid test suite hanging forever
29e6c57040SFabiano Rosas  * when things go wrong. Needs to be higher enough to
30e6c57040SFabiano Rosas  * avoid false positives on loaded hosts.
31e6c57040SFabiano Rosas  */
32e6c57040SFabiano Rosas #define MIGRATION_STATUS_WAIT_TIMEOUT 120
33e6c57040SFabiano Rosas 
34e6c57040SFabiano Rosas /*
35e6c57040SFabiano Rosas  * Wait for a "MIGRATION" event.  This is what Libvirt uses to track
36e6c57040SFabiano Rosas  * migration status changes.
37e6c57040SFabiano Rosas  */
migration_event_wait(QTestState * s,const char * target)38e6c57040SFabiano Rosas void migration_event_wait(QTestState *s, const char *target)
39e6c57040SFabiano Rosas {
40e6c57040SFabiano Rosas     QDict *response, *data;
41e6c57040SFabiano Rosas     const char *status;
42e6c57040SFabiano Rosas     bool found;
43e6c57040SFabiano Rosas 
44e6c57040SFabiano Rosas     do {
45e6c57040SFabiano Rosas         response = qtest_qmp_eventwait_ref(s, "MIGRATION");
46e6c57040SFabiano Rosas         data = qdict_get_qdict(response, "data");
47e6c57040SFabiano Rosas         g_assert(data);
48e6c57040SFabiano Rosas         status = qdict_get_str(data, "status");
49e6c57040SFabiano Rosas         found = (strcmp(status, target) == 0);
50e6c57040SFabiano Rosas         qobject_unref(response);
51e6c57040SFabiano Rosas     } while (!found);
52e6c57040SFabiano Rosas }
53e6c57040SFabiano Rosas 
5443ca9d18SSteve Sistare /*
5543ca9d18SSteve Sistare  * Convert a string representing a single channel to an object.
5643ca9d18SSteve Sistare  * @str may be in JSON or dotted keys format.
5743ca9d18SSteve Sistare  */
migrate_str_to_channel(const char * str)5843ca9d18SSteve Sistare QObject *migrate_str_to_channel(const char *str)
5943ca9d18SSteve Sistare {
6043ca9d18SSteve Sistare     Visitor *v;
6143ca9d18SSteve Sistare     MigrationChannel *channel;
6243ca9d18SSteve Sistare     QObject *obj;
6343ca9d18SSteve Sistare 
6443ca9d18SSteve Sistare     /* Create the channel */
6543ca9d18SSteve Sistare     v = qobject_input_visitor_new_str(str, "channel-type", &error_abort);
6643ca9d18SSteve Sistare     visit_type_MigrationChannel(v, NULL, &channel, &error_abort);
6743ca9d18SSteve Sistare     visit_free(v);
6843ca9d18SSteve Sistare 
6943ca9d18SSteve Sistare     /* Create the object */
7043ca9d18SSteve Sistare     v = qobject_output_visitor_new(&obj);
7143ca9d18SSteve Sistare     visit_type_MigrationChannel(v, NULL, &channel, &error_abort);
7243ca9d18SSteve Sistare     visit_complete(v, &obj);
7343ca9d18SSteve Sistare     visit_free(v);
7443ca9d18SSteve Sistare 
7543ca9d18SSteve Sistare     qapi_free_MigrationChannel(channel);
7643ca9d18SSteve Sistare     return obj;
7743ca9d18SSteve Sistare }
7843ca9d18SSteve Sistare 
migrate_qmp_fail(QTestState * who,const char * uri,QObject * channels,const char * fmt,...)79e6c57040SFabiano Rosas void migrate_qmp_fail(QTestState *who, const char *uri,
8043ca9d18SSteve Sistare                       QObject *channels, const char *fmt, ...)
81e6c57040SFabiano Rosas {
82e6c57040SFabiano Rosas     va_list ap;
83e6c57040SFabiano Rosas     QDict *args, *err;
84e6c57040SFabiano Rosas 
85e6c57040SFabiano Rosas     va_start(ap, fmt);
86e6c57040SFabiano Rosas     args = qdict_from_vjsonf_nofail(fmt, ap);
87e6c57040SFabiano Rosas     va_end(ap);
88e6c57040SFabiano Rosas 
89e6c57040SFabiano Rosas     g_assert(!qdict_haskey(args, "uri"));
90e6c57040SFabiano Rosas     if (uri) {
91e6c57040SFabiano Rosas         qdict_put_str(args, "uri", uri);
92e6c57040SFabiano Rosas     }
93e6c57040SFabiano Rosas 
94e6c57040SFabiano Rosas     g_assert(!qdict_haskey(args, "channels"));
95e6c57040SFabiano Rosas     if (channels) {
9643ca9d18SSteve Sistare         qdict_put_obj(args, "channels", channels);
97e6c57040SFabiano Rosas     }
98e6c57040SFabiano Rosas 
99e6c57040SFabiano Rosas     err = qtest_qmp_assert_failure_ref(
100e6c57040SFabiano Rosas         who, "{ 'execute': 'migrate', 'arguments': %p}", args);
101e6c57040SFabiano Rosas 
102e6c57040SFabiano Rosas     g_assert(qdict_haskey(err, "desc"));
103e6c57040SFabiano Rosas 
104e6c57040SFabiano Rosas     qobject_unref(err);
105e6c57040SFabiano Rosas }
106e6c57040SFabiano Rosas 
107e6c57040SFabiano Rosas /*
108e6c57040SFabiano Rosas  * Send QMP command "migrate".
109e6c57040SFabiano Rosas  * Arguments are built from @fmt... (formatted like
110e6c57040SFabiano Rosas  * qobject_from_jsonf_nofail()) with "uri": @uri spliced in.
111e6c57040SFabiano Rosas  */
migrate_qmp(QTestState * who,QTestState * to,const char * uri,QObject * channels,const char * fmt,...)112e6c57040SFabiano Rosas void migrate_qmp(QTestState *who, QTestState *to, const char *uri,
11343ca9d18SSteve Sistare                  QObject *channels, const char *fmt, ...)
114e6c57040SFabiano Rosas {
115e6c57040SFabiano Rosas     va_list ap;
116e6c57040SFabiano Rosas     QDict *args;
117e6c57040SFabiano Rosas     g_autofree char *connect_uri = NULL;
118e6c57040SFabiano Rosas 
119e6c57040SFabiano Rosas     va_start(ap, fmt);
120e6c57040SFabiano Rosas     args = qdict_from_vjsonf_nofail(fmt, ap);
121e6c57040SFabiano Rosas     va_end(ap);
122e6c57040SFabiano Rosas 
123e6c57040SFabiano Rosas     g_assert(!qdict_haskey(args, "uri"));
124e6c57040SFabiano Rosas     if (uri) {
125e6c57040SFabiano Rosas         qdict_put_str(args, "uri", uri);
126e6c57040SFabiano Rosas     } else if (!channels) {
127e6c57040SFabiano Rosas         connect_uri = migrate_get_connect_uri(to);
128e6c57040SFabiano Rosas         qdict_put_str(args, "uri", connect_uri);
129e6c57040SFabiano Rosas     }
130e6c57040SFabiano Rosas 
131e6c57040SFabiano Rosas     g_assert(!qdict_haskey(args, "channels"));
132e6c57040SFabiano Rosas     if (channels) {
13343ca9d18SSteve Sistare         QList *channel_list = qobject_to(QList, channels);
134e6c57040SFabiano Rosas         migrate_set_ports(to, channel_list);
13543ca9d18SSteve Sistare         qdict_put_obj(args, "channels", channels);
136e6c57040SFabiano Rosas     }
137e6c57040SFabiano Rosas 
138e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
139e6c57040SFabiano Rosas                              "{ 'execute': 'migrate', 'arguments': %p}", args);
140e6c57040SFabiano Rosas }
141e6c57040SFabiano Rosas 
migrate_set_capability(QTestState * who,const char * capability,bool value)142e6c57040SFabiano Rosas void migrate_set_capability(QTestState *who, const char *capability,
143e6c57040SFabiano Rosas                             bool value)
144e6c57040SFabiano Rosas {
145e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
146e6c57040SFabiano Rosas                              "{ 'execute': 'migrate-set-capabilities',"
147e6c57040SFabiano Rosas                              "'arguments': { "
148e6c57040SFabiano Rosas                              "'capabilities': [ { "
149e6c57040SFabiano Rosas                              "'capability': %s, 'state': %i } ] } }",
150e6c57040SFabiano Rosas                              capability, value);
151e6c57040SFabiano Rosas }
152e6c57040SFabiano Rosas 
migrate_incoming_qmp(QTestState * to,const char * uri,QObject * channels,const char * fmt,...)15343ca9d18SSteve Sistare void migrate_incoming_qmp(QTestState *to, const char *uri, QObject *channels,
15443ca9d18SSteve Sistare                           const char *fmt, ...)
155e6c57040SFabiano Rosas {
156e6c57040SFabiano Rosas     va_list ap;
157e6c57040SFabiano Rosas     QDict *args, *rsp;
158e6c57040SFabiano Rosas 
159e6c57040SFabiano Rosas     va_start(ap, fmt);
160e6c57040SFabiano Rosas     args = qdict_from_vjsonf_nofail(fmt, ap);
161e6c57040SFabiano Rosas     va_end(ap);
162e6c57040SFabiano Rosas 
163e6c57040SFabiano Rosas     g_assert(!qdict_haskey(args, "uri"));
16443ca9d18SSteve Sistare     if (uri) {
165e6c57040SFabiano Rosas         qdict_put_str(args, "uri", uri);
16643ca9d18SSteve Sistare     }
16743ca9d18SSteve Sistare 
16843ca9d18SSteve Sistare     g_assert(!qdict_haskey(args, "channels"));
16943ca9d18SSteve Sistare     if (channels) {
17043ca9d18SSteve Sistare         qdict_put_obj(args, "channels", channels);
17143ca9d18SSteve Sistare     }
172e6c57040SFabiano Rosas 
173e6c57040SFabiano Rosas     /* This function relies on the event to work, make sure it's enabled */
174e6c57040SFabiano Rosas     migrate_set_capability(to, "events", true);
175e6c57040SFabiano Rosas 
176e6c57040SFabiano Rosas     rsp = qtest_qmp(to, "{ 'execute': 'migrate-incoming', 'arguments': %p}",
177e6c57040SFabiano Rosas                     args);
178e6c57040SFabiano Rosas 
179e6c57040SFabiano Rosas     if (!qdict_haskey(rsp, "return")) {
180e6c57040SFabiano Rosas         g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(rsp), true);
181e6c57040SFabiano Rosas         g_test_message("%s", s->str);
182e6c57040SFabiano Rosas     }
183e6c57040SFabiano Rosas 
184e6c57040SFabiano Rosas     g_assert(qdict_haskey(rsp, "return"));
185e6c57040SFabiano Rosas     qobject_unref(rsp);
186e6c57040SFabiano Rosas 
187e6c57040SFabiano Rosas     migration_event_wait(to, "setup");
188e6c57040SFabiano Rosas }
189e6c57040SFabiano Rosas 
check_migration_status(QTestState * who,const char * goal,const char ** ungoals)190e6c57040SFabiano Rosas static bool check_migration_status(QTestState *who, const char *goal,
191e6c57040SFabiano Rosas                                    const char **ungoals)
192e6c57040SFabiano Rosas {
193e6c57040SFabiano Rosas     bool ready;
194e6c57040SFabiano Rosas     char *current_status;
195e6c57040SFabiano Rosas     const char **ungoal;
196e6c57040SFabiano Rosas 
197e6c57040SFabiano Rosas     current_status = migrate_query_status(who);
198e6c57040SFabiano Rosas     ready = strcmp(current_status, goal) == 0;
199e6c57040SFabiano Rosas     if (!ungoals) {
200e6c57040SFabiano Rosas         g_assert_cmpstr(current_status, !=, "failed");
201e6c57040SFabiano Rosas         /*
202e6c57040SFabiano Rosas          * If looking for a state other than completed,
203e6c57040SFabiano Rosas          * completion of migration would cause the test to
204e6c57040SFabiano Rosas          * hang.
205e6c57040SFabiano Rosas          */
206e6c57040SFabiano Rosas         if (strcmp(goal, "completed") != 0) {
207e6c57040SFabiano Rosas             g_assert_cmpstr(current_status, !=, "completed");
208e6c57040SFabiano Rosas         }
209e6c57040SFabiano Rosas     } else {
210e6c57040SFabiano Rosas         for (ungoal = ungoals; *ungoal; ungoal++) {
211e6c57040SFabiano Rosas             g_assert_cmpstr(current_status, !=,  *ungoal);
212e6c57040SFabiano Rosas         }
213e6c57040SFabiano Rosas     }
214e6c57040SFabiano Rosas     g_free(current_status);
215e6c57040SFabiano Rosas     return ready;
216e6c57040SFabiano Rosas }
217e6c57040SFabiano Rosas 
wait_for_migration_status(QTestState * who,const char * goal,const char ** ungoals)218e6c57040SFabiano Rosas void wait_for_migration_status(QTestState *who,
219e6c57040SFabiano Rosas                                const char *goal, const char **ungoals)
220e6c57040SFabiano Rosas {
221e6c57040SFabiano Rosas     g_test_timer_start();
222e6c57040SFabiano Rosas     while (!check_migration_status(who, goal, ungoals)) {
223e6c57040SFabiano Rosas         usleep(1000);
224e6c57040SFabiano Rosas 
225e6c57040SFabiano Rosas         g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
226e6c57040SFabiano Rosas     }
227e6c57040SFabiano Rosas }
228e6c57040SFabiano Rosas 
wait_for_migration_complete(QTestState * who)229e6c57040SFabiano Rosas void wait_for_migration_complete(QTestState *who)
230e6c57040SFabiano Rosas {
231e6c57040SFabiano Rosas     wait_for_migration_status(who, "completed", NULL);
232e6c57040SFabiano Rosas }
233e6c57040SFabiano Rosas 
wait_for_migration_fail(QTestState * from,bool allow_active)234e6c57040SFabiano Rosas void wait_for_migration_fail(QTestState *from, bool allow_active)
235e6c57040SFabiano Rosas {
236e6c57040SFabiano Rosas     g_test_timer_start();
237e6c57040SFabiano Rosas     QDict *rsp_return;
238e6c57040SFabiano Rosas     char *status;
239e6c57040SFabiano Rosas     bool failed;
240e6c57040SFabiano Rosas 
241e6c57040SFabiano Rosas     do {
242e6c57040SFabiano Rosas         status = migrate_query_status(from);
243e6c57040SFabiano Rosas         bool result = !strcmp(status, "setup") || !strcmp(status, "failed") ||
244e6c57040SFabiano Rosas             (allow_active && !strcmp(status, "active"));
245e6c57040SFabiano Rosas         if (!result) {
246e6c57040SFabiano Rosas             fprintf(stderr, "%s: unexpected status status=%s allow_active=%d\n",
247e6c57040SFabiano Rosas                     __func__, status, allow_active);
248e6c57040SFabiano Rosas         }
249e6c57040SFabiano Rosas         g_assert(result);
250e6c57040SFabiano Rosas         failed = !strcmp(status, "failed");
251e6c57040SFabiano Rosas         g_free(status);
252e6c57040SFabiano Rosas 
253e6c57040SFabiano Rosas         g_assert(g_test_timer_elapsed() < MIGRATION_STATUS_WAIT_TIMEOUT);
254e6c57040SFabiano Rosas     } while (!failed);
255e6c57040SFabiano Rosas 
256e6c57040SFabiano Rosas     /* Is the machine currently running? */
257e6c57040SFabiano Rosas     rsp_return = qtest_qmp_assert_success_ref(from,
258e6c57040SFabiano Rosas                                               "{ 'execute': 'query-status' }");
259e6c57040SFabiano Rosas     g_assert(qdict_haskey(rsp_return, "running"));
260e6c57040SFabiano Rosas     g_assert(qdict_get_bool(rsp_return, "running"));
261e6c57040SFabiano Rosas     qobject_unref(rsp_return);
262e6c57040SFabiano Rosas }
263e6c57040SFabiano Rosas 
wait_for_stop(QTestState * who,QTestMigrationState * state)264e6c57040SFabiano Rosas void wait_for_stop(QTestState *who, QTestMigrationState *state)
265e6c57040SFabiano Rosas {
266e6c57040SFabiano Rosas     if (!state->stop_seen) {
267e6c57040SFabiano Rosas         qtest_qmp_eventwait(who, "STOP");
268e6c57040SFabiano Rosas     }
269e6c57040SFabiano Rosas }
270e6c57040SFabiano Rosas 
wait_for_resume(QTestState * who,QTestMigrationState * state)271e6c57040SFabiano Rosas void wait_for_resume(QTestState *who, QTestMigrationState *state)
272e6c57040SFabiano Rosas {
273e6c57040SFabiano Rosas     if (!state->resume_seen) {
274e6c57040SFabiano Rosas         qtest_qmp_eventwait(who, "RESUME");
275e6c57040SFabiano Rosas     }
276e6c57040SFabiano Rosas }
277e6c57040SFabiano Rosas 
wait_for_suspend(QTestState * who,QTestMigrationState * state)278e6c57040SFabiano Rosas void wait_for_suspend(QTestState *who, QTestMigrationState *state)
279e6c57040SFabiano Rosas {
280e6c57040SFabiano Rosas     if (state->suspend_me && !state->suspend_seen) {
281e6c57040SFabiano Rosas         qtest_qmp_eventwait(who, "SUSPEND");
282e6c57040SFabiano Rosas     }
283e6c57040SFabiano Rosas }
284e6c57040SFabiano Rosas 
285e6c57040SFabiano Rosas /*
286e6c57040SFabiano Rosas  * Note: caller is responsible to free the returned object via
287e6c57040SFabiano Rosas  * qobject_unref() after use
288e6c57040SFabiano Rosas  */
migrate_query(QTestState * who)289e6c57040SFabiano Rosas QDict *migrate_query(QTestState *who)
290e6c57040SFabiano Rosas {
291e6c57040SFabiano Rosas     return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
292e6c57040SFabiano Rosas }
293e6c57040SFabiano Rosas 
migrate_query_not_failed(QTestState * who)294e6c57040SFabiano Rosas QDict *migrate_query_not_failed(QTestState *who)
295e6c57040SFabiano Rosas {
296e6c57040SFabiano Rosas     const char *status;
297e6c57040SFabiano Rosas     QDict *rsp = migrate_query(who);
298e6c57040SFabiano Rosas     status = qdict_get_str(rsp, "status");
299e6c57040SFabiano Rosas     if (g_str_equal(status, "failed")) {
300e6c57040SFabiano Rosas         g_printerr("query-migrate shows failed migration: %s\n",
301e6c57040SFabiano Rosas                    qdict_get_str(rsp, "error-desc"));
302e6c57040SFabiano Rosas     }
303e6c57040SFabiano Rosas     g_assert(!g_str_equal(status, "failed"));
304e6c57040SFabiano Rosas     return rsp;
305e6c57040SFabiano Rosas }
306e6c57040SFabiano Rosas 
307e6c57040SFabiano Rosas /*
308e6c57040SFabiano Rosas  * Note: caller is responsible to free the returned object via
309e6c57040SFabiano Rosas  * g_free() after use
310e6c57040SFabiano Rosas  */
migrate_query_status(QTestState * who)311e6c57040SFabiano Rosas gchar *migrate_query_status(QTestState *who)
312e6c57040SFabiano Rosas {
313e6c57040SFabiano Rosas     QDict *rsp_return = migrate_query(who);
314e6c57040SFabiano Rosas     gchar *status = g_strdup(qdict_get_str(rsp_return, "status"));
315e6c57040SFabiano Rosas 
316e6c57040SFabiano Rosas     g_assert(status);
317e6c57040SFabiano Rosas     qobject_unref(rsp_return);
318e6c57040SFabiano Rosas 
319e6c57040SFabiano Rosas     return status;
320e6c57040SFabiano Rosas }
321e6c57040SFabiano Rosas 
read_ram_property_int(QTestState * who,const char * property)322e6c57040SFabiano Rosas int64_t read_ram_property_int(QTestState *who, const char *property)
323e6c57040SFabiano Rosas {
324e6c57040SFabiano Rosas     QDict *rsp_return, *rsp_ram;
325e6c57040SFabiano Rosas     int64_t result;
326e6c57040SFabiano Rosas 
327e6c57040SFabiano Rosas     rsp_return = migrate_query_not_failed(who);
328e6c57040SFabiano Rosas     if (!qdict_haskey(rsp_return, "ram")) {
329e6c57040SFabiano Rosas         /* Still in setup */
330e6c57040SFabiano Rosas         result = 0;
331e6c57040SFabiano Rosas     } else {
332e6c57040SFabiano Rosas         rsp_ram = qdict_get_qdict(rsp_return, "ram");
333e6c57040SFabiano Rosas         result = qdict_get_try_int(rsp_ram, property, 0);
334e6c57040SFabiano Rosas     }
335e6c57040SFabiano Rosas     qobject_unref(rsp_return);
336e6c57040SFabiano Rosas     return result;
337e6c57040SFabiano Rosas }
338e6c57040SFabiano Rosas 
read_migrate_property_int(QTestState * who,const char * property)339e6c57040SFabiano Rosas int64_t read_migrate_property_int(QTestState *who, const char *property)
340e6c57040SFabiano Rosas {
341e6c57040SFabiano Rosas     QDict *rsp_return;
342e6c57040SFabiano Rosas     int64_t result;
343e6c57040SFabiano Rosas 
344e6c57040SFabiano Rosas     rsp_return = migrate_query_not_failed(who);
345e6c57040SFabiano Rosas     result = qdict_get_try_int(rsp_return, property, 0);
346e6c57040SFabiano Rosas     qobject_unref(rsp_return);
347e6c57040SFabiano Rosas     return result;
348e6c57040SFabiano Rosas }
349e6c57040SFabiano Rosas 
get_migration_pass(QTestState * who)350e6c57040SFabiano Rosas uint64_t get_migration_pass(QTestState *who)
351e6c57040SFabiano Rosas {
352e6c57040SFabiano Rosas     return read_ram_property_int(who, "dirty-sync-count");
353e6c57040SFabiano Rosas }
354e6c57040SFabiano Rosas 
read_blocktime(QTestState * who)355e6c57040SFabiano Rosas void read_blocktime(QTestState *who)
356e6c57040SFabiano Rosas {
357e6c57040SFabiano Rosas     QDict *rsp_return;
358e6c57040SFabiano Rosas 
359e6c57040SFabiano Rosas     rsp_return = migrate_query_not_failed(who);
360e6c57040SFabiano Rosas     g_assert(qdict_haskey(rsp_return, "postcopy-blocktime"));
361e6c57040SFabiano Rosas     qobject_unref(rsp_return);
362e6c57040SFabiano Rosas }
363e6c57040SFabiano Rosas 
364e6c57040SFabiano Rosas /*
365e6c57040SFabiano Rosas  * Wait for two changes in the migration pass count, but bail if we stop.
366e6c57040SFabiano Rosas  */
wait_for_migration_pass(QTestState * who,QTestMigrationState * src_state)367e6c57040SFabiano Rosas void wait_for_migration_pass(QTestState *who, QTestMigrationState *src_state)
368e6c57040SFabiano Rosas {
369e6c57040SFabiano Rosas     uint64_t pass, prev_pass = 0, changes = 0;
370e6c57040SFabiano Rosas 
371e6c57040SFabiano Rosas     while (changes < 2 && !src_state->stop_seen && !src_state->suspend_seen) {
372e6c57040SFabiano Rosas         usleep(1000);
373e6c57040SFabiano Rosas         pass = get_migration_pass(who);
374e6c57040SFabiano Rosas         changes += (pass != prev_pass);
375e6c57040SFabiano Rosas         prev_pass = pass;
376e6c57040SFabiano Rosas     }
377e6c57040SFabiano Rosas }
378e6c57040SFabiano Rosas 
migrate_get_parameter_int(QTestState * who,const char * parameter)379e6c57040SFabiano Rosas static long long migrate_get_parameter_int(QTestState *who,
380e6c57040SFabiano Rosas                                            const char *parameter)
381e6c57040SFabiano Rosas {
382e6c57040SFabiano Rosas     QDict *rsp;
383e6c57040SFabiano Rosas     long long result;
384e6c57040SFabiano Rosas 
385e6c57040SFabiano Rosas     rsp = qtest_qmp_assert_success_ref(
386e6c57040SFabiano Rosas         who, "{ 'execute': 'query-migrate-parameters' }");
387e6c57040SFabiano Rosas     result = qdict_get_int(rsp, parameter);
388e6c57040SFabiano Rosas     qobject_unref(rsp);
389e6c57040SFabiano Rosas     return result;
390e6c57040SFabiano Rosas }
391e6c57040SFabiano Rosas 
migrate_check_parameter_int(QTestState * who,const char * parameter,long long value)392e6c57040SFabiano Rosas static void migrate_check_parameter_int(QTestState *who, const char *parameter,
393e6c57040SFabiano Rosas                                         long long value)
394e6c57040SFabiano Rosas {
395e6c57040SFabiano Rosas     long long result;
396e6c57040SFabiano Rosas 
397e6c57040SFabiano Rosas     result = migrate_get_parameter_int(who, parameter);
398e6c57040SFabiano Rosas     g_assert_cmpint(result, ==, value);
399e6c57040SFabiano Rosas }
400e6c57040SFabiano Rosas 
migrate_set_parameter_int(QTestState * who,const char * parameter,long long value)401e6c57040SFabiano Rosas void migrate_set_parameter_int(QTestState *who, const char *parameter,
402e6c57040SFabiano Rosas                                long long value)
403e6c57040SFabiano Rosas {
404e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
405e6c57040SFabiano Rosas                              "{ 'execute': 'migrate-set-parameters',"
406e6c57040SFabiano Rosas                              "'arguments': { %s: %lld } }",
407e6c57040SFabiano Rosas                              parameter, value);
408e6c57040SFabiano Rosas     migrate_check_parameter_int(who, parameter, value);
409e6c57040SFabiano Rosas }
410e6c57040SFabiano Rosas 
migrate_get_parameter_str(QTestState * who,const char * parameter)411e6c57040SFabiano Rosas static char *migrate_get_parameter_str(QTestState *who, const char *parameter)
412e6c57040SFabiano Rosas {
413e6c57040SFabiano Rosas     QDict *rsp;
414e6c57040SFabiano Rosas     char *result;
415e6c57040SFabiano Rosas 
416e6c57040SFabiano Rosas     rsp = qtest_qmp_assert_success_ref(
417e6c57040SFabiano Rosas         who, "{ 'execute': 'query-migrate-parameters' }");
418e6c57040SFabiano Rosas     result = g_strdup(qdict_get_str(rsp, parameter));
419e6c57040SFabiano Rosas     qobject_unref(rsp);
420e6c57040SFabiano Rosas     return result;
421e6c57040SFabiano Rosas }
422e6c57040SFabiano Rosas 
migrate_check_parameter_str(QTestState * who,const char * parameter,const char * value)423e6c57040SFabiano Rosas static void migrate_check_parameter_str(QTestState *who, const char *parameter,
424e6c57040SFabiano Rosas                                         const char *value)
425e6c57040SFabiano Rosas {
426e6c57040SFabiano Rosas     g_autofree char *result = migrate_get_parameter_str(who, parameter);
427e6c57040SFabiano Rosas     g_assert_cmpstr(result, ==, value);
428e6c57040SFabiano Rosas }
429e6c57040SFabiano Rosas 
migrate_set_parameter_str(QTestState * who,const char * parameter,const char * value)430e6c57040SFabiano Rosas void migrate_set_parameter_str(QTestState *who, const char *parameter,
431e6c57040SFabiano Rosas                                const char *value)
432e6c57040SFabiano Rosas {
433e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
434e6c57040SFabiano Rosas                              "{ 'execute': 'migrate-set-parameters',"
435e6c57040SFabiano Rosas                              "'arguments': { %s: %s } }",
436e6c57040SFabiano Rosas                              parameter, value);
437e6c57040SFabiano Rosas     migrate_check_parameter_str(who, parameter, value);
438e6c57040SFabiano Rosas }
439e6c57040SFabiano Rosas 
migrate_get_parameter_bool(QTestState * who,const char * parameter)440e6c57040SFabiano Rosas static long long migrate_get_parameter_bool(QTestState *who,
441e6c57040SFabiano Rosas                                             const char *parameter)
442e6c57040SFabiano Rosas {
443e6c57040SFabiano Rosas     QDict *rsp;
444e6c57040SFabiano Rosas     int result;
445e6c57040SFabiano Rosas 
446e6c57040SFabiano Rosas     rsp = qtest_qmp_assert_success_ref(
447e6c57040SFabiano Rosas         who, "{ 'execute': 'query-migrate-parameters' }");
448e6c57040SFabiano Rosas     result = qdict_get_bool(rsp, parameter);
449e6c57040SFabiano Rosas     qobject_unref(rsp);
450e6c57040SFabiano Rosas     return !!result;
451e6c57040SFabiano Rosas }
452e6c57040SFabiano Rosas 
migrate_check_parameter_bool(QTestState * who,const char * parameter,int value)453e6c57040SFabiano Rosas static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
454e6c57040SFabiano Rosas                                          int value)
455e6c57040SFabiano Rosas {
456e6c57040SFabiano Rosas     int result;
457e6c57040SFabiano Rosas 
458e6c57040SFabiano Rosas     result = migrate_get_parameter_bool(who, parameter);
459e6c57040SFabiano Rosas     g_assert_cmpint(result, ==, value);
460e6c57040SFabiano Rosas }
461e6c57040SFabiano Rosas 
migrate_set_parameter_bool(QTestState * who,const char * parameter,int value)462e6c57040SFabiano Rosas void migrate_set_parameter_bool(QTestState *who, const char *parameter,
463e6c57040SFabiano Rosas                                 int value)
464e6c57040SFabiano Rosas {
465e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
466e6c57040SFabiano Rosas                              "{ 'execute': 'migrate-set-parameters',"
467e6c57040SFabiano Rosas                              "'arguments': { %s: %i } }",
468e6c57040SFabiano Rosas                              parameter, value);
469e6c57040SFabiano Rosas     migrate_check_parameter_bool(who, parameter, value);
470e6c57040SFabiano Rosas }
471e6c57040SFabiano Rosas 
migrate_ensure_non_converge(QTestState * who)472e6c57040SFabiano Rosas void migrate_ensure_non_converge(QTestState *who)
473e6c57040SFabiano Rosas {
474e6c57040SFabiano Rosas     /* Can't converge with 1ms downtime + 3 mbs bandwidth limit */
475e6c57040SFabiano Rosas     migrate_set_parameter_int(who, "max-bandwidth", 3 * 1000 * 1000);
476e6c57040SFabiano Rosas     migrate_set_parameter_int(who, "downtime-limit", 1);
477e6c57040SFabiano Rosas }
478e6c57040SFabiano Rosas 
migrate_ensure_converge(QTestState * who)479e6c57040SFabiano Rosas void migrate_ensure_converge(QTestState *who)
480e6c57040SFabiano Rosas {
481e6c57040SFabiano Rosas     /* Should converge with 30s downtime + 1 gbs bandwidth limit */
482e6c57040SFabiano Rosas     migrate_set_parameter_int(who, "max-bandwidth", 1 * 1000 * 1000 * 1000);
483e6c57040SFabiano Rosas     migrate_set_parameter_int(who, "downtime-limit", 30 * 1000);
484e6c57040SFabiano Rosas }
485e6c57040SFabiano Rosas 
migrate_pause(QTestState * who)486e6c57040SFabiano Rosas void migrate_pause(QTestState *who)
487e6c57040SFabiano Rosas {
488e6c57040SFabiano Rosas     qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
489e6c57040SFabiano Rosas }
490e6c57040SFabiano Rosas 
migrate_continue(QTestState * who,const char * state)491e6c57040SFabiano Rosas void migrate_continue(QTestState *who, const char *state)
492e6c57040SFabiano Rosas {
493e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
494e6c57040SFabiano Rosas                              "{ 'execute': 'migrate-continue',"
495e6c57040SFabiano Rosas                              "  'arguments': { 'state': %s } }",
496e6c57040SFabiano Rosas                              state);
497e6c57040SFabiano Rosas }
498e6c57040SFabiano Rosas 
migrate_recover(QTestState * who,const char * uri)499e6c57040SFabiano Rosas void migrate_recover(QTestState *who, const char *uri)
500e6c57040SFabiano Rosas {
501e6c57040SFabiano Rosas     qtest_qmp_assert_success(who,
5023dec966fSJuraj Marcin                              "{ 'exec-oob': 'migrate-recover', "
503e6c57040SFabiano Rosas                              "  'id': 'recover-cmd', "
504e6c57040SFabiano Rosas                              "  'arguments': { 'uri': %s } }",
505e6c57040SFabiano Rosas                              uri);
506e6c57040SFabiano Rosas }
507e6c57040SFabiano Rosas 
migrate_cancel(QTestState * who)508e6c57040SFabiano Rosas void migrate_cancel(QTestState *who)
509e6c57040SFabiano Rosas {
510e6c57040SFabiano Rosas     qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
511e6c57040SFabiano Rosas }
512e6c57040SFabiano Rosas 
migrate_postcopy_start(QTestState * from,QTestState * to,QTestMigrationState * src_state)513e6c57040SFabiano Rosas void migrate_postcopy_start(QTestState *from, QTestState *to,
514e6c57040SFabiano Rosas                             QTestMigrationState *src_state)
515e6c57040SFabiano Rosas {
516e6c57040SFabiano Rosas     qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
517e6c57040SFabiano Rosas 
518e6c57040SFabiano Rosas     wait_for_stop(from, src_state);
519e6c57040SFabiano Rosas     qtest_qmp_eventwait(to, "RESUME");
520e6c57040SFabiano Rosas }
521