@samitouri / QOSamiQemu / commits / 15619a10d0

tests/qtest/device-introspect-test: replace 'info qom-tree'

Replace "info qom-tree" with recursive qom-list walk. This substitutes a HMP-only command by a QOM command, allowing the test to run when !CONFIG_HMP later in this series. Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260828-qemu-no-hmp-v5-16-9227de146347@redhat.com>

Marc-André Lureau committed Aug 28, 2026 at 16:04 UTC 15619a10d0fb49989fcd806faf54434d44b1eb5d
1 file changed +58 -7
tests/qtest/device-introspect-test.c
+58 -7
@@ -100,6 +100,57 @@ static QList *device_type_list(QTestState *qts, bool abstract)
100 return qom_list_types(qts, "device", abstract);
101 }
102
103 +/*
104 + * Recursively walk the QOM composition tree via qom-list and build a
105 + * string representation. This serves two purposes: detecting dangling
106 + * pointers (qom-list would crash QEMU) and detecting leaked objects
107 + * (by comparing the output before and after device introspection).
108 + */
109 +static void qom_tree_walk(QTestState *qts, const char *path, GString *result)
110 +{
111 + QDict *resp;
112 + QList *list;
113 + QListEntry *e;
114 + GList *children = NULL;
115 +
116 + resp = qtest_qmp(qts, "{'execute': 'qom-list',"
117 + " 'arguments': {'path': %s}}", path);
118 + g_assert(qdict_haskey(resp, "return"));
119 + list = qdict_get_qlist(resp, "return");
120 +
121 + QLIST_FOREACH_ENTRY(list, e) {
122 + QDict *prop = qobject_to(QDict, qlist_entry_obj(e));
123 + const char *type = qdict_get_str(prop, "type");
124 + if (g_str_has_prefix(type, "child<")) {
125 + const char *name = qdict_get_str(prop, "name");
126 + children = g_list_prepend(children, g_strdup(name));
127 + }
128 + }
129 +
130 + children = g_list_sort_with_data(children, (GCompareDataFunc)g_strcmp0,
131 + NULL);
132 +
133 + for (GList *l = children; l; l = l->next) {
134 + const char *name = l->data;
135 + g_autofree char *child_path = (!strcmp(path, "/"))
136 + ? g_strdup_printf("/%s", name)
137 + : g_strdup_printf("%s/%s", path, name);
138 +
139 + g_string_append_printf(result, "%s\n", child_path);
140 + qom_tree_walk(qts, child_path, result);
141 + }
142 +
143 + g_list_free_full(children, g_free);
144 + qobject_unref(resp);
145 +}
146 +
147 +static char *qom_tree_str(QTestState *qts)
148 +{
149 + GString *result = g_string_new("");
150 + qom_tree_walk(qts, "/", result);
151 + return g_string_free(result, FALSE);
152 +}
153 +
154 static void test_one_device(QTestState *qts, const char *type)
155 {
156 QDict *resp;
@@ -198,7 +249,7 @@ static void test_qom_list_fields(void)
249 static void test_device_intro_none(void)
250 {
251 QTestState *qts = qtest_init(common_args);
201 - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
252 + g_autofree char *qom_tree_start = qom_tree_str(qts);
253 g_autofree char *qom_tree_end = NULL;
254 g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
255 g_autofree char *qtree_end = NULL;
@@ -206,7 +257,7 @@ static void test_device_intro_none(void)
257 test_one_device(qts, "nonexistent");
258
259 /* Make sure that really nothing changed in the trees */
209 - qom_tree_end = qtest_hmp(qts, "info qom-tree");
260 + qom_tree_end = qom_tree_str(qts);
261 g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
262 qtree_end = qtest_hmp(qts, "info qtree");
263 g_assert_cmpstr(qtree_start, ==, qtree_end);
@@ -217,7 +268,7 @@ static void test_device_intro_none(void)
268 static void test_device_intro_abstract(void)
269 {
270 QTestState *qts = qtest_init(common_args);
220 - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
271 + g_autofree char *qom_tree_start = qom_tree_str(qts);
272 g_autofree char *qom_tree_end = NULL;
273 g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
274 g_autofree char *qtree_end = NULL;
@@ -225,7 +276,7 @@ static void test_device_intro_abstract(void)
276 test_one_device(qts, "device");
277
278 /* Make sure that really nothing changed in the trees */
228 - qom_tree_end = qtest_hmp(qts, "info qom-tree");
279 + qom_tree_end = qom_tree_str(qts);
280 g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
281 qtree_end = qtest_hmp(qts, "info qtree");
282 g_assert_cmpstr(qtree_start, ==, qtree_end);
@@ -239,7 +290,7 @@ static void test_device_intro_concrete(const void *args)
290 QListEntry *entry;
291 const char *type;
292 QTestState *qts = qtest_init(args);
242 - g_autofree char *qom_tree_start = qtest_hmp(qts, "info qom-tree");
293 + g_autofree char *qom_tree_start = qom_tree_str(qts);
294 g_autofree char *qom_tree_end = NULL;
295 g_autofree char *qtree_start = qtest_hmp(qts, "info qtree");
296 g_autofree char *qtree_end = NULL;
@@ -255,10 +306,10 @@ static void test_device_intro_concrete(const void *args)
306
307 /*
308 * Some devices leave dangling pointers in QOM behind.
258 - * "info qom-tree" or "info qtree" have a good chance at crashing then.
309 + * Walking the QOM tree via qom-list has a good chance at crashing then.
310 * Also make sure that the tree did not change.
311 */
261 - qom_tree_end = qtest_hmp(qts, "info qom-tree");
312 + qom_tree_end = qom_tree_str(qts);
313 g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
314
315 qtree_end = qtest_hmp(qts, "info qtree");