[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH RFC 1/1] qtest: Add generic PCI device test
From: |
Markus Armbruster |
Subject: |
[Qemu-devel] [PATCH RFC 1/1] qtest: Add generic PCI device test |
Date: |
Thu, 29 Jan 2015 15:58:40 +0100 |
Covers only cold plug with -device so far.
Signed-off-by: Markus Armbruster <address@hidden>
---
tests/Makefile | 2 +
tests/pci-devs-test.c | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 301 insertions(+)
create mode 100644 tests/pci-devs-test.c
diff --git a/tests/Makefile b/tests/Makefile
index c2e2e52..230238d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -100,6 +100,7 @@ gcov-files-virtio-y +=
i386-softmmu/hw/char/virtio-serial-bus.c
check-qtest-virtio-y += $(check-qtest-virtioserial-y)
gcov-files-virtio-y += $(gcov-files-virtioserial-y)
+check-qtest-pci-y += tests/pci-devs-test$(EXESUF)
check-qtest-pci-y += tests/e1000-test$(EXESUF)
gcov-files-pci-y += hw/net/e1000.c
check-qtest-pci-y += tests/rtl8139-test$(EXESUF)
@@ -319,6 +320,7 @@ tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o
$(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
+tests/pci-devs-test$(EXESUF): tests/pci-devs-test.o
tests/e1000-test$(EXESUF): tests/e1000-test.o
tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o
tests/pcnet-test$(EXESUF): tests/pcnet-test.o
diff --git a/tests/pci-devs-test.c b/tests/pci-devs-test.c
new file mode 100644
index 0000000..27cbeee
--- /dev/null
+++ b/tests/pci-devs-test.c
@@ -0,0 +1,299 @@
+/*
+ * Generic PCI device test cases.
+ *
+ * Copyright (c) 2015 Red Hat Inc.
+ *
+ * Authors:
+ * Markus Armbruster <address@hidden>,
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * Covers only cold plug with -device so far. Better than nothing.
+ * Improvements welcome.
+ */
+
+#include "qemu-common.h"
+#include "libqtest.h"
+#include "qapi/qmp/types.h"
+
+typedef struct Prop {
+ const char *name;
+ const char *value;
+} Prop;
+
+typedef struct {
+ Prop prop[16];
+ int nprop;
+ const char *xprops;
+ int nchr;
+ int nblk;
+} TestCase;
+
+static const char *blacklist[] = {
+ /* cannot_instantiate_with_device_add_yet, no way to introspect it */
+ "Bonito",
+ "ICH9 SMB",
+ "ICH9-LPC",
+ "PIIX3",
+ "PIIX3-xen",
+ "PIIX4",
+ "PIIX4_PM",
+ "VT82C686B",
+ "dec-21154",
+ "e500-host-bridge",
+ "grackle",
+ "gt64120_pci",
+ "i440FX",
+ "mch",
+ "pbm-pci",
+ "ppc4xx-host-bridge",
+ "raven",
+ "s390-pcihost",
+ "sh_pci_host",
+ "spapr-pci-host-bridge",
+ "u3-agp",
+ "uni-north-agp",
+ "uni-north-internal-pci",
+ "uni-north-pci",
+ "versatile_pci_host",
+ /* require a suitable host device to pass through */
+ "kvm-pci-assign",
+ "vfio-pci",
+ "vhost-scsi-pci",
+ "xen-pci-passthrough",
+ /* require a backend this test can't setup (yet) */
+ "virtio-9p-pci", /* requires -fsdev ... */
+ "ivshmem", /* requires special chardev */
+ /* test fails */
+ "qxl", /* qemu crashes */
+ "xen-platform" /* qemu crashes */
+};
+
+static struct {
+ const char *name, *propstr;
+} oddball[] = {
+ { "nvme", "serial=foo" },
+ { "xen-pvdevice", "device-id=666" },
+ { "pci-bridge", "chassis_nr=13" },
+};
+
+static bool is_blacklisted(const char *typename)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); i++) {
+ if (!strcmp(blacklist[i], typename)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void add_xprops(TestCase *tcase, const char *typename)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(oddball); i++) {
+ if (!strcmp(oddball[i].name, typename)) {
+ tcase->xprops = oddball[i].propstr;
+ break;
+ }
+ }
+}
+
+static void add_prop(TestCase *tcase, const char *name, const char *value)
+{
+ g_assert(tcase->nprop < ARRAY_SIZE(tcase->prop));
+ tcase->prop[tcase->nprop].name = g_strdup(name);
+ tcase->prop[tcase->nprop].value = g_strdup(value);
+ tcase->nprop++;
+}
+
+static char *fmt_props(const Prop prop[], int nprop, const char *xprops)
+{
+ char **strv = g_new(char *, nprop + 2);
+ int i;
+ char *props;
+
+ for (i = 0; i < nprop; i++) {
+ strv[i] = g_strdup_printf("%s=%s", prop[i].name, prop[i].value);
+ }
+ strv[nprop] = (char *)xprops;
+ strv[nprop + 1] = NULL;
+
+ props = g_strjoinv(",", strv);
+
+ for (i = 0; i < nprop; i++) {
+ g_free(strv[i]);
+ }
+
+ return props;
+}
+
+static char *fmt_blkid(char *buf, size_t sz, int index)
+{
+ size_t len = snprintf(buf, sz, "blk%d", index);
+ g_assert(len < sz);
+ return buf;
+}
+
+static char *fmt_blockdevs(int nblk)
+{
+ char **strv = g_new(char *, nblk + 1);
+ int i;
+ char buf[64];
+ char *blks;
+
+ for (i = 0; i < nblk; i++) {
+ strv[i] = g_strdup_printf("-drive
if=none,id=%s,format=raw,file=/dev/null",
+ fmt_blkid(buf, sizeof(buf), i));
+ }
+ strv[nblk] = NULL;
+
+ blks = g_strjoinv(" ", strv);
+
+ for (i = 0; i < nblk; i++) {
+ g_free(strv[i]);
+ }
+
+ return blks;
+}
+
+static char *fmt_chrid(char *buf, size_t sz, int index)
+{
+ size_t len = snprintf(buf, sz, "chr%d", index);
+ g_assert(len < sz);
+ return buf;
+}
+
+static char *fmt_chardevs(int nchr)
+{
+ char **strv = g_new(char *, nchr + 1);
+ int i;
+ char buf[64];
+ char *chrs;
+
+ for (i = 0; i < nchr; i++) {
+ strv[i] = g_strdup_printf("-chardev null,id=%s",
+ fmt_chrid(buf, sizeof(buf), i));
+ }
+ strv[nchr] = NULL;
+
+ chrs = g_strjoinv(" ", strv);
+
+ for (i = 0; i < nchr; i++) {
+ g_free(strv[i]);
+ }
+
+ return chrs;
+}
+
+static void test_device(gconstpointer data)
+{
+ const TestCase *tcase = data;
+ char *blks = fmt_blockdevs(tcase->nblk);
+ char *chrs = fmt_chardevs(tcase->nchr);
+ char *props = fmt_props(tcase->prop, tcase->nprop, tcase->xprops);
+ char *args;
+ QDict *response;
+
+ args = g_strconcat(blks, chrs, " -device '", props, "'", NULL);
+ g_free(props);
+ qtest_start(args);
+ response = qmp("{ 'execute': 'quit' }");
+ g_assert(qdict_haskey(response, "return"));
+ qtest_end();
+ g_free(args);
+}
+
+static void add_backends(TestCase *tcase, const char *typename)
+{
+ QDict *response, *dpinfo;
+ QList *list;
+ const QListEntry *p;
+ QObject *qobj;
+ QString *qstr;
+ const char *name;
+ char buf[64];
+
+ response = qmp("{ 'execute': 'device-list-properties', "
+ "'arguments': { 'typename': %s } }", typename);
+ g_assert(response);
+ list = qdict_get_qlist(response, "return");
+ g_assert(list);
+
+ for (p = qlist_first(list); p; p = qlist_next(p)) {
+ dpinfo = qobject_to_qdict(qlist_entry_obj(p));
+ g_assert(dpinfo);
+ qobj = qdict_get(dpinfo, "name");
+ g_assert(qobj);
+ qstr = qobject_to_qstring(qobj);
+ g_assert(qstr);
+ name = qstring_get_str(qstr);
+
+ if (strstart(name, "chardev", NULL)) {
+ add_prop(tcase, name,
+ fmt_chrid(buf, sizeof(buf), tcase->nchr++));
+ } else if (strstart(name, "drive", NULL)) {
+ add_prop(tcase, name,
+ fmt_blkid(buf, sizeof(buf), tcase->nblk++));
+ }
+ }
+
+ QDECREF(response);
+}
+
+static void add_device_test_cases(void)
+{
+ QDict *response, *otinfo;
+ QList *list;
+ const QListEntry *p;
+ QObject *qobj;
+ QString *qstr;
+ const char *name, *path;
+ TestCase *tcase;
+
+ qtest_start("-machine none");
+ response = qmp("{ 'execute': 'qom-list-types', "
+ "'arguments': { 'implements': 'pci-device' } }");
+ g_assert(response);
+ list = qdict_get_qlist(response, "return");
+ g_assert(list);
+
+ for (p = qlist_first(list); p; p = qlist_next(p)) {
+ otinfo = qobject_to_qdict(qlist_entry_obj(p));
+ g_assert(otinfo);
+ qobj = qdict_get(otinfo, "name");
+ g_assert(qobj);
+ qstr = qobject_to_qstring(qobj);
+ g_assert(qstr);
+ name = qstring_get_str(qstr);
+
+ if (is_blacklisted(name)) {
+ continue;
+ }
+
+ tcase = g_new0(TestCase, 1);
+ add_prop(tcase, "driver", name);
+ add_backends(tcase, name);
+ add_xprops(tcase, name);
+
+ path = g_strdup_printf("/pci-devs/%s", name);
+ g_test_add_data_func(path, tcase, test_device);
+ }
+
+ QDECREF(response);
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ add_device_test_cases();
+
+ return g_test_run();
+}
--
1.9.3