xref: /qemu/tests/qtest/device-introspect-test.c (revision dbb2a604a94f3899fa34bd1ede462f213e822e03)
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