qtest: add "qom-tests" command

Add a new "qom-tests" to exercise basic object lifecycle. Instantiate
all non-abstract objects, get and set properties and unref.

This should quickly find leaks and other related issues that are
eventually triggerable at run-time with QMP qom commands.

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau
2026-04-24 20:28:11 +04:00
parent 27c1ec4848
commit f741225073
4 changed files with 72 additions and 0 deletions

View File

@@ -31,6 +31,8 @@
#include "qemu/cutils.h"
#include "qemu/target-info.h"
#include "qom/object_interfaces.h"
#include "qom/qom-qobject.h"
#include "qobject/qobject.h"
#define MAX_IRQ 256
@@ -754,6 +756,50 @@ static void qtest_process_command(CharFrontend *chr, gchar **words)
new_ns = qemu_clock_advance_virtual_time(ns);
qtest_sendf(chr, "%s %"PRIi64"\n",
new_ns == ns ? "OK" : "FAIL", new_ns);
} else if (strcmp(words[0], "qom-tests") == 0) {
GSList *list, *l;
list = object_class_get_list(NULL, false);
for (l = list; l; l = l->next) {
ObjectClass *klass = l->data;
const char *type_name = object_class_get_name(klass);
Object *obj;
ObjectPropertyIterator iter;
ObjectProperty *prop;
obj = object_new_with_class(klass);
object_property_iter_init(&iter, obj);
while ((prop = object_property_iter_next(&iter))) {
QObject *value;
Error *local_err = NULL;
value = object_property_get_qobject(obj, prop->name,
&local_err);
if (local_err) {
error_report("qom-tests: %s.%s: get failed: %s",
type_name, prop->name,
error_get_pretty(local_err));
error_free(local_err);
continue;
}
if (prop->set) {
if (!object_property_set_qobject(obj, prop->name, value,
&local_err)) {
error_report("qom-tests: %s.%s: set failed: %s",
type_name, prop->name,
error_get_pretty(local_err));
error_free(local_err);
}
}
qobject_unref(value);
}
object_unref(obj);
}
g_slist_free(list);
qtest_send(chr, "OK\n");
} else if (process_command_cb && process_command_cb(chr, words)) {
/* Command got consumed by the callback handler */
} else {

View File

@@ -1137,6 +1137,12 @@ void qtest_module_load(QTestState *s, const char *prefix, const char *libname)
qtest_rsp(s);
}
void qtest_qom_tests(QTestState *s)
{
qtest_sendf(s, "qom-tests\n");
qtest_rsp(s);
}
static int64_t qtest_clock_rsp(QTestState *s)
{
gchar **words;

View File

@@ -426,6 +426,14 @@ char *qtest_vhmp(QTestState *s, const char *fmt, va_list ap)
void qtest_module_load(QTestState *s, const char *prefix, const char *libname);
/**
* qtest_qom_tests:
* @s: #QTestState instance to operate on.
*
* Run QOM property get/set round-trip tests on all non-abstract types.
*/
void qtest_qom_tests(QTestState *s);
/**
* qtest_get_irq:
* @s: #QTestState instance to operate on.

View File

@@ -227,6 +227,17 @@ static void add_machine_test_case(const char *mname)
g_free(path);
}
static void test_qom_qtests(void)
{
QTestState *qts;
qts = qtest_initf("-machine none");
qtest_qom_tests(qts);
qtest_quit(qts);
}
int main(int argc, char **argv)
{
char *v_env = getenv("V");
@@ -238,6 +249,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
qtest_add_func("qom/qom-qtests", test_qom_qtests);
return g_test_run();
}