Replace "info qom-tree" with recursive qom-list walk.
Disable HMP-only code paths, info qtree, kinda duplicating the test.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/qtest/device-introspect-test.c | 111 +++++++++++++++++++++++++++--------
1 file changed, 88 insertions(+), 23 deletions(-)
diff --git a/tests/qtest/device-introspect-test.c b/tests/qtest/device-introspect-test.c
index f84cec51dc2..f6eca2c8eb7 100644
--- a/tests/qtest/device-introspect-test.c
+++ b/tests/qtest/device-introspect-test.c
@@ -11,10 +11,10 @@
*/
/*
- * Covers QMP device-list-properties and HMP device_add help. We
- * currently don't check that their output makes sense, only that QEMU
- * survives. Useful since we've had an astounding number of crash
- * bugs around here.
+ * Covers QMP device-list-properties and HMP device_add help (if
+ * CONFIG_HMP). We currently don't check that the output makes sense,
+ * only that QEMU survives. Useful since we've had an astounding
+ * number of crash bugs around here.
*/
#include "qemu/osdep.h"
@@ -100,11 +100,60 @@ static QList *device_type_list(QTestState *qts, bool abstract)
return qom_list_types(qts, "device", abstract);
}
+/*
+ * Recursively walk the QOM composition tree via qom-list and build a
+ * string representation. This serves two purposes: detecting dangling
+ * pointers (qom-list would crash QEMU) and detecting leaked objects
+ * (by comparing the output before and after device introspection).
+ */
+static void qom_tree_walk(QTestState *qts, const char *path, GString *result)
+{
+ QDict *resp;
+ QList *list;
+ QListEntry *e;
+ GList *children = NULL;
+
+ resp = qtest_qmp(qts, "{'execute': 'qom-list',"
+ " 'arguments': {'path': %s}}", path);
+ g_assert(qdict_haskey(resp, "return"));
+ list = qdict_get_qlist(resp, "return");
+
+ QLIST_FOREACH_ENTRY(list, e) {
+ QDict *prop = qobject_to(QDict, qlist_entry_obj(e));
+ const char *type = qdict_get_str(prop, "type");
+ if (g_str_has_prefix(type, "child<")) {
+ const char *name = qdict_get_str(prop, "name");
+ children = g_list_prepend(children, g_strdup(name));
+ }
+ }
+
+ children = g_list_sort_with_data(children, (GCompareDataFunc)g_strcmp0,
+ NULL);
+
+ for (GList *l = children; l; l = l->next) {
+ const char *name = l->data;
+ g_autofree char *child_path = (!strcmp(path, "/"))
+ ? g_strdup_printf("/%s", name)
+ : g_strdup_printf("%s/%s", path, name);
+
+ g_string_append_printf(result, "%s\n", child_path);
+ qom_tree_walk(qts, child_path, result);
+ }
+
+ g_list_free_full(children, g_free);
+ qobject_unref(resp);
+}
+
+static char *qom_tree_str(QTestState *qts)
+{
+ GString *result = g_string_new("");
+ qom_tree_walk(qts, "/", result);
+ return g_string_free(result, FALSE);
+}
+
static void test_one_device(QTestState *qts, const char *type)
{
QDict *resp;
- char *help, *escaped;
- GRegex *comma;
g_test_message("Testing device '%s'", type);
@@ -113,19 +162,21 @@ static void test_one_device(QTestState *qts, const char *type)
type);
qobject_unref(resp);
- comma = g_regex_new(",", 0, 0, NULL);
- escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL);
- g_regex_unref(comma);
+#ifdef CONFIG_HMP
+ {
+ g_autofree char *escaped = NULL;
+ g_autoptr(GRegex) comma = NULL;
- help = qtest_hmp(qts, "device_add \"%s,help\"", escaped);
- g_free(help);
- g_free(escaped);
+ comma = g_regex_new(",", 0, 0, NULL);
+ escaped = g_regex_replace_literal(comma, type, -1, 0, ",,", 0, NULL);
+ g_free(qtest_hmp(qts, "device_add \"%s,help\"", escaped));
+ }
+#endif
}
static void test_device_intro_list(void)
{
QList *types;
- char *help;
QTestState *qts;
qts = qtest_init(common_args);
@@ -133,8 +184,11 @@ static void test_device_intro_list(void)
types = device_type_list(qts, true);
qobject_unref(types);
- help = qtest_hmp(qts, "device_add help");
- g_free(help);
+#ifdef CONFIG_HMP
+ {
+ g_free(qtest_hmp(qts, "device_add help"));
+ }
+#endif
qtest_quit(qts);
}
@@ -198,18 +252,22 @@ static void test_qom_list_fields(void)
static void test_device_intro_none(void)
{
QTestState *qts = qtest_init(common_args);
- g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
+ g_autofree char *qom_tree_start = qom_tree_str(qts);
g_autofree char *qom_tree_end = NULL;
+#ifdef CONFIG_HMP
g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
g_autofree char *qtree_end = NULL;
+#endif
test_one_device(qts, "nonexistent");
/* Make sure that really nothing changed in the trees */
- qom_tree_end = qtest_hmp(qts, "info qom-tree");
+ qom_tree_end = qom_tree_str(qts);
g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
+#ifdef CONFIG_HMP
qtree_end = qtest_hmp(qts, "info qtree");
g_assert_cmpstr(qtree_start, ==, qtree_end);
+#endif
qtest_quit(qts);
}
@@ -217,18 +275,22 @@ static void test_device_intro_none(void)
static void test_device_intro_abstract(void)
{
QTestState *qts = qtest_init(common_args);
- g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
+ g_autofree char *qom_tree_start = qom_tree_str(qts);
g_autofree char *qom_tree_end = NULL;
+#ifdef CONFIG_HMP
g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
g_autofree char *qtree_end = NULL;
+#endif
test_one_device(qts, "device");
/* Make sure that really nothing changed in the trees */
- qom_tree_end = qtest_hmp(qts, "info qom-tree");
+ qom_tree_end = qom_tree_str(qts);
g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
+#ifdef CONFIG_HMP
qtree_end = qtest_hmp(qts, "info qtree");
g_assert_cmpstr(qtree_start, ==, qtree_end);
+#endif
qtest_quit(qts);
}
@@ -239,10 +301,12 @@ static void test_device_intro_concrete(const void *args)
QListEntry *entry;
const char *type;
QTestState *qts = qtest_init(args);
- g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
+ g_autofree char *qom_tree_start = qom_tree_str(qts);
g_autofree char *qom_tree_end = NULL;
+#ifdef CONFIG_HMP
g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
g_autofree char *qtree_end = NULL;
+#endif
types = device_type_list(qts, false);
@@ -255,14 +319,15 @@ static void test_device_intro_concrete(const void *args)
/*
* Some devices leave dangling pointers in QOM behind.
- * "info qom-tree" or "info qtree" have a good chance at crashing then.
+ * Walking the QOM tree via qom-list has a good chance at crashing then.
* Also make sure that the tree did not change.
*/
- qom_tree_end = qtest_hmp(qts, "info qom-tree");
+ qom_tree_end = qom_tree_str(qts);
g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
-
+#ifdef CONFIG_HMP
qtree_end = qtest_hmp(qts, "info qtree");
g_assert_cmpstr(qtree_start, ==, qtree_end);
+#endif
qobject_unref(types);
qtest_quit(qts);
--
2.54.0