blob: 48a4fa791a5bb9a1b494dc2d792afc9aaff34ad2 [file] [log] [blame]
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +01001/*
2 * QMP protocol test cases
3 *
Markus Armbrusteraed877c2018-08-23 18:39:33 +02004 * Copyright (c) 2017-2018 Red Hat Inc.
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +01005 *
6 * Authors:
Markus Armbrusterd93bb9d2018-08-23 18:39:32 +02007 * Markus Armbruster <armbru@redhat.com>
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +01008 *
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"
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010015#include "qapi/error.h"
Markus Armbruster112ed242018-02-26 17:13:27 -060016#include "qapi/qapi-visit-misc.h"
Markus Armbruster452fcdb2018-02-01 12:18:39 +010017#include "qapi/qmp/qdict.h"
Markus Armbruster47e6b292018-02-01 12:18:38 +010018#include "qapi/qmp/qlist.h"
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010019#include "qapi/qobject-input-visitor.h"
Peter Xu02130312018-03-09 16:59:53 +080020#include "qapi/qmp/qstring.h"
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010021
22const char common_args[] = "-nodefaults -machine none";
23
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010024static void test_version(QObject *version)
25{
26 Visitor *v;
27 VersionInfo *vinfo;
28
29 g_assert(version);
Markus Armbruster048abb72017-03-03 13:32:39 +010030 v = qobject_input_visitor_new(version);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010031 visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
32 qapi_free_VersionInfo(vinfo);
33 visit_free(v);
34}
35
Marc-André Lureauebb4d822018-08-30 17:58:07 +020036static void assert_recovered(QTestState *qts)
Markus Armbrusteraed877c2018-08-23 18:39:33 +020037{
38 QDict *resp;
Markus Armbrusteraed877c2018-08-23 18:39:33 +020039
40 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +020041 qmp_assert_error_class(resp, "CommandNotFound");
Markus Armbrusteraed877c2018-08-23 18:39:33 +020042}
43
Eric Blake6a5c88f2017-09-11 12:20:06 -050044static void test_malformed(QTestState *qts)
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010045{
46 QDict *resp;
47
Markus Armbrusteraed877c2018-08-23 18:39:33 +020048 /* syntax error */
49 qtest_qmp_send_raw(qts, "{]\n");
50 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020051 qmp_assert_error_class(resp, "GenericError");
52 assert_recovered(qts);
Markus Armbrusteraed877c2018-08-23 18:39:33 +020053
54 /* lexical error: impossible byte outside string */
55 qtest_qmp_send_raw(qts, "{\xFF");
56 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020057 qmp_assert_error_class(resp, "GenericError");
58 assert_recovered(qts);
Markus Armbrusteraed877c2018-08-23 18:39:33 +020059
Markus Armbruster6bc93a32018-08-23 18:39:42 +020060 /* lexical error: funny control character outside string */
61 qtest_qmp_send_raw(qts, "{\x01");
62 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020063 qmp_assert_error_class(resp, "GenericError");
64 assert_recovered(qts);
Markus Armbruster6bc93a32018-08-23 18:39:42 +020065
Markus Armbrusteraed877c2018-08-23 18:39:33 +020066 /* lexical error: impossible byte in string */
67 qtest_qmp_send_raw(qts, "{'bad \xFF");
68 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020069 qmp_assert_error_class(resp, "GenericError");
70 assert_recovered(qts);
Markus Armbrusteraed877c2018-08-23 18:39:33 +020071
Markus Armbruster6bc93a32018-08-23 18:39:42 +020072 /* lexical error: control character in string */
Markus Armbruster340db1e2018-08-23 18:39:45 +020073 qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n");
Markus Armbruster6bc93a32018-08-23 18:39:42 +020074 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020075 qmp_assert_error_class(resp, "GenericError");
76 assert_recovered(qts);
Markus Armbruster6bc93a32018-08-23 18:39:42 +020077
Markus Armbrusteraed877c2018-08-23 18:39:33 +020078 /* lexical error: interpolation */
Markus Armbruster0f07a5d2018-08-31 09:58:39 +020079 qtest_qmp_send_raw(qts, "%%p");
Markus Armbrusteraed877c2018-08-23 18:39:33 +020080 resp = qtest_qmp_receive(qts);
Marc-André Lureauebb4d822018-08-30 17:58:07 +020081 qmp_assert_error_class(resp, "GenericError");
82 assert_recovered(qts);
Markus Armbrusteraed877c2018-08-23 18:39:33 +020083
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010084 /* Not even a dictionary */
Eric Blake6a5c88f2017-09-11 12:20:06 -050085 resp = qtest_qmp(qts, "null");
Marc-André Lureauebb4d822018-08-30 17:58:07 +020086 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010087
88 /* No "execute" key */
Eric Blake6a5c88f2017-09-11 12:20:06 -050089 resp = qtest_qmp(qts, "{}");
Marc-André Lureauebb4d822018-08-30 17:58:07 +020090 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010091
92 /* "execute" isn't a string */
Eric Blake6a5c88f2017-09-11 12:20:06 -050093 resp = qtest_qmp(qts, "{ 'execute': true }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +020094 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010095
96 /* "arguments" isn't a dictionary */
Eric Blake6a5c88f2017-09-11 12:20:06 -050097 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +020098 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +010099
100 /* extra key */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500101 resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +0200102 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100103}
104
105static void test_qmp_protocol(void)
106{
107 QDict *resp, *q, *ret;
108 QList *capabilities;
Eric Blake6a5c88f2017-09-11 12:20:06 -0500109 QTestState *qts;
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100110
Peter Xu192f26a2018-10-09 14:27:16 +0800111 qts = qtest_init_without_qmp_handshake(common_args);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100112
113 /* Test greeting */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500114 resp = qtest_qmp_receive(qts);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100115 q = qdict_get_qdict(resp, "QMP");
116 g_assert(q);
117 test_version(qdict_get(q, "version"));
118 capabilities = qdict_get_qlist(q, "capabilities");
Peter Xu82582922018-10-09 14:27:15 +0800119 g_assert(capabilities);
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200120 qobject_unref(resp);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100121
122 /* Test valid command before handshake */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500123 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +0200124 qmp_assert_error_class(resp, "CommandNotFound");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100125
126 /* Test malformed commands before handshake */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500127 test_malformed(qts);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100128
129 /* Test handshake */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500130 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100131 ret = qdict_get_qdict(resp, "return");
132 g_assert(ret && !qdict_size(ret));
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200133 qobject_unref(resp);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100134
135 /* Test repeated handshake */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500136 resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
Marc-André Lureauebb4d822018-08-30 17:58:07 +0200137 qmp_assert_error_class(resp, "CommandNotFound");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100138
139 /* Test valid command */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500140 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100141 test_version(qdict_get(resp, "return"));
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200142 qobject_unref(resp);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100143
144 /* Test malformed commands */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500145 test_malformed(qts);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100146
147 /* Test 'id' */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500148 resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100149 ret = qdict_get_qdict(resp, "return");
150 g_assert(ret);
151 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200152 qobject_unref(resp);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100153
154 /* Test command failure with 'id' */
Eric Blake6a5c88f2017-09-11 12:20:06 -0500155 resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100156 g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
Marc-André Lureauebb4d822018-08-30 17:58:07 +0200157 qmp_assert_error_class(resp, "GenericError");
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100158
Eric Blake6a5c88f2017-09-11 12:20:06 -0500159 qtest_quit(qts);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100160}
161
Markus Armbruster97ca0712018-07-03 10:53:31 +0200162/* Out-of-band tests */
163
164char tmpdir[] = "/tmp/qmp-test-XXXXXX";
165char *fifo_name;
166
167static void setup_blocking_cmd(void)
168{
169 if (!mkdtemp(tmpdir)) {
170 g_error("mkdtemp: %s", strerror(errno));
171 }
172 fifo_name = g_strdup_printf("%s/fifo", tmpdir);
173 if (mkfifo(fifo_name, 0666)) {
174 g_error("mkfifo: %s", strerror(errno));
175 }
176}
177
178static void cleanup_blocking_cmd(void)
179{
180 unlink(fifo_name);
181 rmdir(tmpdir);
182}
183
184static void send_cmd_that_blocks(QTestState *s, const char *id)
185{
Markus Armbruster4277f1e2018-08-06 08:53:22 +0200186 qtest_qmp_send(s, "{ 'execute': 'blockdev-add', 'id': %s,"
187 " 'arguments': {"
188 " 'driver': 'blkdebug', 'node-name': %s,"
189 " 'config': %s,"
190 " 'image': { 'driver': 'null-co' } } }",
191 id, id, fifo_name);
Markus Armbruster97ca0712018-07-03 10:53:31 +0200192}
193
194static void unblock_blocked_cmd(void)
195{
196 int fd = open(fifo_name, O_WRONLY);
197 g_assert(fd >= 0);
198 close(fd);
199}
200
201static void send_oob_cmd_that_fails(QTestState *s, const char *id)
202{
Markus Armbruster4277f1e2018-08-06 08:53:22 +0200203 qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
Markus Armbruster97ca0712018-07-03 10:53:31 +0200204}
205
206static void recv_cmd_id(QTestState *s, const char *id)
207{
208 QDict *resp = qtest_qmp_receive(s);
209
210 g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
211 qobject_unref(resp);
212}
213
Peter Xufa198ad2018-03-26 14:39:01 +0800214static void test_qmp_oob(void)
215{
216 QTestState *qts;
217 QDict *resp, *q;
Peter Xufa198ad2018-03-26 14:39:01 +0800218 const QListEntry *entry;
219 QList *capabilities;
220 QString *qstr;
Peter Xufa198ad2018-03-26 14:39:01 +0800221
Peter Xu192f26a2018-10-09 14:27:16 +0800222 qts = qtest_init_without_qmp_handshake(common_args);
Peter Xufa198ad2018-03-26 14:39:01 +0800223
224 /* Check the greeting message. */
225 resp = qtest_qmp_receive(qts);
226 q = qdict_get_qdict(resp, "QMP");
227 g_assert(q);
228 capabilities = qdict_get_qlist(q, "capabilities");
229 g_assert(capabilities && !qlist_empty(capabilities));
230 entry = qlist_first(capabilities);
231 g_assert(entry);
232 qstr = qobject_to(QString, entry->value);
233 g_assert(qstr);
234 g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200235 qobject_unref(resp);
Peter Xufa198ad2018-03-26 14:39:01 +0800236
237 /* Try a fake capability, it should fail. */
238 resp = qtest_qmp(qts,
239 "{ 'execute': 'qmp_capabilities', "
240 " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
241 g_assert(qdict_haskey(resp, "error"));
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200242 qobject_unref(resp);
Peter Xufa198ad2018-03-26 14:39:01 +0800243
244 /* Now, enable OOB in current QMP session, it should succeed. */
245 resp = qtest_qmp(qts,
246 "{ 'execute': 'qmp_capabilities', "
247 " 'arguments': { 'enable': [ 'oob' ] } }");
248 g_assert(qdict_haskey(resp, "return"));
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200249 qobject_unref(resp);
Peter Xufa198ad2018-03-26 14:39:01 +0800250
251 /*
252 * Try any command that does not support OOB but with OOB flag. We
253 * should get failure.
254 */
Markus Armbruster00ecec12018-07-03 10:53:38 +0200255 resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
Peter Xufa198ad2018-03-26 14:39:01 +0800256 g_assert(qdict_haskey(resp, "error"));
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200257 qobject_unref(resp);
Peter Xufa198ad2018-03-26 14:39:01 +0800258
Markus Armbruster97ca0712018-07-03 10:53:31 +0200259 /* OOB command overtakes slow in-band command */
260 setup_blocking_cmd();
261 send_cmd_that_blocks(qts, "ib-blocks-1");
Markus Armbruster4277f1e2018-08-06 08:53:22 +0200262 qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
Markus Armbruster97ca0712018-07-03 10:53:31 +0200263 send_oob_cmd_that_fails(qts, "oob-1");
264 recv_cmd_id(qts, "oob-1");
265 unblock_blocked_cmd();
266 recv_cmd_id(qts, "ib-blocks-1");
Markus Armbruster2970b442018-07-03 10:53:32 +0200267 recv_cmd_id(qts, "ib-quick-1");
Markus Armbrustere8f4a222018-07-03 10:53:42 +0200268
Markus Armbruster69240fe2018-07-03 10:53:43 +0200269 /* Even malformed in-band command fails in-band */
Markus Armbrustere8f4a222018-07-03 10:53:42 +0200270 send_cmd_that_blocks(qts, "blocks-2");
Markus Armbruster4277f1e2018-08-06 08:53:22 +0200271 qtest_qmp_send(qts, "{ 'id': 'err-2' }");
Markus Armbrustere8f4a222018-07-03 10:53:42 +0200272 unblock_blocked_cmd();
273 recv_cmd_id(qts, "blocks-2");
Markus Armbruster69240fe2018-07-03 10:53:43 +0200274 recv_cmd_id(qts, "err-2");
Markus Armbruster97ca0712018-07-03 10:53:31 +0200275 cleanup_blocking_cmd();
Peter Xufa198ad2018-03-26 14:39:01 +0800276
277 qtest_quit(qts);
278}
279
Markus Armbruster97ca0712018-07-03 10:53:31 +0200280/* Preconfig tests */
281
Igor Mammedovfb1e58f2018-05-17 13:28:44 +0200282static void test_qmp_preconfig(void)
283{
284 QDict *rsp, *ret;
Markus Armbruster88b988c2018-08-06 08:53:43 +0200285 QTestState *qs = qtest_initf("%s --preconfig", common_args);
Igor Mammedovfb1e58f2018-05-17 13:28:44 +0200286
287 /* preconfig state */
288 /* enabled commands, no error expected */
289 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
290
291 /* forbidden commands, expected error */
292 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
293
294 /* check that query-status returns preconfig state */
295 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
296 ret = qdict_get_qdict(rsp, "return");
297 g_assert(ret);
298 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
299 qobject_unref(rsp);
300
301 /* exit preconfig state */
Markus Armbruster361ac942018-07-05 11:14:02 +0200302 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
Igor Mammedovfb1e58f2018-05-17 13:28:44 +0200303 qtest_qmp_eventwait(qs, "RESUME");
304
305 /* check that query-status returns running state */
306 rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
307 ret = qdict_get_qdict(rsp, "return");
308 g_assert(ret);
309 g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
310 qobject_unref(rsp);
311
Markus Armbruster361ac942018-07-05 11:14:02 +0200312 /* check that x-exit-preconfig returns error after exiting preconfig */
313 g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
Igor Mammedovfb1e58f2018-05-17 13:28:44 +0200314
315 /* enabled commands, no error expected */
316 g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
317
318 qtest_quit(qs);
319}
320
Marc-André Lureau61793a62018-10-29 18:57:09 +0400321static void test_qmp_missing_any_arg(void)
322{
323 QTestState *qts;
324 QDict *resp;
325
326 qts = qtest_init(common_args);
327 resp = qtest_qmp(qts, "{'execute': 'qom-set', 'arguments':"
328 " { 'path': '/machine', 'property': 'rtc-time' } }");
329 g_assert_nonnull(resp);
330 qmp_assert_error_class(resp, "GenericError");
331 qtest_quit(qts);
332}
333
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100334int main(int argc, char *argv[])
335{
336 g_test_init(&argc, &argv, NULL);
337
338 qtest_add_func("qmp/protocol", test_qmp_protocol);
Peter Xufa198ad2018-03-26 14:39:01 +0800339 qtest_add_func("qmp/oob", test_qmp_oob);
Igor Mammedovfb1e58f2018-05-17 13:28:44 +0200340 qtest_add_func("qmp/preconfig", test_qmp_preconfig);
Marc-André Lureau61793a62018-10-29 18:57:09 +0400341 qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg);
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100342
Markus Armbrusterd93bb9d2018-08-23 18:39:32 +0200343 return g_test_run();
Markus Armbrusterf66e7ac2017-03-03 13:32:23 +0100344}