12d1abb85SMarkus Armbruster /* 22d1abb85SMarkus Armbruster * Device introspection test cases 32d1abb85SMarkus Armbruster * 42d1abb85SMarkus Armbruster * Copyright (c) 2015 Red Hat Inc. 52d1abb85SMarkus Armbruster * 62d1abb85SMarkus Armbruster * Authors: 72d1abb85SMarkus Armbruster * Markus Armbruster <armbru@redhat.com>, 82d1abb85SMarkus Armbruster * 92d1abb85SMarkus Armbruster * This work is licensed under the terms of the GNU GPL, version 2 or later. 102d1abb85SMarkus Armbruster * See the COPYING file in the top-level directory. 112d1abb85SMarkus Armbruster */ 122d1abb85SMarkus Armbruster 132d1abb85SMarkus Armbruster /* 142d1abb85SMarkus Armbruster * Covers QMP device-list-properties and HMP device_add help. We 152d1abb85SMarkus Armbruster * currently don't check that their output makes sense, only that QEMU 162d1abb85SMarkus Armbruster * survives. Useful since we've had an astounding number of crash 172d1abb85SMarkus Armbruster * bugs around here. 182d1abb85SMarkus Armbruster */ 192d1abb85SMarkus Armbruster 20681c28a3SPeter Maydell #include "qemu/osdep.h" 212d1abb85SMarkus Armbruster #include "qemu-common.h" 222d1abb85SMarkus Armbruster #include "qapi/qmp/qstring.h" 231c6d75d5SEduardo Habkost #include "qapi/qmp/qbool.h" 241c6d75d5SEduardo Habkost #include "qapi/qmp/qdict.h" 252d1abb85SMarkus Armbruster #include "libqtest.h" 262d1abb85SMarkus Armbruster 272d1abb85SMarkus Armbruster const char common_args[] = "-nodefaults -machine none"; 282d1abb85SMarkus Armbruster 291c6d75d5SEduardo Habkost static QList *qom_list_types(const char *implements, bool abstract) 302d1abb85SMarkus Armbruster { 312d1abb85SMarkus Armbruster QDict *resp; 322d1abb85SMarkus Armbruster QList *ret; 331c6d75d5SEduardo Habkost QDict *args = qdict_new(); 342d1abb85SMarkus Armbruster 3546f5ac20SEric Blake qdict_put_bool(args, "abstract", abstract); 361c6d75d5SEduardo Habkost if (implements) { 3746f5ac20SEric Blake qdict_put_str(args, "implements", implements); 381c6d75d5SEduardo Habkost } 392d1abb85SMarkus Armbruster resp = qmp("{'execute': 'qom-list-types'," 401c6d75d5SEduardo Habkost " 'arguments': %p }", args); 412d1abb85SMarkus Armbruster g_assert(qdict_haskey(resp, "return")); 422d1abb85SMarkus Armbruster ret = qdict_get_qlist(resp, "return"); 432d1abb85SMarkus Armbruster QINCREF(ret); 442d1abb85SMarkus Armbruster QDECREF(resp); 452d1abb85SMarkus Armbruster return ret; 462d1abb85SMarkus Armbruster } 472d1abb85SMarkus Armbruster 48*dbb2a604SEduardo Habkost /* Find an entry on a list returned by qom-list-types */ 49*dbb2a604SEduardo Habkost static QDict *type_list_find(QList *types, const char *name) 50*dbb2a604SEduardo Habkost { 51*dbb2a604SEduardo Habkost QListEntry *e; 52*dbb2a604SEduardo Habkost 53*dbb2a604SEduardo Habkost QLIST_FOREACH_ENTRY(types, e) { 54*dbb2a604SEduardo Habkost QDict *d = qobject_to_qdict(qlist_entry_obj(e)); 55*dbb2a604SEduardo Habkost const char *ename = qdict_get_str(d, "name"); 56*dbb2a604SEduardo Habkost if (!strcmp(ename, name)) { 57*dbb2a604SEduardo Habkost return d; 58*dbb2a604SEduardo Habkost } 59*dbb2a604SEduardo Habkost } 60*dbb2a604SEduardo Habkost 61*dbb2a604SEduardo Habkost return NULL; 62*dbb2a604SEduardo Habkost } 63*dbb2a604SEduardo Habkost 641c6d75d5SEduardo Habkost static QList *device_type_list(bool abstract) 651c6d75d5SEduardo Habkost { 661c6d75d5SEduardo Habkost return qom_list_types("device", abstract); 671c6d75d5SEduardo Habkost } 681c6d75d5SEduardo Habkost 692d1abb85SMarkus Armbruster static void test_one_device(const char *type) 702d1abb85SMarkus Armbruster { 712d1abb85SMarkus Armbruster QDict *resp; 722d1abb85SMarkus Armbruster char *help, *qom_tree; 732d1abb85SMarkus Armbruster 742d1abb85SMarkus Armbruster resp = qmp("{'execute': 'device-list-properties'," 752d1abb85SMarkus Armbruster " 'arguments': {'typename': %s}}", 762d1abb85SMarkus Armbruster type); 772d1abb85SMarkus Armbruster QDECREF(resp); 782d1abb85SMarkus Armbruster 792d1abb85SMarkus Armbruster help = hmp("device_add \"%s,help\"", type); 802d1abb85SMarkus Armbruster g_free(help); 812d1abb85SMarkus Armbruster 822d1abb85SMarkus Armbruster /* 832d1abb85SMarkus Armbruster * Some devices leave dangling pointers in QOM behind. 842d1abb85SMarkus Armbruster * "info qom-tree" has a good chance at crashing then 852d1abb85SMarkus Armbruster */ 862d1abb85SMarkus Armbruster qom_tree = hmp("info qom-tree"); 872d1abb85SMarkus Armbruster g_free(qom_tree); 882d1abb85SMarkus Armbruster } 892d1abb85SMarkus Armbruster 902d1abb85SMarkus Armbruster static void test_device_intro_list(void) 912d1abb85SMarkus Armbruster { 922d1abb85SMarkus Armbruster QList *types; 932d1abb85SMarkus Armbruster char *help; 942d1abb85SMarkus Armbruster 952d1abb85SMarkus Armbruster qtest_start(common_args); 962d1abb85SMarkus Armbruster 972d1abb85SMarkus Armbruster types = device_type_list(true); 982d1abb85SMarkus Armbruster QDECREF(types); 992d1abb85SMarkus Armbruster 1002d1abb85SMarkus Armbruster help = hmp("device_add help"); 1012d1abb85SMarkus Armbruster g_free(help); 1022d1abb85SMarkus Armbruster 1032d1abb85SMarkus Armbruster qtest_end(); 1042d1abb85SMarkus Armbruster } 1052d1abb85SMarkus Armbruster 1062d1abb85SMarkus Armbruster static void test_device_intro_none(void) 1072d1abb85SMarkus Armbruster { 1082d1abb85SMarkus Armbruster qtest_start(common_args); 1092d1abb85SMarkus Armbruster test_one_device("nonexistent"); 1102d1abb85SMarkus Armbruster qtest_end(); 1112d1abb85SMarkus Armbruster } 1122d1abb85SMarkus Armbruster 1132d1abb85SMarkus Armbruster static void test_device_intro_abstract(void) 1142d1abb85SMarkus Armbruster { 1152d1abb85SMarkus Armbruster qtest_start(common_args); 1162d1abb85SMarkus Armbruster test_one_device("device"); 1172d1abb85SMarkus Armbruster qtest_end(); 1182d1abb85SMarkus Armbruster } 1192d1abb85SMarkus Armbruster 1202d1abb85SMarkus Armbruster static void test_device_intro_concrete(void) 1212d1abb85SMarkus Armbruster { 1222d1abb85SMarkus Armbruster QList *types; 1232d1abb85SMarkus Armbruster QListEntry *entry; 1242d1abb85SMarkus Armbruster const char *type; 1252d1abb85SMarkus Armbruster 1262d1abb85SMarkus Armbruster qtest_start(common_args); 1272d1abb85SMarkus Armbruster types = device_type_list(false); 1282d1abb85SMarkus Armbruster 1292d1abb85SMarkus Armbruster QLIST_FOREACH_ENTRY(types, entry) { 1302d1abb85SMarkus Armbruster type = qdict_get_try_str(qobject_to_qdict(qlist_entry_obj(entry)), 1312d1abb85SMarkus Armbruster "name"); 1322d1abb85SMarkus Armbruster g_assert(type); 1332d1abb85SMarkus Armbruster test_one_device(type); 1342d1abb85SMarkus Armbruster } 1352d1abb85SMarkus Armbruster 1362d1abb85SMarkus Armbruster QDECREF(types); 1372d1abb85SMarkus Armbruster qtest_end(); 1382d1abb85SMarkus Armbruster } 1392d1abb85SMarkus Armbruster 1401c6d75d5SEduardo Habkost static void test_abstract_interfaces(void) 1411c6d75d5SEduardo Habkost { 1421c6d75d5SEduardo Habkost QList *all_types; 1431c6d75d5SEduardo Habkost QList *obj_types; 144*dbb2a604SEduardo Habkost QListEntry *e; 1451c6d75d5SEduardo Habkost 1461c6d75d5SEduardo Habkost qtest_start(common_args); 1471c6d75d5SEduardo Habkost /* qom-list-types implements=interface would return any type 1481c6d75d5SEduardo Habkost * that implements _any_ interface (not just interface types), 1491c6d75d5SEduardo Habkost * so use a trick to find the interface type names: 1501c6d75d5SEduardo Habkost * - list all object types 1511c6d75d5SEduardo Habkost * - list all types, and look for items that are not 1521c6d75d5SEduardo Habkost * on the first list 1531c6d75d5SEduardo Habkost */ 1541c6d75d5SEduardo Habkost all_types = qom_list_types(NULL, false); 1551c6d75d5SEduardo Habkost obj_types = qom_list_types("object", false); 1561c6d75d5SEduardo Habkost 157*dbb2a604SEduardo Habkost QLIST_FOREACH_ENTRY(all_types, e) { 158*dbb2a604SEduardo Habkost QDict *d = qobject_to_qdict(qlist_entry_obj(e)); 1591c6d75d5SEduardo Habkost 160*dbb2a604SEduardo Habkost /* 161*dbb2a604SEduardo Habkost * An interface (incorrectly) marked as non-abstract would 162*dbb2a604SEduardo Habkost * appear on all_types, but not on obj_types: 163*dbb2a604SEduardo Habkost */ 164*dbb2a604SEduardo Habkost g_assert(type_list_find(obj_types, qdict_get_str(d, "name"))); 1651c6d75d5SEduardo Habkost 1661c6d75d5SEduardo Habkost } 1671c6d75d5SEduardo Habkost 1681c6d75d5SEduardo Habkost QDECREF(all_types); 1691c6d75d5SEduardo Habkost QDECREF(obj_types); 1701c6d75d5SEduardo Habkost qtest_end(); 1711c6d75d5SEduardo Habkost } 1721c6d75d5SEduardo Habkost 1732d1abb85SMarkus Armbruster int main(int argc, char **argv) 1742d1abb85SMarkus Armbruster { 1752d1abb85SMarkus Armbruster g_test_init(&argc, &argv, NULL); 1762d1abb85SMarkus Armbruster 1772d1abb85SMarkus Armbruster qtest_add_func("device/introspect/list", test_device_intro_list); 1782d1abb85SMarkus Armbruster qtest_add_func("device/introspect/none", test_device_intro_none); 1792d1abb85SMarkus Armbruster qtest_add_func("device/introspect/abstract", test_device_intro_abstract); 1802d1abb85SMarkus Armbruster qtest_add_func("device/introspect/concrete", test_device_intro_concrete); 1811c6d75d5SEduardo Habkost qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces); 1822d1abb85SMarkus Armbruster 1832d1abb85SMarkus Armbruster return g_test_run(); 1842d1abb85SMarkus Armbruster } 185