1f6a5f380SDaniel P. Berrangé /* 2f6a5f380SDaniel P. Berrangé * Validate -readconfig 3f6a5f380SDaniel P. Berrangé * 4f6a5f380SDaniel P. Berrangé * Copyright (c) 2022 Red Hat, Inc. 5f6a5f380SDaniel P. Berrangé * 6f6a5f380SDaniel P. Berrangé * This work is licensed under the terms of the GNU GPL, version 2 or later. 7f6a5f380SDaniel P. Berrangé * See the COPYING file in the top-level directory. 8f6a5f380SDaniel P. Berrangé */ 9f6a5f380SDaniel P. Berrangé 10f6a5f380SDaniel P. Berrangé #include "qemu/osdep.h" 11f6a5f380SDaniel P. Berrangé #include "libqtest.h" 12f6a5f380SDaniel P. Berrangé #include "qapi/error.h" 13f6a5f380SDaniel P. Berrangé #include "qapi/qapi-visit-machine.h" 14f6a5f380SDaniel P. Berrangé #include "qapi/qapi-visit-qom.h" 15f6a5f380SDaniel P. Berrangé #include "qapi/qapi-visit-ui.h" 16f6a5f380SDaniel P. Berrangé #include "qapi/qmp/qdict.h" 17f6a5f380SDaniel P. Berrangé #include "qapi/qmp/qlist.h" 18f6a5f380SDaniel P. Berrangé #include "qapi/qobject-input-visitor.h" 19f6a5f380SDaniel P. Berrangé #include "qapi/qmp/qstring.h" 20f6a5f380SDaniel P. Berrangé #include "qemu/units.h" 21f6a5f380SDaniel P. Berrangé 22f6a5f380SDaniel P. Berrangé static QTestState *qtest_init_with_config(const char *cfgdata) 23f6a5f380SDaniel P. Berrangé { 24f6a5f380SDaniel P. Berrangé GError *error = NULL; 25f6a5f380SDaniel P. Berrangé g_autofree char *args = NULL; 26f6a5f380SDaniel P. Berrangé int cfgfd = -1; 27f6a5f380SDaniel P. Berrangé g_autofree char *cfgpath = NULL; 28f6a5f380SDaniel P. Berrangé QTestState *qts; 29f6a5f380SDaniel P. Berrangé ssize_t ret; 30f6a5f380SDaniel P. Berrangé 31f6a5f380SDaniel P. Berrangé cfgfd = g_file_open_tmp("readconfig-test-XXXXXX", &cfgpath, &error); 32f6a5f380SDaniel P. Berrangé g_assert_no_error(error); 33f6a5f380SDaniel P. Berrangé g_assert_cmpint(cfgfd, >=, 0); 34f6a5f380SDaniel P. Berrangé 35f6a5f380SDaniel P. Berrangé ret = qemu_write_full(cfgfd, cfgdata, strlen(cfgdata)); 369c23d719SDaniel P. Berrangé close(cfgfd); 37f6a5f380SDaniel P. Berrangé if (ret < 0) { 38f6a5f380SDaniel P. Berrangé unlink(cfgpath); 39f6a5f380SDaniel P. Berrangé } 40f6a5f380SDaniel P. Berrangé g_assert_cmpint(ret, ==, strlen(cfgdata)); 41f6a5f380SDaniel P. Berrangé 42f6a5f380SDaniel P. Berrangé args = g_strdup_printf("-nodefaults -machine none -readconfig %s", cfgpath); 43f6a5f380SDaniel P. Berrangé 44f6a5f380SDaniel P. Berrangé qts = qtest_init(args); 45f6a5f380SDaniel P. Berrangé 46f6a5f380SDaniel P. Berrangé unlink(cfgpath); 47f6a5f380SDaniel P. Berrangé 48f6a5f380SDaniel P. Berrangé return qts; 49f6a5f380SDaniel P. Berrangé } 50f6a5f380SDaniel P. Berrangé 51*5a7d4dc9SThomas Huth static void test_x86_memdev_resp(QObject *res, const char *mem_id, int size) 52f6a5f380SDaniel P. Berrangé { 53f6a5f380SDaniel P. Berrangé Visitor *v; 54f6a5f380SDaniel P. Berrangé g_autoptr(MemdevList) memdevs = NULL; 55f6a5f380SDaniel P. Berrangé Memdev *memdev; 56f6a5f380SDaniel P. Berrangé 57f6a5f380SDaniel P. Berrangé g_assert(res); 58f6a5f380SDaniel P. Berrangé v = qobject_input_visitor_new(res); 59f6a5f380SDaniel P. Berrangé visit_type_MemdevList(v, NULL, &memdevs, &error_abort); 60f6a5f380SDaniel P. Berrangé 61f6a5f380SDaniel P. Berrangé g_assert(memdevs); 62f6a5f380SDaniel P. Berrangé g_assert(memdevs->value); 63f6a5f380SDaniel P. Berrangé g_assert(!memdevs->next); 64f6a5f380SDaniel P. Berrangé 65f6a5f380SDaniel P. Berrangé memdev = memdevs->value; 66*5a7d4dc9SThomas Huth g_assert_cmpstr(memdev->id, ==, mem_id); 67*5a7d4dc9SThomas Huth g_assert_cmpint(memdev->size, ==, size * MiB); 68f6a5f380SDaniel P. Berrangé 69f6a5f380SDaniel P. Berrangé visit_free(v); 70f6a5f380SDaniel P. Berrangé } 71f6a5f380SDaniel P. Berrangé 72f6a5f380SDaniel P. Berrangé static void test_x86_memdev(void) 73f6a5f380SDaniel P. Berrangé { 74f6a5f380SDaniel P. Berrangé QDict *resp; 75f6a5f380SDaniel P. Berrangé QTestState *qts; 76f6a5f380SDaniel P. Berrangé const char *cfgdata = 77f6a5f380SDaniel P. Berrangé "[memory]\n" 78f6a5f380SDaniel P. Berrangé "size = \"200\""; 79f6a5f380SDaniel P. Berrangé 80f6a5f380SDaniel P. Berrangé qts = qtest_init_with_config(cfgdata); 81f6a5f380SDaniel P. Berrangé /* Test valid command */ 82f6a5f380SDaniel P. Berrangé resp = qtest_qmp(qts, "{ 'execute': 'query-memdev' }"); 83*5a7d4dc9SThomas Huth test_x86_memdev_resp(qdict_get(resp, "return"), "ram", 200); 84f6a5f380SDaniel P. Berrangé qobject_unref(resp); 85f6a5f380SDaniel P. Berrangé 86f6a5f380SDaniel P. Berrangé qtest_quit(qts); 87f6a5f380SDaniel P. Berrangé } 88f6a5f380SDaniel P. Berrangé 8901013d2cSThomas Huth /* FIXME: The test is currently broken on FreeBSD */ 9001013d2cSThomas Huth #if defined(CONFIG_SPICE) && !defined(__FreeBSD__) 91f6a5f380SDaniel P. Berrangé static void test_spice_resp(QObject *res) 92f6a5f380SDaniel P. Berrangé { 93f6a5f380SDaniel P. Berrangé Visitor *v; 94f6a5f380SDaniel P. Berrangé g_autoptr(SpiceInfo) spice = NULL; 95f6a5f380SDaniel P. Berrangé 96f6a5f380SDaniel P. Berrangé g_assert(res); 97f6a5f380SDaniel P. Berrangé v = qobject_input_visitor_new(res); 989c23d719SDaniel P. Berrangé visit_type_SpiceInfo(v, "spice", &spice, &error_abort); 99f6a5f380SDaniel P. Berrangé 100f6a5f380SDaniel P. Berrangé g_assert(spice); 101f6a5f380SDaniel P. Berrangé g_assert(spice->enabled); 102f6a5f380SDaniel P. Berrangé 103f6a5f380SDaniel P. Berrangé visit_free(v); 104f6a5f380SDaniel P. Berrangé } 105f6a5f380SDaniel P. Berrangé 106f6a5f380SDaniel P. Berrangé static void test_spice(void) 107f6a5f380SDaniel P. Berrangé { 108f6a5f380SDaniel P. Berrangé QDict *resp; 109f6a5f380SDaniel P. Berrangé QTestState *qts; 110f6a5f380SDaniel P. Berrangé const char *cfgdata = 111f6a5f380SDaniel P. Berrangé "[spice]\n" 112beecc4b7SMarc-André Lureau #ifndef WIN32 113beecc4b7SMarc-André Lureau "unix = \"on\"\n" 114beecc4b7SMarc-André Lureau #endif 115beecc4b7SMarc-André Lureau "disable-ticketing = \"on\"\n"; 116f6a5f380SDaniel P. Berrangé 117f6a5f380SDaniel P. Berrangé qts = qtest_init_with_config(cfgdata); 118f6a5f380SDaniel P. Berrangé /* Test valid command */ 119f6a5f380SDaniel P. Berrangé resp = qtest_qmp(qts, "{ 'execute': 'query-spice' }"); 120f6a5f380SDaniel P. Berrangé test_spice_resp(qdict_get(resp, "return")); 121f6a5f380SDaniel P. Berrangé qobject_unref(resp); 122f6a5f380SDaniel P. Berrangé 123f6a5f380SDaniel P. Berrangé qtest_quit(qts); 124f6a5f380SDaniel P. Berrangé } 125f6a5f380SDaniel P. Berrangé #endif 126f6a5f380SDaniel P. Berrangé 12779571e7fSThomas Huth static void test_object_available(QObject *res, const char *name, 12879571e7fSThomas Huth const char *type) 129f6a5f380SDaniel P. Berrangé { 130f6a5f380SDaniel P. Berrangé Visitor *v; 131f6a5f380SDaniel P. Berrangé g_autoptr(ObjectPropertyInfoList) objs = NULL; 132f6a5f380SDaniel P. Berrangé ObjectPropertyInfoList *tmp; 133f6a5f380SDaniel P. Berrangé ObjectPropertyInfo *obj; 13479571e7fSThomas Huth bool object_available = false; 13579571e7fSThomas Huth g_autofree char *childtype = g_strdup_printf("child<%s>", type); 136f6a5f380SDaniel P. Berrangé 137f6a5f380SDaniel P. Berrangé g_assert(res); 138f6a5f380SDaniel P. Berrangé v = qobject_input_visitor_new(res); 139f6a5f380SDaniel P. Berrangé visit_type_ObjectPropertyInfoList(v, NULL, &objs, &error_abort); 140f6a5f380SDaniel P. Berrangé 141f6a5f380SDaniel P. Berrangé g_assert(objs); 142f6a5f380SDaniel P. Berrangé tmp = objs; 143f6a5f380SDaniel P. Berrangé while (tmp) { 144f6a5f380SDaniel P. Berrangé g_assert(tmp->value); 145f6a5f380SDaniel P. Berrangé 146f6a5f380SDaniel P. Berrangé obj = tmp->value; 14779571e7fSThomas Huth if (g_str_equal(obj->name, name) && g_str_equal(obj->type, childtype)) { 14879571e7fSThomas Huth object_available = true; 1499c23d719SDaniel P. Berrangé break; 150f6a5f380SDaniel P. Berrangé } 151f6a5f380SDaniel P. Berrangé 152f6a5f380SDaniel P. Berrangé tmp = tmp->next; 153f6a5f380SDaniel P. Berrangé } 154f6a5f380SDaniel P. Berrangé 15579571e7fSThomas Huth g_assert(object_available); 156f6a5f380SDaniel P. Berrangé 157f6a5f380SDaniel P. Berrangé visit_free(v); 158f6a5f380SDaniel P. Berrangé } 159f6a5f380SDaniel P. Berrangé 160f6a5f380SDaniel P. Berrangé static void test_object_rng(void) 161f6a5f380SDaniel P. Berrangé { 162f6a5f380SDaniel P. Berrangé QDict *resp; 163f6a5f380SDaniel P. Berrangé QTestState *qts; 164f6a5f380SDaniel P. Berrangé const char *cfgdata = 165f6a5f380SDaniel P. Berrangé "[object]\n" 166f6a5f380SDaniel P. Berrangé "qom-type = \"rng-builtin\"\n" 167f6a5f380SDaniel P. Berrangé "id = \"rng0\"\n"; 168f6a5f380SDaniel P. Berrangé 169f6a5f380SDaniel P. Berrangé qts = qtest_init_with_config(cfgdata); 170f6a5f380SDaniel P. Berrangé /* Test valid command */ 171f6a5f380SDaniel P. Berrangé resp = qtest_qmp(qts, 172f6a5f380SDaniel P. Berrangé "{ 'execute': 'qom-list'," 173f6a5f380SDaniel P. Berrangé " 'arguments': {'path': '/objects' }}"); 17479571e7fSThomas Huth test_object_available(qdict_get(resp, "return"), "rng0", "rng-builtin"); 175f6a5f380SDaniel P. Berrangé qobject_unref(resp); 176f6a5f380SDaniel P. Berrangé 177f6a5f380SDaniel P. Berrangé qtest_quit(qts); 178f6a5f380SDaniel P. Berrangé } 179f6a5f380SDaniel P. Berrangé 180201aa17eSThomas Huth static void test_docs_config_ich9(void) 181201aa17eSThomas Huth { 182201aa17eSThomas Huth QTestState *qts; 183201aa17eSThomas Huth QDict *resp; 184201aa17eSThomas Huth QObject *qobj; 185201aa17eSThomas Huth 186201aa17eSThomas Huth qts = qtest_initf("-nodefaults -readconfig docs/config/ich9-ehci-uhci.cfg"); 187201aa17eSThomas Huth 188201aa17eSThomas Huth resp = qtest_qmp(qts, "{ 'execute': 'qom-list'," 189201aa17eSThomas Huth " 'arguments': {'path': '/machine/peripheral' }}"); 190201aa17eSThomas Huth qobj = qdict_get(resp, "return"); 191201aa17eSThomas Huth test_object_available(qobj, "ehci", "ich9-usb-ehci1"); 192201aa17eSThomas Huth test_object_available(qobj, "uhci-1", "ich9-usb-uhci1"); 193201aa17eSThomas Huth test_object_available(qobj, "uhci-2", "ich9-usb-uhci2"); 194201aa17eSThomas Huth test_object_available(qobj, "uhci-3", "ich9-usb-uhci3"); 195201aa17eSThomas Huth qobject_unref(resp); 196201aa17eSThomas Huth 197201aa17eSThomas Huth qtest_quit(qts); 198201aa17eSThomas Huth } 199201aa17eSThomas Huth 200f6a5f380SDaniel P. Berrangé int main(int argc, char *argv[]) 201f6a5f380SDaniel P. Berrangé { 202f6a5f380SDaniel P. Berrangé const char *arch; 203f6a5f380SDaniel P. Berrangé g_test_init(&argc, &argv, NULL); 204f6a5f380SDaniel P. Berrangé 205f6a5f380SDaniel P. Berrangé arch = qtest_get_arch(); 206f6a5f380SDaniel P. Berrangé 207f6a5f380SDaniel P. Berrangé if (g_str_equal(arch, "i386") || 208f6a5f380SDaniel P. Berrangé g_str_equal(arch, "x86_64")) { 209f6a5f380SDaniel P. Berrangé qtest_add_func("readconfig/x86/memdev", test_x86_memdev); 210335da811SThomas Huth if (qtest_has_device("ich9-usb-ehci1") && 211335da811SThomas Huth qtest_has_device("ich9-usb-uhci1")) { 212201aa17eSThomas Huth qtest_add_func("readconfig/x86/ich9-ehci-uhci", test_docs_config_ich9); 213f6a5f380SDaniel P. Berrangé } 214335da811SThomas Huth } 21501013d2cSThomas Huth #if defined(CONFIG_SPICE) && !defined(__FreeBSD__) 216f6a5f380SDaniel P. Berrangé qtest_add_func("readconfig/spice", test_spice); 217f6a5f380SDaniel P. Berrangé #endif 218f6a5f380SDaniel P. Berrangé 219f6a5f380SDaniel P. Berrangé qtest_add_func("readconfig/object-rng", test_object_rng); 220f6a5f380SDaniel P. Berrangé 221f6a5f380SDaniel P. Berrangé return g_test_run(); 222f6a5f380SDaniel P. Berrangé } 223