]> Git Repo - qemu.git/blame - tests/qmp-test.c
tests/libqos: Utilize newer glib spawn check
[qemu.git] / tests / qmp-test.c
CommitLineData
f66e7ac8
MA
1/*
2 * QMP protocol test cases
3 *
aed877c5 4 * Copyright (c) 2017-2018 Red Hat Inc.
f66e7ac8
MA
5 *
6 * Authors:
d93bb9d5 7 * Markus Armbruster <[email protected]>
f66e7ac8
MA
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13#include "qemu/osdep.h"
14#include "libqtest.h"
f66e7ac8 15#include "qapi/error.h"
112ed241 16#include "qapi/qapi-visit-misc.h"
452fcdbc 17#include "qapi/qmp/qdict.h"
47e6b297 18#include "qapi/qmp/qlist.h"
f66e7ac8 19#include "qapi/qobject-input-visitor.h"
02130314 20#include "qapi/qmp/qstring.h"
f66e7ac8
MA
21
22const char common_args[] = "-nodefaults -machine none";
23
24static const char *get_error_class(QDict *resp)
25{
26 QDict *error = qdict_get_qdict(resp, "error");
27 const char *desc = qdict_get_try_str(error, "desc");
28
29 g_assert(desc);
30 return error ? qdict_get_try_str(error, "class") : NULL;
31}
32
33static void test_version(QObject *version)
34{
35 Visitor *v;
36 VersionInfo *vinfo;
37
38 g_assert(version);
048abb7b 39 v = qobject_input_visitor_new(version);
f66e7ac8
MA
40 visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
41 qapi_free_VersionInfo(vinfo);
42 visit_free(v);
43}
44
aed877c5
MA
45static bool recovered(QTestState *qts)
46{
47 QDict *resp;
48 bool ret;
49
50 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }");
51 ret = !strcmp(get_error_class(resp), "CommandNotFound");
52 qobject_unref(resp);
53 return ret;
54}
55
6a5c88f5 56static void test_malformed(QTestState *qts)
f66e7ac8
MA
57{
58 QDict *resp;
59
aed877c5
MA
60 /* syntax error */
61 qtest_qmp_send_raw(qts, "{]\n");
62 resp = qtest_qmp_receive(qts);
63 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
64 qobject_unref(resp);
65 g_assert(recovered(qts));
66
67 /* lexical error: impossible byte outside string */
68 qtest_qmp_send_raw(qts, "{\xFF");
69 resp = qtest_qmp_receive(qts);
70 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
71 qobject_unref(resp);
72 g_assert(recovered(qts));
73
6bc93a34
MA
74 /* lexical error: funny control character outside string */
75 qtest_qmp_send_raw(qts, "{\x01");
76 resp = qtest_qmp_receive(qts);
77 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
78 qobject_unref(resp);
79 g_assert(recovered(qts));
80
aed877c5
MA
81 /* lexical error: impossible byte in string */
82 qtest_qmp_send_raw(qts, "{'bad \xFF");
83 resp = qtest_qmp_receive(qts);
84 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
85 qobject_unref(resp);
86 g_assert(recovered(qts));
87
6bc93a34 88 /* lexical error: control character in string */
340db1ed 89 qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n");
6bc93a34 90 resp = qtest_qmp_receive(qts);
340db1ed 91 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
6bc93a34
MA
92 qobject_unref(resp);
93 g_assert(recovered(qts));
94
aed877c5
MA
95 /* lexical error: interpolation */
96 qtest_qmp_send_raw(qts, "%%p\n");
2cbd15aa
MA
97 /* two errors, one for "%", one for "p" */
98 resp = qtest_qmp_receive(qts);
99 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
100 qobject_unref(resp);
aed877c5
MA
101 resp = qtest_qmp_receive(qts);
102 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
103 qobject_unref(resp);
104 g_assert(recovered(qts));
105
f66e7ac8 106 /* Not even a dictionary */
6a5c88f5 107 resp = qtest_qmp(qts, "null");
f66e7ac8 108 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
cb3e7f08 109 qobject_unref(resp);
f66e7ac8
MA
110
111 /* No "execute" key */
6a5c88f5 112 resp = qtest_qmp(qts, "{}");
f66e7ac8 113 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
cb3e7f08 114 qobject_unref(resp);
f66e7ac8
MA
115
116 /* "execute" isn't a string */
6a5c88f5 117 resp = qtest_qmp(qts, "{ 'execute': true }");
f66e7ac8 118 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
cb3e7f08 119 qobject_unref(resp);
f66e7ac8
MA
120
121 /* "arguments" isn't a dictionary */
6a5c88f5 122 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
f66e7ac8 123 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
cb3e7f08 124 qobject_unref(resp);
f66e7ac8
MA
125
126 /* extra key */
6a5c88f5 127 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
f66e7ac8 128 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
cb3e7f08 129 qobject_unref(resp);
f66e7ac8
MA
130}
131
132static void test_qmp_protocol(void)
133{
134 QDict *resp, *q, *ret;
135 QList *capabilities;
6a5c88f5 136 QTestState *qts;
f66e7ac8 137
ddee57e0 138 qts = qtest_init_without_qmp_handshake(false, common_args);
f66e7ac8
MA
139
140 /* Test greeting */
6a5c88f5 141 resp = qtest_qmp_receive(qts);
f66e7ac8
MA
142 q = qdict_get_qdict(resp, "QMP");
143 g_assert(q);
144 test_version(qdict_get(q, "version"));
145 capabilities = qdict_get_qlist(q, "capabilities");
a4f90923 146 g_assert(capabilities && qlist_empty(capabilities));
cb3e7f08 147 qobject_unref(resp);
f66e7ac8
MA
148
149 /* Test valid command before handshake */
6a5c88f5 150 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
f66e7ac8 151 g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
cb3e7f08 152 qobject_unref(resp);
f66e7ac8
MA
153
154 /* Test malformed commands before handshake */
6a5c88f5 155 test_malformed(qts);
f66e7ac8
MA
156
157 /* Test handshake */
6a5c88f5 158 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
f66e7ac8
MA
159 ret = qdict_get_qdict(resp, "return");
160 g_assert(ret && !qdict_size(ret));
cb3e7f08 161 qobject_unref(resp);
f66e7ac8
MA
162
163 /* Test repeated handshake */
6a5c88f5 164 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
f66e7ac8 165 g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
cb3e7f08 166 qobject_unref(resp);
f66e7ac8
MA
167
168 /* Test valid command */
6a5c88f5 169 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
f66e7ac8 170 test_version(qdict_get(resp, "return"));
cb3e7f08 171 qobject_unref(resp);
f66e7ac8
MA
172
173 /* Test malformed commands */
6a5c88f5 174 test_malformed(qts);
f66e7ac8
MA
175
176 /* Test 'id' */
6a5c88f5 177 resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
f66e7ac8
MA
178 ret = qdict_get_qdict(resp, "return");
179 g_assert(ret);
180 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
cb3e7f08 181 qobject_unref(resp);
f66e7ac8
MA
182
183 /* Test command failure with 'id' */
6a5c88f5 184 resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
f66e7ac8
MA
185 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
186 g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
cb3e7f08 187 qobject_unref(resp);
f66e7ac8 188
6a5c88f5 189 qtest_quit(qts);
f66e7ac8
MA
190}
191
97ca0712
MA
192/* Out-of-band tests */
193
194char tmpdir[] = "/tmp/qmp-test-XXXXXX";
195char *fifo_name;
196
197static void setup_blocking_cmd(void)
198{
199 if (!mkdtemp(tmpdir)) {
200 g_error("mkdtemp: %s", strerror(errno));
201 }
202 fifo_name = g_strdup_printf("%s/fifo", tmpdir);
203 if (mkfifo(fifo_name, 0666)) {
204 g_error("mkfifo: %s", strerror(errno));
205 }
206}
207
208static void cleanup_blocking_cmd(void)
209{
210 unlink(fifo_name);
211 rmdir(tmpdir);
212}
213
214static void send_cmd_that_blocks(QTestState *s, const char *id)
215{
4277f1eb
MA
216 qtest_qmp_send(s, "{ 'execute': 'blockdev-add', 'id': %s,"
217 " 'arguments': {"
218 " 'driver': 'blkdebug', 'node-name': %s,"
219 " 'config': %s,"
220 " 'image': { 'driver': 'null-co' } } }",
221 id, id, fifo_name);
97ca0712
MA
222}
223
224static void unblock_blocked_cmd(void)
225{
226 int fd = open(fifo_name, O_WRONLY);
227 g_assert(fd >= 0);
228 close(fd);
229}
230
231static void send_oob_cmd_that_fails(QTestState *s, const char *id)
232{
4277f1eb 233 qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
97ca0712
MA
234}
235
236static void recv_cmd_id(QTestState *s, const char *id)
237{
238 QDict *resp = qtest_qmp_receive(s);
239
240 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
241 qobject_unref(resp);
242}
243
fa198ad9
PX
244static void test_qmp_oob(void)
245{
246 QTestState *qts;
247 QDict *resp, *q;
fa198ad9
PX
248 const QListEntry *entry;
249 QList *capabilities;
250 QString *qstr;
fa198ad9
PX
251
252 qts = qtest_init_without_qmp_handshake(true, common_args);
253
254 /* Check the greeting message. */
255 resp = qtest_qmp_receive(qts);
256 q = qdict_get_qdict(resp, "QMP");
257 g_assert(q);
258 capabilities = qdict_get_qlist(q, "capabilities");
259 g_assert(capabilities && !qlist_empty(capabilities));
260 entry = qlist_first(capabilities);
261 g_assert(entry);
262 qstr = qobject_to(QString, entry->value);
263 g_assert(qstr);
264 g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
cb3e7f08 265 qobject_unref(resp);
fa198ad9
PX
266
267 /* Try a fake capability, it should fail. */
268 resp = qtest_qmp(qts,
269 "{ 'execute': 'qmp_capabilities', "
270 " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
271 g_assert(qdict_haskey(resp, "error"));
cb3e7f08 272 qobject_unref(resp);
fa198ad9
PX
273
274 /* Now, enable OOB in current QMP session, it should succeed. */
275 resp = qtest_qmp(qts,
276 "{ 'execute': 'qmp_capabilities', "
277 " 'arguments': { 'enable': [ 'oob' ] } }");
278 g_assert(qdict_haskey(resp, "return"));
cb3e7f08 279 qobject_unref(resp);
fa198ad9
PX
280
281 /*
282 * Try any command that does not support OOB but with OOB flag. We
283 * should get failure.
284 */
00ecec15 285 resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
fa198ad9 286 g_assert(qdict_haskey(resp, "error"));
cb3e7f08 287 qobject_unref(resp);
fa198ad9 288
97ca0712
MA
289 /* OOB command overtakes slow in-band command */
290 setup_blocking_cmd();
291 send_cmd_that_blocks(qts, "ib-blocks-1");
4277f1eb 292 qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
97ca0712
MA
293 send_oob_cmd_that_fails(qts, "oob-1");
294 recv_cmd_id(qts, "oob-1");
295 unblock_blocked_cmd();
296 recv_cmd_id(qts, "ib-blocks-1");
2970b446 297 recv_cmd_id(qts, "ib-quick-1");
e8f4a221 298
69240fe6 299 /* Even malformed in-band command fails in-band */
e8f4a221 300 send_cmd_that_blocks(qts, "blocks-2");
4277f1eb 301 qtest_qmp_send(qts, "{ 'id': 'err-2' }");
e8f4a221
MA
302 unblock_blocked_cmd();
303 recv_cmd_id(qts, "blocks-2");
69240fe6 304 recv_cmd_id(qts, "err-2");
97ca0712 305 cleanup_blocking_cmd();
fa198ad9
PX
306
307 qtest_quit(qts);
308}
309
97ca0712
MA
310/* Preconfig tests */
311
fb1e58f7
IM
312static void test_qmp_preconfig(void)
313{
314 QDict *rsp, *ret;
88b988c8 315 QTestState *qs = qtest_initf("%s --preconfig", common_args);
fb1e58f7
IM
316
317 /* preconfig state */
318 /* enabled commands, no error expected */
319 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
320
321 /* forbidden commands, expected error */
322 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
323
324 /* check that query-status returns preconfig state */
325 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
326 ret = qdict_get_qdict(rsp, "return");
327 g_assert(ret);
328 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
329 qobject_unref(rsp);
330
331 /* exit preconfig state */
361ac948 332 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
fb1e58f7
IM
333 qtest_qmp_eventwait(qs, "RESUME");
334
335 /* check that query-status returns running state */
336 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
337 ret = qdict_get_qdict(rsp, "return");
338 g_assert(ret);
339 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
340 qobject_unref(rsp);
341
361ac948
MA
342 /* check that x-exit-preconfig returns error after exiting preconfig */
343 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
fb1e58f7
IM
344
345 /* enabled commands, no error expected */
346 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
347
348 qtest_quit(qs);
349}
350
f66e7ac8
MA
351int main(int argc, char *argv[])
352{
353 g_test_init(&argc, &argv, NULL);
354
355 qtest_add_func("qmp/protocol", test_qmp_protocol);
fa198ad9 356 qtest_add_func("qmp/oob", test_qmp_oob);
fb1e58f7 357 qtest_add_func("qmp/preconfig", test_qmp_preconfig);
e4a426e7 358
d93bb9d5 359 return g_test_run();
f66e7ac8 360}
This page took 0.202941 seconds and 4 git commands to generate.