2
0

qmp-test.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. #include "qemu/osdep.h"
  13. #include "libqtest.h"
  14. #include "qapi/error.h"
  15. #include "qapi/qapi-visit-misc.h"
  16. #include "qapi/qmp/qdict.h"
  17. #include "qapi/qmp/qlist.h"
  18. #include "qapi/qobject-input-visitor.h"
  19. #include "qapi/qmp/qstring.h"
  20. const char common_args[] = "-nodefaults -machine none";
  21. static void test_version(QObject *version)
  22. {
  23. Visitor *v;
  24. VersionInfo *vinfo;
  25. g_assert(version);
  26. v = qobject_input_visitor_new(version);
  27. visit_type_VersionInfo(v, "version", &vinfo, &error_abort);
  28. qapi_free_VersionInfo(vinfo);
  29. visit_free(v);
  30. }
  31. static void assert_recovered(QTestState *qts)
  32. {
  33. QDict *resp;
  34. resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd' }");
  35. qmp_assert_error_class(resp, "CommandNotFound");
  36. }
  37. static void test_malformed(QTestState *qts)
  38. {
  39. QDict *resp;
  40. /* syntax error */
  41. qtest_qmp_send_raw(qts, "{]\n");
  42. resp = qtest_qmp_receive(qts);
  43. qmp_assert_error_class(resp, "GenericError");
  44. assert_recovered(qts);
  45. /* lexical error: impossible byte outside string */
  46. qtest_qmp_send_raw(qts, "{\xFF");
  47. resp = qtest_qmp_receive(qts);
  48. qmp_assert_error_class(resp, "GenericError");
  49. assert_recovered(qts);
  50. /* lexical error: funny control character outside string */
  51. qtest_qmp_send_raw(qts, "{\x01");
  52. resp = qtest_qmp_receive(qts);
  53. qmp_assert_error_class(resp, "GenericError");
  54. assert_recovered(qts);
  55. /* lexical error: impossible byte in string */
  56. qtest_qmp_send_raw(qts, "{'bad \xFF");
  57. resp = qtest_qmp_receive(qts);
  58. qmp_assert_error_class(resp, "GenericError");
  59. assert_recovered(qts);
  60. /* lexical error: control character in string */
  61. qtest_qmp_send_raw(qts, "{'execute': 'nonexistent', 'id':'\n");
  62. resp = qtest_qmp_receive(qts);
  63. qmp_assert_error_class(resp, "GenericError");
  64. assert_recovered(qts);
  65. /* lexical error: interpolation */
  66. qtest_qmp_send_raw(qts, "%%p");
  67. resp = qtest_qmp_receive(qts);
  68. qmp_assert_error_class(resp, "GenericError");
  69. assert_recovered(qts);
  70. /* Not even a dictionary */
  71. resp = qtest_qmp(qts, "null");
  72. qmp_assert_error_class(resp, "GenericError");
  73. /* No "execute" key */
  74. resp = qtest_qmp(qts, "{}");
  75. qmp_assert_error_class(resp, "GenericError");
  76. /* "execute" isn't a string */
  77. resp = qtest_qmp(qts, "{ 'execute': true }");
  78. qmp_assert_error_class(resp, "GenericError");
  79. /* "arguments" isn't a dictionary */
  80. resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }");
  81. qmp_assert_error_class(resp, "GenericError");
  82. /* extra key */
  83. resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }");
  84. qmp_assert_error_class(resp, "GenericError");
  85. }
  86. static void test_qmp_protocol(void)
  87. {
  88. QDict *resp, *q, *ret;
  89. QList *capabilities;
  90. QTestState *qts;
  91. qts = qtest_init_without_qmp_handshake(common_args);
  92. /* Test greeting */
  93. resp = qtest_qmp_receive(qts);
  94. q = qdict_get_qdict(resp, "QMP");
  95. g_assert(q);
  96. test_version(qdict_get(q, "version"));
  97. capabilities = qdict_get_qlist(q, "capabilities");
  98. g_assert(capabilities);
  99. qobject_unref(resp);
  100. /* Test valid command before handshake */
  101. resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
  102. qmp_assert_error_class(resp, "CommandNotFound");
  103. /* Test malformed commands before handshake */
  104. test_malformed(qts);
  105. /* Test handshake */
  106. resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
  107. ret = qdict_get_qdict(resp, "return");
  108. g_assert(ret && !qdict_size(ret));
  109. qobject_unref(resp);
  110. /* Test repeated handshake */
  111. resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }");
  112. qmp_assert_error_class(resp, "CommandNotFound");
  113. /* Test valid command */
  114. resp = qtest_qmp(qts, "{ 'execute': 'query-version' }");
  115. test_version(qdict_get(resp, "return"));
  116. qobject_unref(resp);
  117. /* Test malformed commands */
  118. test_malformed(qts);
  119. /* Test 'id' */
  120. resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }");
  121. ret = qdict_get_qdict(resp, "return");
  122. g_assert(ret);
  123. g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1");
  124. qobject_unref(resp);
  125. /* Test command failure with 'id' */
  126. resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }");
  127. g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2);
  128. qmp_assert_error_class(resp, "GenericError");
  129. qtest_quit(qts);
  130. }
  131. /* Out-of-band tests */
  132. char tmpdir[] = "/tmp/qmp-test-XXXXXX";
  133. char *fifo_name;
  134. static void setup_blocking_cmd(void)
  135. {
  136. if (!mkdtemp(tmpdir)) {
  137. g_error("mkdtemp: %s", strerror(errno));
  138. }
  139. fifo_name = g_strdup_printf("%s/fifo", tmpdir);
  140. if (mkfifo(fifo_name, 0666)) {
  141. g_error("mkfifo: %s", strerror(errno));
  142. }
  143. }
  144. static void cleanup_blocking_cmd(void)
  145. {
  146. unlink(fifo_name);
  147. rmdir(tmpdir);
  148. }
  149. static void send_cmd_that_blocks(QTestState *s, const char *id)
  150. {
  151. qtest_qmp_send(s, "{ 'execute': 'blockdev-add', 'id': %s,"
  152. " 'arguments': {"
  153. " 'driver': 'blkdebug', 'node-name': %s,"
  154. " 'config': %s,"
  155. " 'image': { 'driver': 'null-co', 'read-zeroes': true } } }",
  156. id, id, fifo_name);
  157. }
  158. static void unblock_blocked_cmd(void)
  159. {
  160. int fd = open(fifo_name, O_WRONLY);
  161. g_assert(fd >= 0);
  162. close(fd);
  163. }
  164. static void send_oob_cmd_that_fails(QTestState *s, const char *id)
  165. {
  166. qtest_qmp_send(s, "{ 'exec-oob': 'migrate-pause', 'id': %s }", id);
  167. }
  168. static void recv_cmd_id(QTestState *s, const char *id)
  169. {
  170. QDict *resp = qtest_qmp_receive(s);
  171. g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, id);
  172. qobject_unref(resp);
  173. }
  174. static void test_qmp_oob(void)
  175. {
  176. QTestState *qts;
  177. QDict *resp, *q;
  178. const QListEntry *entry;
  179. QList *capabilities;
  180. QString *qstr;
  181. qts = qtest_init_without_qmp_handshake(common_args);
  182. /* Check the greeting message. */
  183. resp = qtest_qmp_receive(qts);
  184. q = qdict_get_qdict(resp, "QMP");
  185. g_assert(q);
  186. capabilities = qdict_get_qlist(q, "capabilities");
  187. g_assert(capabilities && !qlist_empty(capabilities));
  188. entry = qlist_first(capabilities);
  189. g_assert(entry);
  190. qstr = qobject_to(QString, entry->value);
  191. g_assert(qstr);
  192. g_assert_cmpstr(qstring_get_str(qstr), ==, "oob");
  193. qobject_unref(resp);
  194. /* Try a fake capability, it should fail. */
  195. resp = qtest_qmp(qts,
  196. "{ 'execute': 'qmp_capabilities', "
  197. " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }");
  198. g_assert(qdict_haskey(resp, "error"));
  199. qobject_unref(resp);
  200. /* Now, enable OOB in current QMP session, it should succeed. */
  201. resp = qtest_qmp(qts,
  202. "{ 'execute': 'qmp_capabilities', "
  203. " 'arguments': { 'enable': [ 'oob' ] } }");
  204. g_assert(qdict_haskey(resp, "return"));
  205. qobject_unref(resp);
  206. /*
  207. * Try any command that does not support OOB but with OOB flag. We
  208. * should get failure.
  209. */
  210. resp = qtest_qmp(qts, "{ 'exec-oob': 'query-cpus' }");
  211. g_assert(qdict_haskey(resp, "error"));
  212. qobject_unref(resp);
  213. /* OOB command overtakes slow in-band command */
  214. setup_blocking_cmd();
  215. send_cmd_that_blocks(qts, "ib-blocks-1");
  216. qtest_qmp_send(qts, "{ 'execute': 'query-name', 'id': 'ib-quick-1' }");
  217. send_oob_cmd_that_fails(qts, "oob-1");
  218. recv_cmd_id(qts, "oob-1");
  219. unblock_blocked_cmd();
  220. recv_cmd_id(qts, "ib-blocks-1");
  221. recv_cmd_id(qts, "ib-quick-1");
  222. /* Even malformed in-band command fails in-band */
  223. send_cmd_that_blocks(qts, "blocks-2");
  224. qtest_qmp_send(qts, "{ 'id': 'err-2' }");
  225. unblock_blocked_cmd();
  226. recv_cmd_id(qts, "blocks-2");
  227. recv_cmd_id(qts, "err-2");
  228. cleanup_blocking_cmd();
  229. qtest_quit(qts);
  230. }
  231. /* Preconfig tests */
  232. static void test_qmp_preconfig(void)
  233. {
  234. QDict *rsp, *ret;
  235. QTestState *qs = qtest_initf("%s --preconfig", common_args);
  236. /* preconfig state */
  237. /* enabled commands, no error expected */
  238. g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-commands' }")));
  239. /* forbidden commands, expected error */
  240. g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
  241. /* check that query-status returns preconfig state */
  242. rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
  243. ret = qdict_get_qdict(rsp, "return");
  244. g_assert(ret);
  245. g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "preconfig");
  246. qobject_unref(rsp);
  247. /* exit preconfig state */
  248. g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
  249. qtest_qmp_eventwait(qs, "RESUME");
  250. /* check that query-status returns running state */
  251. rsp = qtest_qmp(qs, "{ 'execute': 'query-status' }");
  252. ret = qdict_get_qdict(rsp, "return");
  253. g_assert(ret);
  254. g_assert_cmpstr(qdict_get_try_str(ret, "status"), ==, "running");
  255. qobject_unref(rsp);
  256. /* check that x-exit-preconfig returns error after exiting preconfig */
  257. g_assert(qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'x-exit-preconfig' }")));
  258. /* enabled commands, no error expected */
  259. g_assert(!qmp_rsp_is_err(qtest_qmp(qs, "{ 'execute': 'query-cpus' }")));
  260. qtest_quit(qs);
  261. }
  262. static void test_qmp_missing_any_arg(void)
  263. {
  264. QTestState *qts;
  265. QDict *resp;
  266. qts = qtest_init(common_args);
  267. resp = qtest_qmp(qts, "{'execute': 'qom-set', 'arguments':"
  268. " { 'path': '/machine', 'property': 'rtc-time' } }");
  269. g_assert_nonnull(resp);
  270. qmp_assert_error_class(resp, "GenericError");
  271. qtest_quit(qts);
  272. }
  273. int main(int argc, char *argv[])
  274. {
  275. g_test_init(&argc, &argv, NULL);
  276. qtest_add_func("qmp/protocol", test_qmp_protocol);
  277. qtest_add_func("qmp/oob", test_qmp_oob);
  278. qtest_add_func("qmp/preconfig", test_qmp_preconfig);
  279. qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg);
  280. return g_test_run();
  281. }