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");