1f66e7ac8SMarkus Armbruster /* 2f66e7ac8SMarkus Armbruster * QMP protocol test cases 3f66e7ac8SMarkus Armbruster * 4f66e7ac8SMarkus Armbruster * Copyright (c) 2017 Red Hat Inc. 5f66e7ac8SMarkus Armbruster * 6f66e7ac8SMarkus Armbruster * Authors: 7f66e7ac8SMarkus Armbruster * Markus Armbruster <armbru@redhat.com>, 8f66e7ac8SMarkus Armbruster * 9f66e7ac8SMarkus Armbruster * This work is licensed under the terms of the GNU GPL, version 2 or later. 10f66e7ac8SMarkus Armbruster * See the COPYING file in the top-level directory. 11f66e7ac8SMarkus Armbruster */ 12f66e7ac8SMarkus Armbruster 13f66e7ac8SMarkus Armbruster #include "qemu/osdep.h" 14f66e7ac8SMarkus Armbruster #include "libqtest.h" 15f66e7ac8SMarkus Armbruster #include "qapi/error.h" 16112ed241SMarkus Armbruster #include "qapi/qapi-visit-introspect.h" 17112ed241SMarkus Armbruster #include "qapi/qapi-visit-misc.h" 18452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 1947e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h" 20f66e7ac8SMarkus Armbruster #include "qapi/qobject-input-visitor.h" 21e4a426e7SMarkus Armbruster #include "qapi/util.h" 22f66e7ac8SMarkus Armbruster #include "qapi/visitor.h" 2302130314SPeter Xu #include "qapi/qmp/qstring.h" 24f66e7ac8SMarkus Armbruster 25f66e7ac8SMarkus Armbruster const char common_args[] = "-nodefaults -machine none"; 26f66e7ac8SMarkus Armbruster 27f66e7ac8SMarkus Armbruster static const char *get_error_class(QDict *resp) 28f66e7ac8SMarkus Armbruster { 29f66e7ac8SMarkus Armbruster QDict *error = qdict_get_qdict(resp, "error"); 30f66e7ac8SMarkus Armbruster const char *desc = qdict_get_try_str(error, "desc"); 31f66e7ac8SMarkus Armbruster 32f66e7ac8SMarkus Armbruster g_assert(desc); 33f66e7ac8SMarkus Armbruster return error ? qdict_get_try_str(error, "class") : NULL; 34f66e7ac8SMarkus Armbruster } 35f66e7ac8SMarkus Armbruster 36f66e7ac8SMarkus Armbruster static void test_version(QObject *version) 37f66e7ac8SMarkus Armbruster { 38f66e7ac8SMarkus Armbruster Visitor *v; 39f66e7ac8SMarkus Armbruster VersionInfo *vinfo; 40f66e7ac8SMarkus Armbruster 41f66e7ac8SMarkus Armbruster g_assert(version); 42048abb7bSMarkus Armbruster v = qobject_input_visitor_new(version); 43f66e7ac8SMarkus Armbruster visit_type_VersionInfo(v, "version", &vinfo, &error_abort); 44f66e7ac8SMarkus Armbruster qapi_free_VersionInfo(vinfo); 45f66e7ac8SMarkus Armbruster visit_free(v); 46f66e7ac8SMarkus Armbruster } 47f66e7ac8SMarkus Armbruster 486a5c88f5SEric Blake static void test_malformed(QTestState *qts) 49f66e7ac8SMarkus Armbruster { 50f66e7ac8SMarkus Armbruster QDict *resp; 51f66e7ac8SMarkus Armbruster 52f66e7ac8SMarkus Armbruster /* Not even a dictionary */ 536a5c88f5SEric Blake resp = qtest_qmp(qts, "null"); 54f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 55*cb3e7f08SMarc-André Lureau qobject_unref(resp); 56f66e7ac8SMarkus Armbruster 57f66e7ac8SMarkus Armbruster /* No "execute" key */ 586a5c88f5SEric Blake resp = qtest_qmp(qts, "{}"); 59f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 60*cb3e7f08SMarc-André Lureau qobject_unref(resp); 61f66e7ac8SMarkus Armbruster 62f66e7ac8SMarkus Armbruster /* "execute" isn't a string */ 636a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': true }"); 64f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 65*cb3e7f08SMarc-André Lureau qobject_unref(resp); 66f66e7ac8SMarkus Armbruster 67f66e7ac8SMarkus Armbruster /* "arguments" isn't a dictionary */ 686a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'arguments': [] }"); 69f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 70*cb3e7f08SMarc-André Lureau qobject_unref(resp); 71f66e7ac8SMarkus Armbruster 72f66e7ac8SMarkus Armbruster /* extra key */ 736a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'no-such-cmd', 'extra': true }"); 74f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 75*cb3e7f08SMarc-André Lureau qobject_unref(resp); 76f66e7ac8SMarkus Armbruster } 77f66e7ac8SMarkus Armbruster 78f66e7ac8SMarkus Armbruster static void test_qmp_protocol(void) 79f66e7ac8SMarkus Armbruster { 80f66e7ac8SMarkus Armbruster QDict *resp, *q, *ret; 81f66e7ac8SMarkus Armbruster QList *capabilities; 826a5c88f5SEric Blake QTestState *qts; 83f66e7ac8SMarkus Armbruster 84ddee57e0SEric Blake qts = qtest_init_without_qmp_handshake(false, common_args); 85f66e7ac8SMarkus Armbruster 86f66e7ac8SMarkus Armbruster /* Test greeting */ 876a5c88f5SEric Blake resp = qtest_qmp_receive(qts); 88f66e7ac8SMarkus Armbruster q = qdict_get_qdict(resp, "QMP"); 89f66e7ac8SMarkus Armbruster g_assert(q); 90f66e7ac8SMarkus Armbruster test_version(qdict_get(q, "version")); 91f66e7ac8SMarkus Armbruster capabilities = qdict_get_qlist(q, "capabilities"); 92a4f90923SPeter Xu g_assert(capabilities && qlist_empty(capabilities)); 93*cb3e7f08SMarc-André Lureau qobject_unref(resp); 94f66e7ac8SMarkus Armbruster 95f66e7ac8SMarkus Armbruster /* Test valid command before handshake */ 966a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); 97f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound"); 98*cb3e7f08SMarc-André Lureau qobject_unref(resp); 99f66e7ac8SMarkus Armbruster 100f66e7ac8SMarkus Armbruster /* Test malformed commands before handshake */ 1016a5c88f5SEric Blake test_malformed(qts); 102f66e7ac8SMarkus Armbruster 103f66e7ac8SMarkus Armbruster /* Test handshake */ 1046a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); 105f66e7ac8SMarkus Armbruster ret = qdict_get_qdict(resp, "return"); 106f66e7ac8SMarkus Armbruster g_assert(ret && !qdict_size(ret)); 107*cb3e7f08SMarc-André Lureau qobject_unref(resp); 108f66e7ac8SMarkus Armbruster 109f66e7ac8SMarkus Armbruster /* Test repeated handshake */ 1106a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'qmp_capabilities' }"); 111f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "CommandNotFound"); 112*cb3e7f08SMarc-André Lureau qobject_unref(resp); 113f66e7ac8SMarkus Armbruster 114f66e7ac8SMarkus Armbruster /* Test valid command */ 1156a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); 116f66e7ac8SMarkus Armbruster test_version(qdict_get(resp, "return")); 117*cb3e7f08SMarc-André Lureau qobject_unref(resp); 118f66e7ac8SMarkus Armbruster 119f66e7ac8SMarkus Armbruster /* Test malformed commands */ 1206a5c88f5SEric Blake test_malformed(qts); 121f66e7ac8SMarkus Armbruster 122f66e7ac8SMarkus Armbruster /* Test 'id' */ 1236a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'query-name', 'id': 'cookie#1' }"); 124f66e7ac8SMarkus Armbruster ret = qdict_get_qdict(resp, "return"); 125f66e7ac8SMarkus Armbruster g_assert(ret); 126f66e7ac8SMarkus Armbruster g_assert_cmpstr(qdict_get_try_str(resp, "id"), ==, "cookie#1"); 127*cb3e7f08SMarc-André Lureau qobject_unref(resp); 128f66e7ac8SMarkus Armbruster 129f66e7ac8SMarkus Armbruster /* Test command failure with 'id' */ 1306a5c88f5SEric Blake resp = qtest_qmp(qts, "{ 'execute': 'human-monitor-command', 'id': 2 }"); 131f66e7ac8SMarkus Armbruster g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 132f66e7ac8SMarkus Armbruster g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); 133*cb3e7f08SMarc-André Lureau qobject_unref(resp); 134f66e7ac8SMarkus Armbruster 1356a5c88f5SEric Blake qtest_quit(qts); 136f66e7ac8SMarkus Armbruster } 137f66e7ac8SMarkus Armbruster 138fa198ad9SPeter Xu /* Tests for Out-Of-Band support. */ 139fa198ad9SPeter Xu static void test_qmp_oob(void) 140fa198ad9SPeter Xu { 141fa198ad9SPeter Xu QTestState *qts; 142fa198ad9SPeter Xu QDict *resp, *q; 143fa198ad9SPeter Xu int acks = 0; 144fa198ad9SPeter Xu const QListEntry *entry; 145fa198ad9SPeter Xu QList *capabilities; 146fa198ad9SPeter Xu QString *qstr; 147fa198ad9SPeter Xu const char *cmd_id; 148fa198ad9SPeter Xu 149fa198ad9SPeter Xu qts = qtest_init_without_qmp_handshake(true, common_args); 150fa198ad9SPeter Xu 151fa198ad9SPeter Xu /* Check the greeting message. */ 152fa198ad9SPeter Xu resp = qtest_qmp_receive(qts); 153fa198ad9SPeter Xu q = qdict_get_qdict(resp, "QMP"); 154fa198ad9SPeter Xu g_assert(q); 155fa198ad9SPeter Xu capabilities = qdict_get_qlist(q, "capabilities"); 156fa198ad9SPeter Xu g_assert(capabilities && !qlist_empty(capabilities)); 157fa198ad9SPeter Xu entry = qlist_first(capabilities); 158fa198ad9SPeter Xu g_assert(entry); 159fa198ad9SPeter Xu qstr = qobject_to(QString, entry->value); 160fa198ad9SPeter Xu g_assert(qstr); 161fa198ad9SPeter Xu g_assert_cmpstr(qstring_get_str(qstr), ==, "oob"); 162*cb3e7f08SMarc-André Lureau qobject_unref(resp); 163fa198ad9SPeter Xu 164fa198ad9SPeter Xu /* Try a fake capability, it should fail. */ 165fa198ad9SPeter Xu resp = qtest_qmp(qts, 166fa198ad9SPeter Xu "{ 'execute': 'qmp_capabilities', " 167fa198ad9SPeter Xu " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }"); 168fa198ad9SPeter Xu g_assert(qdict_haskey(resp, "error")); 169*cb3e7f08SMarc-André Lureau qobject_unref(resp); 170fa198ad9SPeter Xu 171fa198ad9SPeter Xu /* Now, enable OOB in current QMP session, it should succeed. */ 172fa198ad9SPeter Xu resp = qtest_qmp(qts, 173fa198ad9SPeter Xu "{ 'execute': 'qmp_capabilities', " 174fa198ad9SPeter Xu " 'arguments': { 'enable': [ 'oob' ] } }"); 175fa198ad9SPeter Xu g_assert(qdict_haskey(resp, "return")); 176*cb3e7f08SMarc-André Lureau qobject_unref(resp); 177fa198ad9SPeter Xu 178fa198ad9SPeter Xu /* 179fa198ad9SPeter Xu * Try any command that does not support OOB but with OOB flag. We 180fa198ad9SPeter Xu * should get failure. 181fa198ad9SPeter Xu */ 182fa198ad9SPeter Xu resp = qtest_qmp(qts, 183fa198ad9SPeter Xu "{ 'execute': 'query-cpus'," 184fa198ad9SPeter Xu " 'control': { 'run-oob': true } }"); 185fa198ad9SPeter Xu g_assert(qdict_haskey(resp, "error")); 186*cb3e7f08SMarc-André Lureau qobject_unref(resp); 187fa198ad9SPeter Xu 188fa198ad9SPeter Xu /* 189fa198ad9SPeter Xu * First send the "x-oob-test" command with lock=true and 190fa198ad9SPeter Xu * oob=false, it should hang the dispatcher and main thread; 191fa198ad9SPeter Xu * later, we send another lock=false with oob=true to continue 192fa198ad9SPeter Xu * that thread processing. Finally we should receive replies from 193fa198ad9SPeter Xu * both commands. 194fa198ad9SPeter Xu */ 195fa198ad9SPeter Xu qtest_async_qmp(qts, 196fa198ad9SPeter Xu "{ 'execute': 'x-oob-test'," 197fa198ad9SPeter Xu " 'arguments': { 'lock': true }, " 198fa198ad9SPeter Xu " 'id': 'lock-cmd'}"); 199fa198ad9SPeter Xu qtest_async_qmp(qts, 200fa198ad9SPeter Xu "{ 'execute': 'x-oob-test', " 201fa198ad9SPeter Xu " 'arguments': { 'lock': false }, " 202fa198ad9SPeter Xu " 'control': { 'run-oob': true }, " 203fa198ad9SPeter Xu " 'id': 'unlock-cmd' }"); 204fa198ad9SPeter Xu 205fa198ad9SPeter Xu /* Ignore all events. Wait for 2 acks */ 206fa198ad9SPeter Xu while (acks < 2) { 207fa198ad9SPeter Xu resp = qtest_qmp_receive(qts); 208fa198ad9SPeter Xu cmd_id = qdict_get_str(resp, "id"); 209fa198ad9SPeter Xu if (!g_strcmp0(cmd_id, "lock-cmd") || 210fa198ad9SPeter Xu !g_strcmp0(cmd_id, "unlock-cmd")) { 211fa198ad9SPeter Xu acks++; 212fa198ad9SPeter Xu } 213*cb3e7f08SMarc-André Lureau qobject_unref(resp); 214fa198ad9SPeter Xu } 215fa198ad9SPeter Xu 216fa198ad9SPeter Xu qtest_quit(qts); 217fa198ad9SPeter Xu } 218fa198ad9SPeter Xu 219e4a426e7SMarkus Armbruster static int query_error_class(const char *cmd) 220e4a426e7SMarkus Armbruster { 221e4a426e7SMarkus Armbruster static struct { 222e4a426e7SMarkus Armbruster const char *cmd; 223e4a426e7SMarkus Armbruster int err_class; 224e4a426e7SMarkus Armbruster } fails[] = { 225e4a426e7SMarkus Armbruster /* Success depends on build configuration: */ 226e4a426e7SMarkus Armbruster #ifndef CONFIG_SPICE 227e4a426e7SMarkus Armbruster { "query-spice", ERROR_CLASS_COMMAND_NOT_FOUND }, 228e4a426e7SMarkus Armbruster #endif 229e4a426e7SMarkus Armbruster #ifndef CONFIG_VNC 230e4a426e7SMarkus Armbruster { "query-vnc", ERROR_CLASS_GENERIC_ERROR }, 231e4a426e7SMarkus Armbruster { "query-vnc-servers", ERROR_CLASS_GENERIC_ERROR }, 232e4a426e7SMarkus Armbruster #endif 233e4a426e7SMarkus Armbruster #ifndef CONFIG_REPLICATION 234e4a426e7SMarkus Armbruster { "query-xen-replication-status", ERROR_CLASS_COMMAND_NOT_FOUND }, 235e4a426e7SMarkus Armbruster #endif 236e4a426e7SMarkus Armbruster /* Likewise, and require special QEMU command-line arguments: */ 237e4a426e7SMarkus Armbruster { "query-acpi-ospm-status", ERROR_CLASS_GENERIC_ERROR }, 238e4a426e7SMarkus Armbruster { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE }, 239e4a426e7SMarkus Armbruster { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR }, 240e4a426e7SMarkus Armbruster { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR }, 241e4a426e7SMarkus Armbruster { NULL, -1 } 242e4a426e7SMarkus Armbruster }; 243e4a426e7SMarkus Armbruster int i; 244e4a426e7SMarkus Armbruster 245e4a426e7SMarkus Armbruster for (i = 0; fails[i].cmd; i++) { 246e4a426e7SMarkus Armbruster if (!strcmp(cmd, fails[i].cmd)) { 247e4a426e7SMarkus Armbruster return fails[i].err_class; 248e4a426e7SMarkus Armbruster } 249e4a426e7SMarkus Armbruster } 250e4a426e7SMarkus Armbruster return -1; 251e4a426e7SMarkus Armbruster } 252e4a426e7SMarkus Armbruster 253e4a426e7SMarkus Armbruster static void test_query(const void *data) 254e4a426e7SMarkus Armbruster { 255e4a426e7SMarkus Armbruster const char *cmd = data; 256e4a426e7SMarkus Armbruster int expected_error_class = query_error_class(cmd); 257e4a426e7SMarkus Armbruster QDict *resp, *error; 258e4a426e7SMarkus Armbruster const char *error_class; 259e4a426e7SMarkus Armbruster 260e4a426e7SMarkus Armbruster qtest_start(common_args); 261e4a426e7SMarkus Armbruster 262e4a426e7SMarkus Armbruster resp = qmp("{ 'execute': %s }", cmd); 263e4a426e7SMarkus Armbruster error = qdict_get_qdict(resp, "error"); 264e4a426e7SMarkus Armbruster error_class = error ? qdict_get_str(error, "class") : NULL; 265e4a426e7SMarkus Armbruster 266e4a426e7SMarkus Armbruster if (expected_error_class < 0) { 267e4a426e7SMarkus Armbruster g_assert(qdict_haskey(resp, "return")); 268e4a426e7SMarkus Armbruster } else { 269e4a426e7SMarkus Armbruster g_assert(error); 270f7abe0ecSMarc-André Lureau g_assert_cmpint(qapi_enum_parse(&QapiErrorClass_lookup, error_class, 27106c60b6cSMarkus Armbruster -1, &error_abort), 272e4a426e7SMarkus Armbruster ==, expected_error_class); 273e4a426e7SMarkus Armbruster } 274*cb3e7f08SMarc-André Lureau qobject_unref(resp); 275e4a426e7SMarkus Armbruster 276e4a426e7SMarkus Armbruster qtest_end(); 277e4a426e7SMarkus Armbruster } 278e4a426e7SMarkus Armbruster 279e4a426e7SMarkus Armbruster static bool query_is_blacklisted(const char *cmd) 280e4a426e7SMarkus Armbruster { 281e4a426e7SMarkus Armbruster const char *blacklist[] = { 282e4a426e7SMarkus Armbruster /* Not actually queries: */ 283e4a426e7SMarkus Armbruster "add-fd", 284e4a426e7SMarkus Armbruster /* Success depends on target arch: */ 285e4a426e7SMarkus Armbruster "query-cpu-definitions", /* arm, i386, ppc, s390x */ 286e4a426e7SMarkus Armbruster "query-gic-capabilities", /* arm */ 287e4a426e7SMarkus Armbruster /* Success depends on target-specific build configuration: */ 288e4a426e7SMarkus Armbruster "query-pci", /* CONFIG_PCI */ 2891b6a034fSBrijesh Singh /* Success depends on launching SEV guest */ 2901b6a034fSBrijesh Singh "query-sev-launch-measure", 29108a161fdSBrijesh Singh /* Success depends on Host or Hypervisor SEV support */ 29208a161fdSBrijesh Singh "query-sev", 29331dd67f6SBrijesh Singh "query-sev-capabilities", 294e4a426e7SMarkus Armbruster NULL 295e4a426e7SMarkus Armbruster }; 296e4a426e7SMarkus Armbruster int i; 297e4a426e7SMarkus Armbruster 298e4a426e7SMarkus Armbruster for (i = 0; blacklist[i]; i++) { 299e4a426e7SMarkus Armbruster if (!strcmp(cmd, blacklist[i])) { 300e4a426e7SMarkus Armbruster return true; 301e4a426e7SMarkus Armbruster } 302e4a426e7SMarkus Armbruster } 303e4a426e7SMarkus Armbruster return false; 304e4a426e7SMarkus Armbruster } 305e4a426e7SMarkus Armbruster 306e4a426e7SMarkus Armbruster typedef struct { 307e4a426e7SMarkus Armbruster SchemaInfoList *list; 308e4a426e7SMarkus Armbruster GHashTable *hash; 309e4a426e7SMarkus Armbruster } QmpSchema; 310e4a426e7SMarkus Armbruster 311e4a426e7SMarkus Armbruster static void qmp_schema_init(QmpSchema *schema) 312e4a426e7SMarkus Armbruster { 313e4a426e7SMarkus Armbruster QDict *resp; 314e4a426e7SMarkus Armbruster Visitor *qiv; 315e4a426e7SMarkus Armbruster SchemaInfoList *tail; 316e4a426e7SMarkus Armbruster 317e4a426e7SMarkus Armbruster qtest_start(common_args); 318e4a426e7SMarkus Armbruster resp = qmp("{ 'execute': 'query-qmp-schema' }"); 319e4a426e7SMarkus Armbruster 320e4a426e7SMarkus Armbruster qiv = qobject_input_visitor_new(qdict_get(resp, "return")); 321e4a426e7SMarkus Armbruster visit_type_SchemaInfoList(qiv, NULL, &schema->list, &error_abort); 322e4a426e7SMarkus Armbruster visit_free(qiv); 323e4a426e7SMarkus Armbruster 324*cb3e7f08SMarc-André Lureau qobject_unref(resp); 325e4a426e7SMarkus Armbruster qtest_end(); 326e4a426e7SMarkus Armbruster 327e4a426e7SMarkus Armbruster schema->hash = g_hash_table_new(g_str_hash, g_str_equal); 328e4a426e7SMarkus Armbruster 329e4a426e7SMarkus Armbruster /* Build @schema: hash table mapping entity name to SchemaInfo */ 330e4a426e7SMarkus Armbruster for (tail = schema->list; tail; tail = tail->next) { 331e4a426e7SMarkus Armbruster g_hash_table_insert(schema->hash, tail->value->name, tail->value); 332e4a426e7SMarkus Armbruster } 333e4a426e7SMarkus Armbruster } 334e4a426e7SMarkus Armbruster 335e4a426e7SMarkus Armbruster static SchemaInfo *qmp_schema_lookup(QmpSchema *schema, const char *name) 336e4a426e7SMarkus Armbruster { 337e4a426e7SMarkus Armbruster return g_hash_table_lookup(schema->hash, name); 338e4a426e7SMarkus Armbruster } 339e4a426e7SMarkus Armbruster 340e4a426e7SMarkus Armbruster static void qmp_schema_cleanup(QmpSchema *schema) 341e4a426e7SMarkus Armbruster { 342e4a426e7SMarkus Armbruster qapi_free_SchemaInfoList(schema->list); 343e4a426e7SMarkus Armbruster g_hash_table_destroy(schema->hash); 344e4a426e7SMarkus Armbruster } 345e4a426e7SMarkus Armbruster 346e4a426e7SMarkus Armbruster static bool object_type_has_mandatory_members(SchemaInfo *type) 347e4a426e7SMarkus Armbruster { 348e4a426e7SMarkus Armbruster SchemaInfoObjectMemberList *tail; 349e4a426e7SMarkus Armbruster 350e4a426e7SMarkus Armbruster g_assert(type->meta_type == SCHEMA_META_TYPE_OBJECT); 351e4a426e7SMarkus Armbruster 352e4a426e7SMarkus Armbruster for (tail = type->u.object.members; tail; tail = tail->next) { 353e4a426e7SMarkus Armbruster if (!tail->value->has_q_default) { 354e4a426e7SMarkus Armbruster return true; 355e4a426e7SMarkus Armbruster } 356e4a426e7SMarkus Armbruster } 357e4a426e7SMarkus Armbruster 358e4a426e7SMarkus Armbruster return false; 359e4a426e7SMarkus Armbruster } 360e4a426e7SMarkus Armbruster 361e4a426e7SMarkus Armbruster static void add_query_tests(QmpSchema *schema) 362e4a426e7SMarkus Armbruster { 363e4a426e7SMarkus Armbruster SchemaInfoList *tail; 364e4a426e7SMarkus Armbruster SchemaInfo *si, *arg_type, *ret_type; 365e313d5ceSMarc-André Lureau char *test_name; 366e4a426e7SMarkus Armbruster 367e4a426e7SMarkus Armbruster /* Test the query-like commands */ 368e4a426e7SMarkus Armbruster for (tail = schema->list; tail; tail = tail->next) { 369e4a426e7SMarkus Armbruster si = tail->value; 370e4a426e7SMarkus Armbruster if (si->meta_type != SCHEMA_META_TYPE_COMMAND) { 371e4a426e7SMarkus Armbruster continue; 372e4a426e7SMarkus Armbruster } 373e4a426e7SMarkus Armbruster 374e4a426e7SMarkus Armbruster if (query_is_blacklisted(si->name)) { 375e4a426e7SMarkus Armbruster continue; 376e4a426e7SMarkus Armbruster } 377e4a426e7SMarkus Armbruster 378e4a426e7SMarkus Armbruster arg_type = qmp_schema_lookup(schema, si->u.command.arg_type); 379e4a426e7SMarkus Armbruster if (object_type_has_mandatory_members(arg_type)) { 380e4a426e7SMarkus Armbruster continue; 381e4a426e7SMarkus Armbruster } 382e4a426e7SMarkus Armbruster 383e4a426e7SMarkus Armbruster ret_type = qmp_schema_lookup(schema, si->u.command.ret_type); 384e4a426e7SMarkus Armbruster if (ret_type->meta_type == SCHEMA_META_TYPE_OBJECT 385e4a426e7SMarkus Armbruster && !ret_type->u.object.members) { 386e4a426e7SMarkus Armbruster continue; 387e4a426e7SMarkus Armbruster } 388e4a426e7SMarkus Armbruster 389e4a426e7SMarkus Armbruster test_name = g_strdup_printf("qmp/%s", si->name); 390e4a426e7SMarkus Armbruster qtest_add_data_func(test_name, si->name, test_query); 391e313d5ceSMarc-André Lureau g_free(test_name); 392e4a426e7SMarkus Armbruster } 393e4a426e7SMarkus Armbruster } 394e4a426e7SMarkus Armbruster 395f66e7ac8SMarkus Armbruster int main(int argc, char *argv[]) 396f66e7ac8SMarkus Armbruster { 397e4a426e7SMarkus Armbruster QmpSchema schema; 398e4a426e7SMarkus Armbruster int ret; 399e4a426e7SMarkus Armbruster 400f66e7ac8SMarkus Armbruster g_test_init(&argc, &argv, NULL); 401f66e7ac8SMarkus Armbruster 402f66e7ac8SMarkus Armbruster qtest_add_func("qmp/protocol", test_qmp_protocol); 403fa198ad9SPeter Xu qtest_add_func("qmp/oob", test_qmp_oob); 404e4a426e7SMarkus Armbruster qmp_schema_init(&schema); 405e4a426e7SMarkus Armbruster add_query_tests(&schema); 406f66e7ac8SMarkus Armbruster 407e4a426e7SMarkus Armbruster ret = g_test_run(); 408e4a426e7SMarkus Armbruster 409e4a426e7SMarkus Armbruster qmp_schema_cleanup(&schema); 410e4a426e7SMarkus Armbruster return ret; 411f66e7ac8SMarkus Armbruster } 412