| 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-control.h" |
| 17 | #include "qobject/qdict.h" |
| 18 | #include "qobject/qlist.h" |
| 19 | #include "qapi/qobject-input-visitor.h" |
| 20 | #include "qobject/qstring.h" |
| 21 | |
| 22 | const char common_args[] = "-nodefaults -machine none"; |
| 23 | |
| 24 | static void test_version(QObject *version) |
| 25 | { |
| 26 | Visitor *v; |
| 27 | VersionInfo *vinfo; |
| 28 | |
| 29 | g_assert(version); |
| 30 | v = qobject_input_visitor_new(version); |
| 31 | visit_type_VersionInfo(v, "version", &vinfo, &error_abort); |
| 32 | qapi_free_VersionInfo(vinfo); |
| 33 | visit_free(v); |
| 34 | } |
| 35 | |
| 36 | static void assert_recovered(QTestState *qts) |
| 37 | { |
| 38 | QDict *resp; |
| 39 | |
| 40 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }"); |
| 41 | qmp_expect_error_and_unref(resp, "CommandNotFound"); |
| 42 | } |
| 43 | |
| 44 | static void test_malformed(QTestState *qts) |
| 45 | { |
| 46 | QDict *resp; |
| 47 | |
| 48 | /* syntax error */ |
| 49 | qtest_qmp_send_raw(qts, "{]\n"); |
| 50 | resp = qtest_qmp_receive_dict(qts); |
| 51 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 52 | assert_recovered(qts); |
| 53 | |
| 54 | /* lexical error: impossible byte outside string */ |
| 55 | qtest_qmp_send_raw(qts, "{\xFF"); |
| 56 | resp = qtest_qmp_receive_dict(qts); |
| 57 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 58 | assert_recovered(qts); |
| 59 | |
| 60 | /* lexical error: funny control character outside string */ |
| 61 | qtest_qmp_send_raw(qts, "{\x01"); |
| 62 | resp = qtest_qmp_receive_dict(qts); |
| 63 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 64 | assert_recovered(qts); |
| 65 | |
| 66 | /* lexical error: impossible byte in string */ |
| 67 | qtest_qmp_send_raw(qts, "{'bad \xFF"); |
| 68 | resp = qtest_qmp_receive_dict(qts); |
| 69 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 70 | assert_recovered(qts); |
| 71 | |
| 72 | /* lexical error: control character in string */ |
| 73 | qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n"); |
| 74 | resp = qtest_qmp_receive_dict(qts); |
| 75 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 76 | assert_recovered(qts); |
| 77 | |
| 78 | /* lexical error: interpolation */ |
| 79 | qtest_qmp_send_raw(qts, "%%p"); |
| 80 | resp = qtest_qmp_receive_dict(qts); |
| 81 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 82 | assert_recovered(qts); |
| 83 | |
| 84 | /* Not even a dictionary */ |
| 85 | resp = qtest_qmp(qts, "null"); |
| 86 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 87 | |
| 88 | /* No "execute" key */ |
| 89 | resp = qtest_qmp(qts, "{}"); |
| 90 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 91 | |
| 92 | /* "execute" isn't a string */ |
| 93 | resp = qtest_qmp(qts, "{ 'execute': true }"); |
| 94 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 95 | |
| 96 | /* "arguments" isn't a dictionary */ |
| 97 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }"); |
| 98 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 99 | |
| 100 | /* extra key */ |
| 101 | resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }"); |
| 102 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 103 | } |
| 104 | |
| 105 | static void test_qmp_protocol(void) |
| 106 | { |
| 107 | QDict *resp, *q, *ret; |
| 108 | QList *capabilities; |
| 109 | QTestState *qts; |
| 110 | |
| 111 | qts = qtest_init_without_qmp_handshake(common_args); |
| 112 | |
| 113 | /* Test greeting */ |
| 114 | resp = qtest_qmp_receive_dict(qts); |
| 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"); |
| 119 | g_assert(capabilities); |
| 120 | qobject_unref(resp); |
| 121 | |
| 122 | /* Test valid command before handshake */ |
| 123 | resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); |
| 124 | qmp_expect_error_and_unref(resp, "CommandNotFound"); |
| 125 | |
| 126 | /* Test malformed commands before handshake */ |
| 127 | test_malformed(qts); |
| 128 | |
| 129 | /* Test handshake */ |
| 130 | resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); |
| 131 | ret = qdict_get_qdict(resp, "return"); |
| 132 | g_assert(ret && !qdict_size(ret)); |
| 133 | qobject_unref(resp); |
| 134 | |
| 135 | /* Test repeated handshake */ |
| 136 | resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); |
| 137 | qmp_expect_error_and_unref(resp, "CommandNotFound"); |
| 138 | |
| 139 | /* Test valid command */ |
| 140 | resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); |
| 141 | test_version(qdict_get(resp, "return")); |
| 142 | qobject_unref(resp); |
| 143 | |
| 144 | /* Test malformed commands */ |
| 145 | test_malformed(qts); |
| 146 | |
| 147 | /* Test 'id' */ |
| 148 | resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }"); |
| 149 | ret = qdict_get_qdict(resp, "return"); |
| 150 | g_assert(ret); |
| 151 | g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); |
| 152 | qobject_unref(resp); |
| 153 | |
| 154 | /* Test integer 'id' is echoed back on success */ |
| 155 | resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 2 }"); |
| 156 | g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); |
| 157 | qobject_unref(resp); |
| 158 | |
| 159 | /* Test integer 'id' is echoed back on failure */ |
| 160 | resp = qtest_qmp(qts, "{ 'execute': 'block_resize', 'id': 3 }"); |
| 161 | g_assert_cmpint(qdict_get_int(resp, "id"), ==, 3); |
| 162 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 163 | |
| 164 | qtest_quit(qts); |
| 165 | } |
| 166 | |
| 167 | #ifndef _WIN32 |
| 168 | |
| 169 | /* Out-of-band tests */ |
| 170 | |
| 171 | char *tmpdir; |
| 172 | char *fifo_name; |
| 173 | |
| 174 | static void setup_blocking_cmd(void) |
| 175 | { |
| 176 | GError *err = NULL; |
| 177 | tmpdir = g_dir_make_tmp("qmp-test-XXXXXX", &err); |
| 178 | g_assert_no_error(err); |
| 179 | |
| 180 | fifo_name = g_strdup_printf("%s/fifo", tmpdir); |
| 181 | if (mkfifo(fifo_name, 0666)) { |
| 182 | g_error("mkfifo: %s", strerror(errno)); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | static void cleanup_blocking_cmd(void) |
| 187 | { |
| 188 | unlink(fifo_name); |
| 189 | rmdir(tmpdir); |
| 190 | g_free(tmpdir); |
| 191 | } |
| 192 | |
| 193 | static void send_cmd_that_blocks(QTestState *s, const char *id) |
| 194 | { |
| 195 | qtest_qmp_send(s, "{ 'execute': 'blockdev-add', 'id': %s," |
| 196 | " 'arguments': {" |
| 197 | " 'driver': 'blkdebug', 'node-name': %s," |
| 198 | " 'config': %s," |
| 199 | " 'image': { 'driver': 'null-co', 'read-zeroes': true } } }", |
| 200 | id, id, fifo_name); |
| 201 | } |
| 202 | |
| 203 | static void unblock_blocked_cmd(void) |
| 204 | { |
| 205 | int fd = open(fifo_name, O_WRONLY); |
| 206 | g_assert(fd >= 0); |
| 207 | close(fd); |
| 208 | } |
| 209 | |
| 210 | static void send_oob_cmd_that_fails(QTestState *s, const char *id) |
| 211 | { |
| 212 | qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id); |
| 213 | } |
| 214 | |
| 215 | static void recv_cmd_id(QTestState *s, const char *id) |
| 216 | { |
| 217 | QDict *resp = qtest_qmp_receive_dict(s); |
| 218 | |
| 219 | g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id); |
| 220 | qobject_unref(resp); |
| 221 | } |
| 222 | |
| 223 | static void test_qmp_oob(void) |
| 224 | { |
| 225 | QTestState *qts; |
| 226 | QDict *resp, *q; |
| 227 | const QListEntry *entry; |
| 228 | QList *capabilities; |
| 229 | QString *qstr; |
| 230 | |
| 231 | qts = qtest_init_without_qmp_handshake(common_args); |
| 232 | |
| 233 | /* Check the greeting message. */ |
| 234 | resp = qtest_qmp_receive_dict(qts); |
| 235 | q = qdict_get_qdict(resp, "QMP"); |
| 236 | g_assert(q); |
| 237 | capabilities = qdict_get_qlist(q, "capabilities"); |
| 238 | g_assert(capabilities && !qlist_empty(capabilities)); |
| 239 | entry = qlist_first(capabilities); |
| 240 | g_assert(entry); |
| 241 | qstr = qobject_to(QString, entry->value); |
| 242 | g_assert(qstr); |
| 243 | g_assert_cmpstr(qstring_get_str(qstr), ==, "oob"); |
| 244 | qobject_unref(resp); |
| 245 | |
| 246 | /* Try a fake capability, it should fail. */ |
| 247 | resp = qtest_qmp(qts, |
| 248 | "{ 'execute': 'qmp_capabilities', " |
| 249 | " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }"); |
| 250 | g_assert(qdict_haskey(resp, "error")); |
| 251 | qobject_unref(resp); |
| 252 | |
| 253 | /* Now, enable OOB in current QMP session, it should succeed. */ |
| 254 | resp = qtest_qmp(qts, |
| 255 | "{ 'execute': 'qmp_capabilities', " |
| 256 | " 'arguments': { 'enable': [ 'oob' ] } }"); |
| 257 | g_assert(qdict_haskey(resp, "return")); |
| 258 | qobject_unref(resp); |
| 259 | |
| 260 | /* |
| 261 | * Try any command that does not support OOB but with OOB flag. We |
| 262 | * should get failure. |
| 263 | */ |
| 264 | resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus-fast' }"); |
| 265 | g_assert(qdict_haskey(resp, "error")); |
| 266 | qobject_unref(resp); |
| 267 | |
| 268 | /* OOB command overtakes slow in-band command */ |
| 269 | setup_blocking_cmd(); |
| 270 | send_cmd_that_blocks(qts, "ib-blocks-1"); |
| 271 | qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }"); |
| 272 | send_oob_cmd_that_fails(qts, "oob-1"); |
| 273 | recv_cmd_id(qts, "oob-1"); |
| 274 | unblock_blocked_cmd(); |
| 275 | recv_cmd_id(qts, "ib-blocks-1"); |
| 276 | recv_cmd_id(qts, "ib-quick-1"); |
| 277 | |
| 278 | /* Even malformed in-band command fails in-band */ |
| 279 | send_cmd_that_blocks(qts, "blocks-2"); |
| 280 | qtest_qmp_send(qts, "{ 'id': 'err-2' }"); |
| 281 | unblock_blocked_cmd(); |
| 282 | recv_cmd_id(qts, "blocks-2"); |
| 283 | recv_cmd_id(qts, "err-2"); |
| 284 | cleanup_blocking_cmd(); |
| 285 | |
| 286 | qtest_quit(qts); |
| 287 | } |
| 288 | |
| 289 | #endif /* _WIN32 */ |
| 290 | |
| 291 | /* Preconfig tests */ |
| 292 | |
| 293 | static void test_qmp_preconfig(void) |
| 294 | { |
| 295 | QDict *rsp, *ret; |
| 296 | QTestState *qs = qtest_initf("%s --preconfig", common_args); |
| 297 | |
| 298 | /* preconfig state */ |
| 299 | /* enabled commands, no error expected */ |
| 300 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }"))); |
| 301 | |
| 302 | /* forbidden commands, expected error */ |
| 303 | g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus-fast' }"))); |
| 304 | |
| 305 | /* check that query-status returns preconfig 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"), ==, "prelaunch"); |
| 310 | qobject_unref(rsp); |
| 311 | |
| 312 | /* exit preconfig state */ |
| 313 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }"))); |
| 314 | qtest_qmp_eventwait(qs, "RESUME"); |
| 315 | |
| 316 | /* check that query-status returns running state */ |
| 317 | rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }"); |
| 318 | ret = qdict_get_qdict(rsp, "return"); |
| 319 | g_assert(ret); |
| 320 | g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running"); |
| 321 | qobject_unref(rsp); |
| 322 | |
| 323 | /* check that x-exit-preconfig returns error after exiting preconfig */ |
| 324 | g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }"))); |
| 325 | |
| 326 | /* enabled commands, no error expected */ |
| 327 | g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus-fast' }"))); |
| 328 | |
| 329 | qtest_quit(qs); |
| 330 | } |
| 331 | |
| 332 | static void test_qmp_missing_any_arg(void) |
| 333 | { |
| 334 | QTestState *qts; |
| 335 | QDict *resp; |
| 336 | |
| 337 | qts = qtest_init(common_args); |
| 338 | resp = qtest_qmp(qts, "{'execute': 'qom-set', 'arguments':" |
| 339 | " { 'path': '/machine', 'property': 'rtc-time' } }"); |
| 340 | g_assert_nonnull(resp); |
| 341 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 342 | qtest_quit(qts); |
| 343 | } |
| 344 | |
| 345 | static void test_qmp_monitor_add_remove(void) |
| 346 | { |
| 347 | QTestState *qts; |
| 348 | QDict *resp; |
| 349 | |
| 350 | qts = qtest_init(common_args); |
| 351 | |
| 352 | /* Create a null chardev for the dynamic monitor */ |
| 353 | resp = qtest_qmp(qts, |
| 354 | "{'execute': 'chardev-add'," |
| 355 | " 'arguments': {'id': 'monitor-chardev'," |
| 356 | " 'backend': {'type': 'null'," |
| 357 | " 'data': {}}}}"); |
| 358 | g_assert(qdict_haskey(resp, "return")); |
| 359 | qobject_unref(resp); |
| 360 | |
| 361 | /* Add a dynamic monitor */ |
| 362 | resp = qtest_qmp(qts, |
| 363 | "{'execute': 'object-add'," |
| 364 | " 'arguments': {'qom-type': 'monitor-qmp'," |
| 365 | " 'id': 'dyn-mon'," |
| 366 | " 'chardev': 'monitor-chardev'}}"); |
| 367 | g_assert(qdict_haskey(resp, "return")); |
| 368 | qobject_unref(resp); |
| 369 | |
| 370 | /* Remove the dynamic monitor */ |
| 371 | resp = qtest_qmp(qts, |
| 372 | "{'execute': 'object-del'," |
| 373 | " 'arguments': {'id': 'dyn-mon'}}"); |
| 374 | g_assert(qdict_haskey(resp, "return")); |
| 375 | qobject_unref(resp); |
| 376 | |
| 377 | /* Add again after remove -- same id and chardev should work */ |
| 378 | resp = qtest_qmp(qts, |
| 379 | "{'execute': 'object-add'," |
| 380 | " 'arguments': {'qom-type': 'monitor-qmp'," |
| 381 | " 'id': 'dyn-mon'," |
| 382 | " 'chardev': 'monitor-chardev'}}"); |
| 383 | g_assert(qdict_haskey(resp, "return")); |
| 384 | qobject_unref(resp); |
| 385 | |
| 386 | /* Clean up */ |
| 387 | resp = qtest_qmp(qts, |
| 388 | "{'execute': 'object-del'," |
| 389 | " 'arguments': {'id': 'dyn-mon'}}"); |
| 390 | g_assert(qdict_haskey(resp, "return")); |
| 391 | qobject_unref(resp); |
| 392 | |
| 393 | resp = qtest_qmp(qts, |
| 394 | "{'execute': 'chardev-remove'," |
| 395 | " 'arguments': {'id': 'monitor-chardev'}}"); |
| 396 | g_assert(qdict_haskey(resp, "return")); |
| 397 | qobject_unref(resp); |
| 398 | |
| 399 | qtest_quit(qts); |
| 400 | } |
| 401 | |
| 402 | static void test_qmp_monitor_error_paths(void) |
| 403 | { |
| 404 | QTestState *qts; |
| 405 | QDict *resp; |
| 406 | |
| 407 | qts = qtest_init(common_args); |
| 408 | |
| 409 | /* Error: chardev does not exist */ |
| 410 | resp = qtest_qmp(qts, |
| 411 | "{'execute': 'object-add'," |
| 412 | " 'arguments': {'qom-type': 'monitor-qmp'," |
| 413 | " 'id': 'bad-mon'," |
| 414 | " 'chardev': 'nonexistent'}}"); |
| 415 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 416 | |
| 417 | qtest_quit(qts); |
| 418 | } |
| 419 | |
| 420 | static void test_qmp_monitor_chardev_in_use(void) |
| 421 | { |
| 422 | QTestState *qts; |
| 423 | QDict *resp; |
| 424 | |
| 425 | qts = qtest_init(common_args); |
| 426 | |
| 427 | /* Create a null chardev */ |
| 428 | resp = qtest_qmp(qts, |
| 429 | "{'execute': 'chardev-add'," |
| 430 | " 'arguments': {'id': 'shared-chr'," |
| 431 | " 'backend': {'type': 'null'," |
| 432 | " 'data': {}}}}"); |
| 433 | g_assert(qdict_haskey(resp, "return")); |
| 434 | qobject_unref(resp); |
| 435 | |
| 436 | /* Attach first monitor */ |
| 437 | resp = qtest_qmp(qts, |
| 438 | "{'execute': 'object-add'," |
| 439 | " 'arguments': {'qom-type': 'monitor-qmp'," |
| 440 | " 'id': 'mon-1'," |
| 441 | " 'chardev': 'shared-chr'}}"); |
| 442 | g_assert(qdict_haskey(resp, "return")); |
| 443 | qobject_unref(resp); |
| 444 | |
| 445 | /* Error: second monitor on the same chardev */ |
| 446 | resp = qtest_qmp(qts, |
| 447 | "{'execute': 'object-add'," |
| 448 | " 'arguments': {'qom-type': 'monitor-qmp'," |
| 449 | " 'id': 'mon-2'," |
| 450 | " 'chardev': 'shared-chr'}}"); |
| 451 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 452 | |
| 453 | /* Clean up */ |
| 454 | resp = qtest_qmp(qts, |
| 455 | "{'execute': 'object-del'," |
| 456 | " 'arguments': {'id': 'mon-1'}}"); |
| 457 | g_assert(qdict_haskey(resp, "return")); |
| 458 | qobject_unref(resp); |
| 459 | |
| 460 | resp = qtest_qmp(qts, |
| 461 | "{'execute': 'chardev-remove'," |
| 462 | " 'arguments': {'id': 'shared-chr'}}"); |
| 463 | g_assert(qdict_haskey(resp, "return")); |
| 464 | qobject_unref(resp); |
| 465 | |
| 466 | qtest_quit(qts); |
| 467 | } |
| 468 | |
| 469 | static void test_qmp_monitor_remove_cli(void) |
| 470 | { |
| 471 | QTestState *qts; |
| 472 | QDict *resp; |
| 473 | |
| 474 | /* Launch with a named CLI monitor on a null chardev */ |
| 475 | qts = qtest_initf("%s -chardev null,id=cli-chr" |
| 476 | " -object monitor-qmp,id=cli-mon,chardev=cli-chr", |
| 477 | common_args); |
| 478 | |
| 479 | /* CLI-created QMP monitors can be removed */ |
| 480 | resp = qtest_qmp(qts, |
| 481 | "{'execute': 'object-del'," |
| 482 | " 'arguments': {'id': 'cli-mon'}}"); |
| 483 | g_assert(qdict_haskey(resp, "return")); |
| 484 | qobject_unref(resp); |
| 485 | |
| 486 | resp = qtest_qmp(qts, |
| 487 | "{'execute': 'chardev-remove'," |
| 488 | " 'arguments': {'id': 'cli-chr'}}"); |
| 489 | g_assert(qdict_haskey(resp, "return")); |
| 490 | qobject_unref(resp); |
| 491 | |
| 492 | qtest_quit(qts); |
| 493 | } |
| 494 | |
| 495 | #ifdef CONFIG_HMP |
| 496 | static void test_qmp_monitor_remove_hmp(void) |
| 497 | { |
| 498 | QTestState *qts; |
| 499 | QDict *resp; |
| 500 | |
| 501 | qts = qtest_initf("%s -chardev null,id=hmp-chr" |
| 502 | " -object monitor-hmp,id=hmp-mon,chardev=hmp-chr", |
| 503 | common_args); |
| 504 | |
| 505 | /* Error: object_del must reject HMP monitors */ |
| 506 | resp = qtest_qmp(qts, |
| 507 | "{'execute': 'object-del'," |
| 508 | " 'arguments': {'id': 'hmp-mon'}}"); |
| 509 | qmp_expect_error_and_unref(resp, "GenericError"); |
| 510 | |
| 511 | qtest_quit(qts); |
| 512 | } |
| 513 | #endif |
| 514 | |
| 515 | int main(int argc, char *argv[]) |
| 516 | { |
| 517 | g_test_init(&argc, &argv, NULL); |
| 518 | |
| 519 | qtest_add_func("qmp/protocol", test_qmp_protocol); |
| 520 | #ifndef _WIN32 |
| 521 | /* This case calls mkfifo() which does not exist on win32 */ |
| 522 | qtest_add_func("qmp/oob", test_qmp_oob); |
| 523 | #endif |
| 524 | qtest_add_func("qmp/preconfig", test_qmp_preconfig); |
| 525 | qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg); |
| 526 | qtest_add_func("qmp/monitor-add-remove", test_qmp_monitor_add_remove); |
| 527 | qtest_add_func("qmp/monitor-error-paths", test_qmp_monitor_error_paths); |
| 528 | qtest_add_func("qmp/monitor-chardev-in-use", |
| 529 | test_qmp_monitor_chardev_in_use); |
| 530 | qtest_add_func("qmp/monitor-remove-cli", test_qmp_monitor_remove_cli); |
| 531 | #ifdef CONFIG_HMP |
| 532 | qtest_add_func("qmp/monitor-remove-hmp", test_qmp_monitor_remove_hmp); |
| 533 | #endif |
| 534 | |
| 535 | return g_test_run(); |
| 536 | } |