4 * Copyright (c) 2022 Red Hat, Inc.
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
10 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "qapi/qapi-visit-machine.h"
14 #include "qapi/qapi-visit-qom.h"
15 #include "qapi/qapi-visit-ui.h"
16 #include "qapi/qmp/qdict.h"
17 #include "qapi/qmp/qlist.h"
18 #include "qapi/qobject-input-visitor.h"
19 #include "qapi/qmp/qstring.h"
20 #include "qemu/units.h"
22 static QTestState
*qtest_init_with_config(const char *cfgdata
)
25 g_autofree
char *args
= NULL
;
27 g_autofree
char *cfgpath
= NULL
;
31 cfgfd
= g_file_open_tmp("readconfig-test-XXXXXX", &cfgpath
, &error
);
32 g_assert_no_error(error
);
33 g_assert_cmpint(cfgfd
, >=, 0);
35 ret
= qemu_write_full(cfgfd
, cfgdata
, strlen(cfgdata
));
40 g_assert_cmpint(ret
, ==, strlen(cfgdata
));
42 args
= g_strdup_printf("-nodefaults -machine none -readconfig %s", cfgpath
);
44 qts
= qtest_init(args
);
51 static void test_x86_memdev_resp(QObject
*res
, const char *mem_id
, int size
)
54 g_autoptr(MemdevList
) memdevs
= NULL
;
58 v
= qobject_input_visitor_new(res
);
59 visit_type_MemdevList(v
, NULL
, &memdevs
, &error_abort
);
62 g_assert(memdevs
->value
);
63 g_assert(!memdevs
->next
);
65 memdev
= memdevs
->value
;
66 g_assert_cmpstr(memdev
->id
, ==, mem_id
);
67 g_assert_cmpint(memdev
->size
, ==, size
* MiB
);
72 static void test_x86_memdev(void)
80 qts
= qtest_init_with_config(cfgdata
);
81 /* Test valid command */
82 resp
= qtest_qmp(qts
, "{ 'execute': 'query-memdev' }");
83 test_x86_memdev_resp(qdict_get(resp
, "return"), "ram", 200);
89 /* FIXME: The test is currently broken on FreeBSD */
90 #if defined(CONFIG_SPICE) && !defined(__FreeBSD__)
91 static void test_spice_resp(QObject
*res
)
94 g_autoptr(SpiceInfo
) spice
= NULL
;
97 v
= qobject_input_visitor_new(res
);
98 visit_type_SpiceInfo(v
, "spice", &spice
, &error_abort
);
101 g_assert(spice
->enabled
);
106 static void test_spice(void)
110 const char *cfgdata
=
115 "disable-ticketing = \"on\"\n";
117 qts
= qtest_init_with_config(cfgdata
);
118 /* Test valid command */
119 resp
= qtest_qmp(qts
, "{ 'execute': 'query-spice' }");
120 test_spice_resp(qdict_get(resp
, "return"));
127 static void test_object_available(QObject
*res
, const char *name
,
131 g_autoptr(ObjectPropertyInfoList
) objs
= NULL
;
132 ObjectPropertyInfoList
*tmp
;
133 ObjectPropertyInfo
*obj
;
134 bool object_available
= false;
135 g_autofree
char *childtype
= g_strdup_printf("child<%s>", type
);
138 v
= qobject_input_visitor_new(res
);
139 visit_type_ObjectPropertyInfoList(v
, NULL
, &objs
, &error_abort
);
144 g_assert(tmp
->value
);
147 if (g_str_equal(obj
->name
, name
) && g_str_equal(obj
->type
, childtype
)) {
148 object_available
= true;
155 g_assert(object_available
);
160 static void test_object_rng(void)
164 const char *cfgdata
=
166 "qom-type = \"rng-builtin\"\n"
169 qts
= qtest_init_with_config(cfgdata
);
170 /* Test valid command */
171 resp
= qtest_qmp(qts
,
172 "{ 'execute': 'qom-list',"
173 " 'arguments': {'path': '/objects' }}");
174 test_object_available(qdict_get(resp
, "return"), "rng0", "rng-builtin");
180 static void test_docs_config_ich9(void)
186 qts
= qtest_initf("-nodefaults -readconfig docs/config/ich9-ehci-uhci.cfg");
188 resp
= qtest_qmp(qts
, "{ 'execute': 'qom-list',"
189 " 'arguments': {'path': '/machine/peripheral' }}");
190 qobj
= qdict_get(resp
, "return");
191 test_object_available(qobj
, "ehci", "ich9-usb-ehci1");
192 test_object_available(qobj
, "uhci-1", "ich9-usb-uhci1");
193 test_object_available(qobj
, "uhci-2", "ich9-usb-uhci2");
194 test_object_available(qobj
, "uhci-3", "ich9-usb-uhci3");
200 #if defined(CONFIG_POSIX) && defined(CONFIG_SLIRP)
202 static char *make_temp_img(const char *template, const char *format
, int size
)
204 GError
*error
= NULL
;
208 /* Create a temporary image names */
209 fd
= g_file_open_tmp(template, &temp_name
, &error
);
211 fprintf(stderr
, "unable to create file: %s\n", error
->message
);
217 if (!mkimg(temp_name
, format
, size
)) {
218 fprintf(stderr
, "qemu-img failed to create %s\n", temp_name
);
231 static void test_docs_q35(const char *input_file
, struct device
*devices
)
237 g_autofree
char *cfg_file
= NULL
, *sedcmd
= NULL
;
238 g_autofree
char *hd_file
= NULL
, *cd_file
= NULL
;
240 /* Check that all the devices are available in the QEMU binary */
241 for (i
= 0; devices
[i
].name
; i
++) {
242 if (!qtest_has_device(devices
[i
].type
)) {
243 g_test_skip("one of the required devices is not available");
248 hd_file
= make_temp_img("qtest_disk_XXXXXX.qcow2", "qcow2", 1);
249 cd_file
= make_temp_img("qtest_cdrom_XXXXXX.iso", "raw", 1);
250 if (!hd_file
|| !cd_file
) {
251 g_test_skip("could not create disk images");
255 /* Create a temporary config file where we replace the disk image names */
256 ret
= g_file_open_tmp("q35-emulated-XXXXXX.cfg", &cfg_file
, NULL
);
258 g_test_skip("could not create temporary config file");
263 sedcmd
= g_strdup_printf("sed -e 's,guest.qcow2,%s,' -e 's,install.iso,%s,'"
266 !qtest_has_accel("kvm") ? "-e '/accel/d'" : "",
267 input_file
, cfg_file
);
268 ret
= system(sedcmd
);
270 g_test_skip("could not modify temporary config file");
274 qts
= qtest_initf("-machine none -nodefaults -readconfig %s", cfg_file
);
276 /* Check memory size */
277 resp
= qtest_qmp(qts
, "{ 'execute': 'query-memdev' }");
278 test_x86_memdev_resp(qdict_get(resp
, "return"), "pc.ram", 1024);
281 resp
= qtest_qmp(qts
, "{ 'execute': 'qom-list',"
282 " 'arguments': {'path': '/machine/peripheral' }}");
283 qobj
= qdict_get(resp
, "return");
285 /* Check that all the devices have been created */
286 for (i
= 0; devices
[i
].name
; i
++) {
287 test_object_available(qobj
, devices
[i
].name
, devices
[i
].type
);
306 static void test_docs_q35_emulated(void)
308 struct device devices
[] = {
309 { "ich9-pcie-port-1", "ioh3420" },
310 { "ich9-pcie-port-2", "ioh3420" },
311 { "ich9-pcie-port-3", "ioh3420" },
312 { "ich9-pcie-port-4", "ioh3420" },
313 { "ich9-pci-bridge", "i82801b11-bridge" },
314 { "ich9-ehci-1", "ich9-usb-ehci1" },
315 { "ich9-ehci-2", "ich9-usb-ehci2" },
316 { "ich9-uhci-1", "ich9-usb-uhci1" },
317 { "ich9-uhci-2", "ich9-usb-uhci2" },
318 { "ich9-uhci-3", "ich9-usb-uhci3" },
319 { "ich9-uhci-4", "ich9-usb-uhci4" },
320 { "ich9-uhci-5", "ich9-usb-uhci5" },
321 { "ich9-uhci-6", "ich9-usb-uhci6" },
322 { "sata-disk", "ide-hd" },
323 { "sata-optical-disk", "ide-cd" },
326 { "ich9-hda-audio", "ich9-intel-hda" },
327 { "ich9-hda-duplex", "hda-duplex" },
331 test_docs_q35("docs/config/q35-emulated.cfg", devices
);
334 static void test_docs_q35_virtio_graphical(void)
336 struct device devices
[] = {
337 { "pcie.1", "pcie-root-port" },
338 { "pcie.2", "pcie-root-port" },
339 { "pcie.3", "pcie-root-port" },
340 { "pcie.4", "pcie-root-port" },
341 { "pcie.5", "pcie-root-port" },
342 { "pcie.6", "pcie-root-port" },
343 { "pcie.7", "pcie-root-port" },
344 { "pcie.8", "pcie-root-port" },
345 { "scsi", "virtio-scsi-pci" },
346 { "scsi-disk", "scsi-hd" },
347 { "scsi-optical-disk", "scsi-cd" },
348 { "net", "virtio-net-pci" },
349 { "usb", "nec-usb-xhci" },
350 { "tablet", "usb-tablet" },
351 { "video", "qxl-vga" },
352 { "sound", "ich9-intel-hda" },
353 { "duplex", "hda-duplex" },
357 test_docs_q35("docs/config/q35-virtio-graphical.cfg", devices
);
360 static void test_docs_q35_virtio_serial(void)
362 struct device devices
[] = {
363 { "pcie.1", "pcie-root-port" },
364 { "pcie.2", "pcie-root-port" },
365 { "pcie.3", "pcie-root-port" },
366 { "pcie.4", "pcie-root-port" },
367 { "pcie.5", "pcie-root-port" },
368 { "pcie.6", "pcie-root-port" },
369 { "pcie.7", "pcie-root-port" },
370 { "pcie.8", "pcie-root-port" },
371 { "scsi", "virtio-scsi-pci" },
372 { "scsi-disk", "scsi-hd" },
373 { "scsi-optical-disk", "scsi-cd" },
374 { "net", "virtio-net-pci" },
378 test_docs_q35("docs/config/q35-virtio-serial.cfg", devices
);
381 #endif /* CONFIG_LINUX */
383 int main(int argc
, char *argv
[])
386 g_test_init(&argc
, &argv
, NULL
);
388 arch
= qtest_get_arch();
390 if (g_str_equal(arch
, "i386") ||
391 g_str_equal(arch
, "x86_64")) {
392 qtest_add_func("readconfig/x86/memdev", test_x86_memdev
);
393 if (qtest_has_device("ich9-usb-ehci1") &&
394 qtest_has_device("ich9-usb-uhci1")) {
395 qtest_add_func("readconfig/x86/ich9-ehci-uhci", test_docs_config_ich9
);
397 #if defined(CONFIG_POSIX) && defined(CONFIG_SLIRP)
398 qtest_add_func("readconfig/x86/q35-emulated", test_docs_q35_emulated
);
399 qtest_add_func("readconfig/x86/q35-virtio-graphical",
400 test_docs_q35_virtio_graphical
);
403 * q35-virtio-serial.cfg is a subset of q35-virtio-graphical.cfg,
404 * so we can skip the test in quick mode
406 qtest_add_func("readconfig/x86/q35-virtio-serial",
407 test_docs_q35_virtio_serial
);
411 #if defined(CONFIG_SPICE) && !defined(__FreeBSD__)
412 qtest_add_func("readconfig/spice", test_spice
);
415 qtest_add_func("readconfig/object-rng", test_object_rng
);