]> git.proxmox.com Git - mirror_qemu.git/blob - tests/qmp-test.c
qmp-test: Cover syntax and lexical errors
[mirror_qemu.git] / tests / qmp-test.c
1 /*
2 * QMP protocol test cases
3 *
4 * Copyright (c) 2017-2018 Red Hat Inc.
5 *
6 * Authors:
7 * Markus Armbruster <armbru@redhat.com>
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"
15 #include "qapi/error.h"
16 #include "qapi/qapi-visit-misc.h"
17 #include "qapi/qmp/qdict.h"
18 #include "qapi/qmp/qlist.h"
19 #include "qapi/qobject-input-visitor.h"
20 #include "qapi/qmp/qstring.h"
21
22 const char common_args[] = "-nodefaults -machine none";
23
24 static 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
33 static void test_version(QObject *version)
34 {
35 Visitor *v;
36 VersionInfo *vinfo;
37
38 g_assert(version);
39 v = qobject_input_visitor_new(version);
40 visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
41 qapi_free_VersionInfo(vinfo);
42 visit_free(v);
43 }
44
45 static 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
56 static void test_malformed(QTestState *qts)
57 {
58 QDict *resp;
59
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
74 /* lexical error: impossible byte in string */
75 qtest_qmp_send_raw(qts, "{'bad \xFF");
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
81 /* lexical error: interpolation */
82 qtest_qmp_send_raw(qts, "%%p\n");
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
88 /* Not even a dictionary */
89 resp = qtest_qmp(qts, "null");
90 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
91 qobject_unref(resp);
92
93 /* No "execute" key */
94 resp = qtest_qmp(qts, "{}");
95 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
96 qobject_unref(resp);
97
98 /* "execute" isn't a string */
99 resp = qtest_qmp(qts, "{ 'execute': true }");
100 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
101 qobject_unref(resp);
102
103 /* "arguments" isn't a dictionary */
104 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
105 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
106 qobject_unref(resp);
107
108 /* extra key */
109 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
110 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
111 qobject_unref(resp);
112 }
113
114 static void test_qmp_protocol(void)
115 {
116 QDict *resp, *q, *ret;
117 QList *capabilities;
118 QTestState *qts;
119
120 qts = qtest_init_without_qmp_handshake(false, common_args);
121
122 /* Test greeting */
123 resp = qtest_qmp_receive(qts);
124 q = qdict_get_qdict(resp, "QMP");
125 g_assert(q);
126 test_version(qdict_get(q, "version"));
127 capabilities = qdict_get_qlist(q, "capabilities");
128 g_assert(capabilities && qlist_empty(capabilities));
129 qobject_unref(resp);
130
131 /* Test valid command before handshake */
132 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
133 g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
134 qobject_unref(resp);
135
136 /* Test malformed commands before handshake */
137 test_malformed(qts);
138
139 /* Test handshake */
140 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
141 ret = qdict_get_qdict(resp, "return");
142 g_assert(ret && !qdict_size(ret));
143 qobject_unref(resp);
144
145 /* Test repeated handshake */
146 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
147 g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound");
148 qobject_unref(resp);
149
150 /* Test valid command */
151 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
152 test_version(qdict_get(resp, "return"));
153 qobject_unref(resp);
154
155 /* Test malformed commands */
156 test_malformed(qts);
157
158 /* Test 'id' */
159 resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
160 ret = qdict_get_qdict(resp, "return");
161 g_assert(ret);
162 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
163 qobject_unref(resp);
164
165 /* Test command failure with 'id' */
166 resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
167 g_assert_cmpstr(get_error_class(resp), ==, "GenericError");
168 g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
169 qobject_unref(resp);
170
171 qtest_quit(qts);
172 }
173
174 /* Out-of-band tests */
175
176 char tmpdir[] = "/tmp/qmp-test-XXXXXX";
177 char *fifo_name;
178
179 static void setup_blocking_cmd(void)
180 {
181 if (!mkdtemp(tmpdir)) {
182 g_error("mkdtemp: %s", strerror(errno));
183 }
184 fifo_name = g_strdup_printf("%s/fifo", tmpdir);
185 if (mkfifo(fifo_name, 0666)) {
186 g_error("mkfifo: %s", strerror(errno));
187 }
188 }
189
190 static void cleanup_blocking_cmd(void)
191 {
192 unlink(fifo_name);
193 rmdir(tmpdir);
194 }
195
196 static void send_cmd_that_blocks(QTestState *s, const char *id)
197 {
198 qtest_qmp_send(s, "{ 'execute': 'blockdev-add', 'id': %s,"
199 " 'arguments': {"
200 " 'driver': 'blkdebug', 'node-name': %s,"
201 " 'config': %s,"
202 " 'image': { 'driver': 'null-co' } } }",
203 id, id, fifo_name);
204 }
205
206 static void unblock_blocked_cmd(void)
207 {
208 int fd = open(fifo_name, O_WRONLY);
209 g_assert(fd >= 0);
210 close(fd);
211 }
212
213 static void send_oob_cmd_that_fails(QTestState *s, const char *id)
214 {
215 qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
216 }
217
218 static void recv_cmd_id(QTestState *s, const char *id)
219 {
220 QDict *resp = qtest_qmp_receive(s);
221
222 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
223 qobject_unref(resp);
224 }
225
226 static void test_qmp_oob(void)
227 {
228 QTestState *qts;
229 QDict *resp, *q;
230 const QListEntry *entry;
231 QList *capabilities;
232 QString *qstr;
233
234 qts = qtest_init_without_qmp_handshake(true, common_args);
235
236 /* Check the greeting message. */
237 resp = qtest_qmp_receive(qts);
238 q = qdict_get_qdict(resp, "QMP");
239 g_assert(q);
240 capabilities = qdict_get_qlist(q, "capabilities");
241 g_assert(capabilities && !qlist_empty(capabilities));
242 entry = qlist_first(capabilities);
243 g_assert(entry);
244 qstr = qobject_to(QString, entry->value);
245 g_assert(qstr);
246 g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
247 qobject_unref(resp);
248
249 /* Try a fake capability, it should fail. */
250 resp = qtest_qmp(qts,
251 "{ 'execute': 'qmp_capabilities', "
252 " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
253 g_assert(qdict_haskey(resp, "error"));
254 qobject_unref(resp);
255
256 /* Now, enable OOB in current QMP session, it should succeed. */
257 resp = qtest_qmp(qts,
258 "{ 'execute': 'qmp_capabilities', "
259 " 'arguments': { 'enable': [ 'oob' ] } }");
260 g_assert(qdict_haskey(resp, "return"));
261 qobject_unref(resp);
262
263 /*
264 * Try any command that does not support OOB but with OOB flag. We
265 * should get failure.
266 */
267 resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
268 g_assert(qdict_haskey(resp, "error"));
269 qobject_unref(resp);
270
271 /* OOB command overtakes slow in-band command */
272 setup_blocking_cmd();
273 send_cmd_that_blocks(qts, "ib-blocks-1");
274 qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
275 send_oob_cmd_that_fails(qts, "oob-1");
276 recv_cmd_id(qts, "oob-1");
277 unblock_blocked_cmd();
278 recv_cmd_id(qts, "ib-blocks-1");
279 recv_cmd_id(qts, "ib-quick-1");
280
281 /* Even malformed in-band command fails in-band */
282 send_cmd_that_blocks(qts, "blocks-2");
283 qtest_qmp_send(qts, "{ 'id': 'err-2' }");
284 unblock_blocked_cmd();
285 recv_cmd_id(qts, "blocks-2");
286 recv_cmd_id(qts, "err-2");
287 cleanup_blocking_cmd();
288
289 qtest_quit(qts);
290 }
291
292 /* Preconfig tests */
293
294 static void test_qmp_preconfig(void)
295 {
296 QDict *rsp, *ret;
297 QTestState *qs = qtest_initf("%s --preconfig", common_args);
298
299 /* preconfig state */
300 /* enabled commands, no error expected */
301 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
302
303 /* forbidden commands, expected error */
304 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
305
306 /* check that query-status returns preconfig state */
307 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
308 ret = qdict_get_qdict(rsp, "return");
309 g_assert(ret);
310 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
311 qobject_unref(rsp);
312
313 /* exit preconfig state */
314 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
315 qtest_qmp_eventwait(qs, "RESUME");
316
317 /* check that query-status returns running state */
318 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
319 ret = qdict_get_qdict(rsp, "return");
320 g_assert(ret);
321 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
322 qobject_unref(rsp);
323
324 /* check that x-exit-preconfig returns error after exiting preconfig */
325 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
326
327 /* enabled commands, no error expected */
328 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
329
330 qtest_quit(qs);
331 }
332
333 int main(int argc, char *argv[])
334 {
335 g_test_init(&argc, &argv, NULL);
336
337 qtest_add_func("qmp/protocol", test_qmp_protocol);
338 qtest_add_func("qmp/oob", test_qmp_oob);
339 qtest_add_func("qmp/preconfig", test_qmp_preconfig);
340
341 return g_test_run();
342 }