Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 1 | /* |
| 2 | * QMP protocol test cases |
| 3 | * |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 4 | * Copyright (c) 2017-2018 Red Hat Inc. |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 5 | * |
| 6 | * Authors: |
Markus Armbruster | d93bb9d | 2018-08-23 18:39:32 +0200 | [diff] [blame] | 7 | * Markus Armbruster <armbru@redhat.com> |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 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" |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 15 | #include "qapi/error.h" |
Markus Armbruster | 112ed24 | 2018-02-26 17:13:27 -0600 | [diff] [blame] | 16 | #include "qapi/qapi-visit-misc.h" |
Markus Armbruster | 452fcdb | 2018-02-01 12:18:39 +0100 | [diff] [blame] | 17 | #include "qapi/qmp/qdict.h" |
Markus Armbruster | 47e6b29 | 2018-02-01 12:18:38 +0100 | [diff] [blame] | 18 | #include "qapi/qmp/qlist.h" |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 19 | #include "qapi/qobject-input-visitor.h" |
Peter Xu | 0213031 | 2018-03-09 16:59:53 +0800 | [diff] [blame] | 20 | #include "qapi/qmp/qstring.h" |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 21 | |
| 22 | const char common_args[] = "-nodefaults -machine none"; |
| 23 | |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 24 | static void test_version(QObject *version) |
| 25 | { |
| 26 | Visitor *v; |
| 27 | VersionInfo *vinfo; |
| 28 | |
| 29 | g_assert(version); |
Markus Armbruster | 048abb7 | 2017-03-03 13:32:39 +0100 | [diff] [blame] | 30 | v = qobject_input_visitor_new(version); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 31 | visit_type_VersionInfo(v, "version", &vinfo, &error_abort); |
| 32 | qapi_free_VersionInfo(vinfo); |
| 33 | visit_free(v); |
| 34 | } |
| 35 | |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 36 | static void assert_recovered(QTestState *qts) |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 37 | { |
| 38 | QDict *resp; |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 39 | |
| 40 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 41 | qmp_assert_error_class(resp, "CommandNotFound"); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 42 | } |
| 43 | |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 44 | static void test_malformed(QTestState *qts) |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 45 | { |
| 46 | QDict *resp; |
| 47 | |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 48 | /* syntax error */ |
| 49 | qtest_qmp_send_raw(qts, "{]\n"); |
| 50 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 51 | qmp_assert_error_class(resp, "GenericError"); |
| 52 | assert_recovered(qts); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 53 | |
| 54 | /* lexical error: impossible byte outside string */ |
| 55 | qtest_qmp_send_raw(qts, "{\xFF"); |
| 56 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 57 | qmp_assert_error_class(resp, "GenericError"); |
| 58 | assert_recovered(qts); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 59 | |
Markus Armbruster | 6bc93a3 | 2018-08-23 18:39:42 +0200 | [diff] [blame] | 60 | /* lexical error: funny control character outside string */ |
| 61 | qtest_qmp_send_raw(qts, "{\x01"); |
| 62 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 63 | qmp_assert_error_class(resp, "GenericError"); |
| 64 | assert_recovered(qts); |
Markus Armbruster | 6bc93a3 | 2018-08-23 18:39:42 +0200 | [diff] [blame] | 65 | |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 66 | /* lexical error: impossible byte in string */ |
| 67 | qtest_qmp_send_raw(qts, "{'bad \xFF"); |
| 68 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 69 | qmp_assert_error_class(resp, "GenericError"); |
| 70 | assert_recovered(qts); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 71 | |
Markus Armbruster | 6bc93a3 | 2018-08-23 18:39:42 +0200 | [diff] [blame] | 72 | /* lexical error: control character in string */ |
Markus Armbruster | 340db1e | 2018-08-23 18:39:45 +0200 | [diff] [blame] | 73 | qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n"); |
Markus Armbruster | 6bc93a3 | 2018-08-23 18:39:42 +0200 | [diff] [blame] | 74 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 75 | qmp_assert_error_class(resp, "GenericError"); |
| 76 | assert_recovered(qts); |
Markus Armbruster | 6bc93a3 | 2018-08-23 18:39:42 +0200 | [diff] [blame] | 77 | |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 78 | /* lexical error: interpolation */ |
Markus Armbruster | 0f07a5d | 2018-08-31 09:58:39 +0200 | [diff] [blame] | 79 | qtest_qmp_send_raw(qts, "%%p"); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 80 | resp = qtest_qmp_receive(qts); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 81 | qmp_assert_error_class(resp, "GenericError"); |
| 82 | assert_recovered(qts); |
Markus Armbruster | aed877c | 2018-08-23 18:39:33 +0200 | [diff] [blame] | 83 | |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 84 | /* Not even a dictionary */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 85 | resp = qtest_qmp(qts, "null"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 86 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 87 | |
| 88 | /* No "execute" key */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 89 | resp = qtest_qmp(qts, "{}"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 90 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 91 | |
| 92 | /* "execute" isn't a string */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 93 | resp = qtest_qmp(qts, "{ 'execute': true }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 94 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 95 | |
| 96 | /* "arguments" isn't a dictionary */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 97 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 98 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 99 | |
| 100 | /* extra key */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 101 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 102 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | static void test_qmp_protocol(void) |
| 106 | { |
| 107 | QDict *resp, *q, *ret; |
| 108 | QList *capabilities; |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 109 | QTestState *qts; |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 110 | |
Peter Xu | 192f26a | 2018-10-09 14:27:16 +0800 | [diff] [blame] | 111 | qts = qtest_init_without_qmp_handshake(common_args); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 112 | |
| 113 | /* Test greeting */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 114 | resp = qtest_qmp_receive(qts); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 115 | 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 Xu | 8258292 | 2018-10-09 14:27:15 +0800 | [diff] [blame] | 119 | g_assert(capabilities); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 120 | qobject_unref(resp); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 121 | |
| 122 | /* Test valid command before handshake */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 123 | resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 124 | qmp_assert_error_class(resp, "CommandNotFound"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 125 | |
| 126 | /* Test malformed commands before handshake */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 127 | test_malformed(qts); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 128 | |
| 129 | /* Test handshake */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 130 | resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 131 | ret = qdict_get_qdict(resp, "return"); |
| 132 | g_assert(ret && !qdict_size(ret)); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 133 | qobject_unref(resp); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 134 | |
| 135 | /* Test repeated handshake */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 136 | resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 137 | qmp_assert_error_class(resp, "CommandNotFound"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 138 | |
| 139 | /* Test valid command */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 140 | resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 141 | test_version(qdict_get(resp, "return")); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 142 | qobject_unref(resp); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 143 | |
| 144 | /* Test malformed commands */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 145 | test_malformed(qts); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 146 | |
| 147 | /* Test 'id' */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 148 | resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 149 | ret = qdict_get_qdict(resp, "return"); |
| 150 | g_assert(ret); |
| 151 | g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 152 | qobject_unref(resp); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 153 | |
| 154 | /* Test command failure with 'id' */ |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 155 | resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 156 | g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); |
Marc-André Lureau | ebb4d82 | 2018-08-30 17:58:07 +0200 | [diff] [blame] | 157 | qmp_assert_error_class(resp, "GenericError"); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 158 | |
Eric Blake | 6a5c88f | 2017-09-11 12:20:06 -0500 | [diff] [blame] | 159 | qtest_quit(qts); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 160 | } |
| 161 | |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 162 | /* Out-of-band tests */ |
| 163 | |
| 164 | char tmpdir[] = "/tmp/qmp-test-XXXXXX"; |
| 165 | char *fifo_name; |
| 166 | |
| 167 | static 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 | |
| 178 | static void cleanup_blocking_cmd(void) |
| 179 | { |
| 180 | unlink(fifo_name); |
| 181 | rmdir(tmpdir); |
| 182 | } |
| 183 | |
| 184 | static void send_cmd_that_blocks(QTestState *s, const char *id) |
| 185 | { |
Markus Armbruster | 4277f1e | 2018-08-06 08:53:22 +0200 | [diff] [blame] | 186 | 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 Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | static void unblock_blocked_cmd(void) |
| 195 | { |
| 196 | int fd = open(fifo_name, O_WRONLY); |
| 197 | g_assert(fd >= 0); |
| 198 | close(fd); |
| 199 | } |
| 200 | |
| 201 | static void send_oob_cmd_that_fails(QTestState *s, const char *id) |
| 202 | { |
Markus Armbruster | 4277f1e | 2018-08-06 08:53:22 +0200 | [diff] [blame] | 203 | qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id); |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | static 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 Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 214 | static void test_qmp_oob(void) |
| 215 | { |
| 216 | QTestState *qts; |
| 217 | QDict *resp, *q; |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 218 | const QListEntry *entry; |
| 219 | QList *capabilities; |
| 220 | QString *qstr; |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 221 | |
Peter Xu | 192f26a | 2018-10-09 14:27:16 +0800 | [diff] [blame] | 222 | qts = qtest_init_without_qmp_handshake(common_args); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 223 | |
| 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é Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 235 | qobject_unref(resp); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 236 | |
| 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é Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 242 | qobject_unref(resp); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 243 | |
| 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é Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 249 | qobject_unref(resp); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 250 | |
| 251 | /* |
| 252 | * Try any command that does not support OOB but with OOB flag. We |
| 253 | * should get failure. |
| 254 | */ |
Markus Armbruster | 00ecec1 | 2018-07-03 10:53:38 +0200 | [diff] [blame] | 255 | resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }"); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 256 | g_assert(qdict_haskey(resp, "error")); |
Marc-André Lureau | cb3e7f0 | 2018-04-19 17:01:43 +0200 | [diff] [blame] | 257 | qobject_unref(resp); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 258 | |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 259 | /* OOB command overtakes slow in-band command */ |
| 260 | setup_blocking_cmd(); |
| 261 | send_cmd_that_blocks(qts, "ib-blocks-1"); |
Markus Armbruster | 4277f1e | 2018-08-06 08:53:22 +0200 | [diff] [blame] | 262 | qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }"); |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 263 | 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 Armbruster | 2970b44 | 2018-07-03 10:53:32 +0200 | [diff] [blame] | 267 | recv_cmd_id(qts, "ib-quick-1"); |
Markus Armbruster | e8f4a22 | 2018-07-03 10:53:42 +0200 | [diff] [blame] | 268 | |
Markus Armbruster | 69240fe | 2018-07-03 10:53:43 +0200 | [diff] [blame] | 269 | /* Even malformed in-band command fails in-band */ |
Markus Armbruster | e8f4a22 | 2018-07-03 10:53:42 +0200 | [diff] [blame] | 270 | send_cmd_that_blocks(qts, "blocks-2"); |
Markus Armbruster | 4277f1e | 2018-08-06 08:53:22 +0200 | [diff] [blame] | 271 | qtest_qmp_send(qts, "{ 'id': 'err-2' }"); |
Markus Armbruster | e8f4a22 | 2018-07-03 10:53:42 +0200 | [diff] [blame] | 272 | unblock_blocked_cmd(); |
| 273 | recv_cmd_id(qts, "blocks-2"); |
Markus Armbruster | 69240fe | 2018-07-03 10:53:43 +0200 | [diff] [blame] | 274 | recv_cmd_id(qts, "err-2"); |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 275 | cleanup_blocking_cmd(); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 276 | |
| 277 | qtest_quit(qts); |
| 278 | } |
| 279 | |
Markus Armbruster | 97ca071 | 2018-07-03 10:53:31 +0200 | [diff] [blame] | 280 | /* Preconfig tests */ |
| 281 | |
Igor Mammedov | fb1e58f | 2018-05-17 13:28:44 +0200 | [diff] [blame] | 282 | static void test_qmp_preconfig(void) |
| 283 | { |
| 284 | QDict *rsp, *ret; |
Markus Armbruster | 88b988c | 2018-08-06 08:53:43 +0200 | [diff] [blame] | 285 | QTestState *qs = qtest_initf("%s --preconfig", common_args); |
Igor Mammedov | fb1e58f | 2018-05-17 13:28:44 +0200 | [diff] [blame] | 286 | |
| 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 Armbruster | 361ac94 | 2018-07-05 11:14:02 +0200 | [diff] [blame] | 302 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }"))); |
Igor Mammedov | fb1e58f | 2018-05-17 13:28:44 +0200 | [diff] [blame] | 303 | 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 Armbruster | 361ac94 | 2018-07-05 11:14:02 +0200 | [diff] [blame] | 312 | /* 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 Mammedov | fb1e58f | 2018-05-17 13:28:44 +0200 | [diff] [blame] | 314 | |
| 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é Lureau | 61793a6 | 2018-10-29 18:57:09 +0400 | [diff] [blame] | 321 | static 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 Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 334 | int main(int argc, char *argv[]) |
| 335 | { |
| 336 | g_test_init(&argc, &argv, NULL); |
| 337 | |
| 338 | qtest_add_func("qmp/protocol", test_qmp_protocol); |
Peter Xu | fa198ad | 2018-03-26 14:39:01 +0800 | [diff] [blame] | 339 | qtest_add_func("qmp/oob", test_qmp_oob); |
Igor Mammedov | fb1e58f | 2018-05-17 13:28:44 +0200 | [diff] [blame] | 340 | qtest_add_func("qmp/preconfig", test_qmp_preconfig); |
Marc-André Lureau | 61793a6 | 2018-10-29 18:57:09 +0400 | [diff] [blame] | 341 | qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 342 | |
Markus Armbruster | d93bb9d | 2018-08-23 18:39:32 +0200 | [diff] [blame] | 343 | return g_test_run(); |
Markus Armbruster | f66e7ac | 2017-03-03 13:32:23 +0100 | [diff] [blame] | 344 | } |