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. Signed-off-by: Marc-André Lureau <[email protected]> --- tests/qtest/libqtest.h | 8 ++++++++ system/qtest.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ tests/qtest/libqtest.c | 6 ++++++ tests/qtest/qom-test.c | 12 ++++++++++++ 4 files changed, 72 insertions(+) diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h index 950ea2baafa..45217fb8dc0 100644 --- a/tests/qtest/libqtest.h +++ b/tests/qtest/libqtest.h @@ -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. diff --git a/system/qtest.c b/system/qtest.c index a79d10d1361..a44a581a518 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -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 { diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index b1e06ea364e..4e22c66b754 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -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; diff --git a/tests/qtest/qom-test.c b/tests/qtest/qom-test.c index 6421f2d9d9f..cf4c6b5add5 100644 --- a/tests/qtest/qom-test.c +++ b/tests/qtest/qom-test.c @@ -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(); } -- 2.54.0
