From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38138) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGqYX-0008LB-Mg for qemu-devel@nongnu.org; Thu, 29 Jan 2015 09:58:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YGqYQ-0005An-MN for qemu-devel@nongnu.org; Thu, 29 Jan 2015 09:58:53 -0500 Received: from mx1.redhat.com ([209.132.183.28]:47339) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGqYQ-0005AL-EZ for qemu-devel@nongnu.org; Thu, 29 Jan 2015 09:58:46 -0500 From: Markus Armbruster Date: Thu, 29 Jan 2015 15:58:40 +0100 Message-Id: <1422543520-8604-2-git-send-email-armbru@redhat.com> In-Reply-To: <1422543520-8604-1-git-send-email-armbru@redhat.com> References: <1422543520-8604-1-git-send-email-armbru@redhat.com> Subject: [Qemu-devel] [PATCH RFC 1/1] qtest: Add generic PCI device test List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: afaerber@suse.de, mst@redhat.com Covers only cold plug with -device so far. Signed-off-by: Markus Armbruster --- 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 , + * + * 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