mirror of https://gitee.com/openkylin/libvirt.git
tests: Introduce qemucapabilitiestest
This test is there to ensure that our capabilities detection code isn't broken somehow. How to gather test data: Firstly, the data is split into two separate files. The former (with suffix .replies) contains all the qemu replies. This is very fragile as introducing a new device can mean yet another monitor command and hence edit of this file in the future. But there's no better way of doing this. To get this data simply turn on debug logs and copy all the QEMU_MONITOR_IO_PROCESS lines. But be careful to not copy incomplete ones (yeah, we report some incomplete lines too). Long story short, at the libvirtd startup, a dummy qemu is spawn to get all the capabilities. The latter (with suffix .caps) contains capabilities XML. Just start a domain and copy the corresponding part from its state XML file. Including <qemuCaps> tag. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
bd958586ec
commit
63857eb4a0
|
@ -176,6 +176,7 @@
|
|||
/tests/openvzutilstest
|
||||
/tests/qemuagenttest
|
||||
/tests/qemuargv2xmltest
|
||||
/tests/qemucapabilitiestest
|
||||
/tests/qemuhelptest
|
||||
/tests/qemuhotplugtest
|
||||
/tests/qemumonitorjsontest
|
||||
|
|
|
@ -82,6 +82,7 @@ EXTRA_DIST = \
|
|||
nwfilterxml2xmlin \
|
||||
nwfilterxml2xmlout \
|
||||
oomtrace.pl \
|
||||
qemucapabilitiesdata \
|
||||
qemuhelpdata \
|
||||
qemuhotplugtestdata \
|
||||
qemuxml2argvdata \
|
||||
|
@ -173,7 +174,7 @@ if WITH_QEMU
|
|||
test_programs += qemuxml2argvtest qemuxml2xmltest qemuxmlnstest \
|
||||
qemuargv2xmltest qemuhelptest domainsnapshotxml2xmltest \
|
||||
qemumonitortest qemumonitorjsontest qemuhotplugtest \
|
||||
qemuagenttest
|
||||
qemuagenttest qemucapabilitiestest
|
||||
endif WITH_QEMU
|
||||
|
||||
if WITH_LXC
|
||||
|
@ -440,6 +441,13 @@ qemumonitorjsontest_SOURCES = \
|
|||
$(NULL)
|
||||
qemumonitorjsontest_LDADD = libqemumonitortestutils.la $(qemu_LDADDS)
|
||||
|
||||
qemucapabilitiestest_SOURCES = \
|
||||
qemucapabilitiestest.c \
|
||||
testutils.c testutils.h \
|
||||
testutilsqemu.c testutilsqemu.h \
|
||||
$(NULL)
|
||||
qemucapabilitiestest_LDADD = libqemumonitortestutils.la $(qemu_LDADDS)
|
||||
|
||||
qemuagenttest_SOURCES = \
|
||||
qemuagenttest.c \
|
||||
testutils.c testutils.h \
|
||||
|
@ -463,7 +471,7 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \
|
|||
qemuxmlnstest.c qemuhelptest.c domainsnapshotxml2xmltest.c \
|
||||
qemumonitortest.c testutilsqemu.c testutilsqemu.h \
|
||||
qemumonitorjsontest.c qemuhotplugtest.c \
|
||||
qemuagenttest.c \
|
||||
qemuagenttest.c qemucapabilitiestest.c \
|
||||
$(QEMUMONITORTESTUTILS_SOURCES)
|
||||
endif ! WITH_QEMU
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
<qemuCaps>
|
||||
<flag name='vnc-colon'/>
|
||||
<flag name='no-reboot'/>
|
||||
<flag name='drive'/>
|
||||
<flag name='name'/>
|
||||
<flag name='uuid'/>
|
||||
<flag name='vnet-hdr'/>
|
||||
<flag name='migrate-qemu-tcp'/>
|
||||
<flag name='migrate-qemu-exec'/>
|
||||
<flag name='drive-cache-v2'/>
|
||||
<flag name='drive-format'/>
|
||||
<flag name='vga'/>
|
||||
<flag name='0.10'/>
|
||||
<flag name='mem-path'/>
|
||||
<flag name='drive-serial'/>
|
||||
<flag name='migrate-qemu-unix'/>
|
||||
<flag name='chardev'/>
|
||||
<flag name='enable-kvm'/>
|
||||
<flag name='monitor-json'/>
|
||||
<flag name='balloon'/>
|
||||
<flag name='device'/>
|
||||
<flag name='sdl'/>
|
||||
<flag name='smp-topology'/>
|
||||
<flag name='netdev'/>
|
||||
<flag name='rtc'/>
|
||||
<flag name='vhost-net'/>
|
||||
<flag name='no-hpet'/>
|
||||
<flag name='no-kvm-pit'/>
|
||||
<flag name='pci-configfd'/>
|
||||
<flag name='nodefconfig'/>
|
||||
<flag name='boot-menu'/>
|
||||
<flag name='fsdev'/>
|
||||
<flag name='name-process'/>
|
||||
<flag name='drive-readonly'/>
|
||||
<flag name='smbios-type'/>
|
||||
<flag name='vga-qxl'/>
|
||||
<flag name='spice'/>
|
||||
<flag name='vga-none'/>
|
||||
<flag name='migrate-qemu-fd'/>
|
||||
<flag name='boot-index'/>
|
||||
<flag name='hda-duplex'/>
|
||||
<flag name='drive-aio'/>
|
||||
<flag name='pci-multibus'/>
|
||||
<flag name='pci-bootindex'/>
|
||||
<flag name='ccid-passthru'/>
|
||||
<flag name='chardev-spicevmc'/>
|
||||
<flag name='virtio-tx-alg'/>
|
||||
<flag name='device-qxl-vga'/>
|
||||
<flag name='pci-multifunction'/>
|
||||
<flag name='virtio-blk-pci.ioeventfd'/>
|
||||
<flag name='sga'/>
|
||||
<flag name='virtio-blk-pci.event_idx'/>
|
||||
<flag name='virtio-net-pci.event_idx'/>
|
||||
<flag name='cache-directsync'/>
|
||||
<flag name='piix3-usb-uhci'/>
|
||||
<flag name='piix4-usb-uhci'/>
|
||||
<flag name='usb-ehci'/>
|
||||
<flag name='ich9-usb-ehci1'/>
|
||||
<flag name='vt82c686b-usb-uhci'/>
|
||||
<flag name='pci-ohci'/>
|
||||
<flag name='usb-hub'/>
|
||||
<flag name='no-shutdown'/>
|
||||
<flag name='cache-unsafe'/>
|
||||
<flag name='rombar'/>
|
||||
<flag name='ich9-ahci'/>
|
||||
<flag name='no-acpi'/>
|
||||
<flag name='fsdev-readonly'/>
|
||||
<flag name='virtio-blk-pci.scsi'/>
|
||||
<flag name='blk-sg-io'/>
|
||||
<flag name='drive-copy-on-read'/>
|
||||
<flag name='cpu-host'/>
|
||||
<flag name='fsdev-writeout'/>
|
||||
<flag name='drive-iotune'/>
|
||||
<flag name='system_wakeup'/>
|
||||
<flag name='scsi-disk.channel'/>
|
||||
<flag name='scsi-block'/>
|
||||
<flag name='transaction'/>
|
||||
<flag name='block-job-async'/>
|
||||
<flag name='scsi-cd'/>
|
||||
<flag name='ide-cd'/>
|
||||
<flag name='no-user-config'/>
|
||||
<flag name='hda-micro'/>
|
||||
<flag name='dump-guest-memory'/>
|
||||
<flag name='nec-usb-xhci'/>
|
||||
<flag name='balloon-event'/>
|
||||
<flag name='bridge'/>
|
||||
<flag name='lsi'/>
|
||||
<flag name='virtio-scsi-pci'/>
|
||||
<flag name='blockio'/>
|
||||
<flag name='disable-s3'/>
|
||||
<flag name='disable-s4'/>
|
||||
<flag name='ide-drive.wwn'/>
|
||||
<flag name='scsi-disk.wwn'/>
|
||||
<flag name='seccomp-sandbox'/>
|
||||
<flag name='dump-guest-core'/>
|
||||
<flag name='seamless-migration'/>
|
||||
<flag name='block-commit'/>
|
||||
<flag name='vnc'/>
|
||||
<flag name='drive-mirror'/>
|
||||
<flag name='usb-host.bootindex'/>
|
||||
<flag name='blockdev-snapshot-sync'/>
|
||||
<flag name='qxl'/>
|
||||
<flag name='VGA'/>
|
||||
<flag name='cirrus-vga'/>
|
||||
<flag name='vmware-svga'/>
|
||||
<flag name='usb-serial'/>
|
||||
<flag name='usb-net'/>
|
||||
<flag name='add-fd'/>
|
||||
<flag name='nbd-server'/>
|
||||
<flag name='virtio-rng'/>
|
||||
<flag name='rng-random'/>
|
||||
<flag name='rng-egd'/>
|
||||
<flag name='dtb'/>
|
||||
<flag name='megasas'/>
|
||||
<flag name='ipv6-migration'/>
|
||||
<flag name='machine-opt'/>
|
||||
<flag name='machine-usb-opt'/>
|
||||
<flag name='pci-bridge'/>
|
||||
<flag name='vfio-pci'/>
|
||||
<flag name='vfio-pci.bootindex'/>
|
||||
<flag name='scsi-generic'/>
|
||||
<flag name='scsi-generic.bootindex'/>
|
||||
<flag name='mem-merge'/>
|
||||
<flag name='vnc-websocket'/>
|
||||
<flag name='drive-discard'/>
|
||||
<flag name='mlock'/>
|
||||
<flag name='vnc-share-policy'/>
|
||||
<flag name='device-del-event'/>
|
||||
<flag name='dmi-to-pci-bridge'/>
|
||||
<flag name='usb-storage'/>
|
||||
<flag name='usb-storage.removable'/>
|
||||
<flag name='ich9-intel-hda'/>
|
||||
</qemuCaps>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "testutils.h"
|
||||
#include "testutilsqemu.h"
|
||||
#include "qemumonitortestutils.h"
|
||||
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
typedef struct _testQemuData testQemuData;
|
||||
typedef testQemuData * testQemuDataPtr;
|
||||
struct _testQemuData {
|
||||
virDomainXMLOptionPtr xmlopt;
|
||||
const char *base;
|
||||
};
|
||||
|
||||
static qemuMonitorTestPtr
|
||||
testQemuFeedMonitor(char *replies,
|
||||
virDomainXMLOptionPtr xmlopt)
|
||||
{
|
||||
qemuMonitorTestPtr test = NULL;
|
||||
char *tmp = replies;
|
||||
char *singleReply = tmp;
|
||||
|
||||
/* Our JSON parser expects replies to be separated by a newline character.
|
||||
* Hence we must preprocess the file a bit. */
|
||||
while ((tmp = strchr(tmp, '\n'))) {
|
||||
/* It is safe to touch tmp[1] since all strings ends with '\0'. */
|
||||
bool eof = !tmp[1];
|
||||
|
||||
if (*(tmp + 1) != '\n') {
|
||||
*tmp = ' ';
|
||||
tmp++;
|
||||
} else {
|
||||
/* Cut off a single reply. */
|
||||
*(tmp + 1) = '\0';
|
||||
|
||||
if (test) {
|
||||
if (qemuMonitorTestAddItem(test, NULL, singleReply) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
/* Create new mocked monitor with our greeting */
|
||||
if (!(test = qemuMonitorTestNew(true, xmlopt, NULL, NULL, singleReply)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!eof) {
|
||||
/* Move the @tmp and @singleReply. */
|
||||
tmp += 2;
|
||||
singleReply = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (eof)
|
||||
break;
|
||||
}
|
||||
|
||||
if (test && qemuMonitorTestAddItem(test, NULL, singleReply) < 0)
|
||||
goto error;
|
||||
|
||||
return test;
|
||||
|
||||
error:
|
||||
qemuMonitorTestFree(test);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static virQEMUCapsPtr
|
||||
testQemuGetCaps(char *caps)
|
||||
{
|
||||
virQEMUCapsPtr qemuCaps = NULL;
|
||||
xmlDocPtr xml;
|
||||
xmlXPathContextPtr ctxt = NULL;
|
||||
ssize_t i, n;
|
||||
xmlNodePtr *nodes = NULL;
|
||||
|
||||
if (!(xml = virXMLParseStringCtxt(caps, "(test caps)", &ctxt)))
|
||||
goto error;
|
||||
|
||||
if ((n = virXPathNodeSet("/qemuCaps/flag", ctxt, &nodes)) < 0) {
|
||||
fprintf(stderr, "failed to parse qemu capabilities flags");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
if (!(qemuCaps = virQEMUCapsNew()))
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
char *str = virXMLPropString(nodes[i], "name");
|
||||
if (str) {
|
||||
int flag = virQEMUCapsTypeFromString(str);
|
||||
if (flag < 0) {
|
||||
fprintf(stderr, "Unknown qemu capabilities flag %s", str);
|
||||
VIR_FREE(str);
|
||||
goto error;
|
||||
}
|
||||
VIR_FREE(str);
|
||||
virQEMUCapsSet(qemuCaps, flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VIR_FREE(nodes);
|
||||
xmlFreeDoc(xml);
|
||||
xmlXPathFreeContext(ctxt);
|
||||
return qemuCaps;
|
||||
|
||||
error:
|
||||
VIR_FREE(nodes);
|
||||
virObjectUnref(qemuCaps);
|
||||
xmlFreeDoc(xml);
|
||||
xmlXPathFreeContext(ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
testQemuCapsCompare(virQEMUCapsPtr capsProvided,
|
||||
virQEMUCapsPtr capsComputed)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < QEMU_CAPS_LAST; i++) {
|
||||
if (virQEMUCapsGet(capsProvided, i) &&
|
||||
!virQEMUCapsGet(capsComputed, i)) {
|
||||
fprintf(stderr, "Caps mismatch: capsComputed is missing %s\n",
|
||||
virQEMUCapsTypeToString(i));
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (virQEMUCapsGet(capsComputed, i) &&
|
||||
!virQEMUCapsGet(capsProvided, i)) {
|
||||
fprintf(stderr, "Caps mismatch: capsProvided is missing %s\n",
|
||||
virQEMUCapsTypeToString(i));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
testQemuCaps(const void *opaque)
|
||||
{
|
||||
int ret = -1;
|
||||
const testQemuDataPtr data = (const testQemuDataPtr) opaque;
|
||||
char *repliesFile = NULL, *capsFile = NULL;
|
||||
char *replies = NULL, *caps = NULL;
|
||||
qemuMonitorTestPtr mon = NULL;
|
||||
virQEMUCapsPtr capsProvided = NULL, capsComputed = NULL;
|
||||
|
||||
if (virAsprintf(&repliesFile, "%s/qemucapabilitiesdata/%s.replies",
|
||||
abs_srcdir, data->base) < 0 ||
|
||||
virAsprintf(&capsFile, "%s/qemucapabilitiesdata/%s.caps",
|
||||
abs_srcdir, data->base) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virtTestLoadFile(repliesFile, &replies) < 0 ||
|
||||
virtTestLoadFile(capsFile, &caps) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(mon = testQemuFeedMonitor(replies, data->xmlopt)))
|
||||
goto cleanup;
|
||||
|
||||
if (!(capsProvided = testQemuGetCaps(caps)))
|
||||
goto cleanup;
|
||||
|
||||
if (!(capsComputed = virQEMUCapsNew()))
|
||||
goto cleanup;
|
||||
|
||||
if (virQEMUCapsInitQMPMonitor(capsComputed,
|
||||
qemuMonitorTestGetMonitor(mon)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (testQemuCapsCompare(capsProvided, capsComputed) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(repliesFile);
|
||||
VIR_FREE(capsFile);
|
||||
VIR_FREE(replies);
|
||||
VIR_FREE(caps);
|
||||
qemuMonitorTestFree(mon);
|
||||
virObjectUnref(capsProvided);
|
||||
virObjectUnref(capsComputed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mymain(void)
|
||||
{
|
||||
int ret = 0;
|
||||
virDomainXMLOptionPtr xmlopt;
|
||||
testQemuData data;
|
||||
|
||||
#if !WITH_YAJL
|
||||
fputs("libvirt not compiled with yajl, skipping this test\n", stderr);
|
||||
return EXIT_AM_SKIP;
|
||||
#endif
|
||||
|
||||
if (virThreadInitialize() < 0 ||
|
||||
!(xmlopt = virQEMUDriverCreateXMLConf(NULL)))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
virEventRegisterDefaultImpl();
|
||||
|
||||
data.xmlopt = xmlopt;
|
||||
|
||||
#define DO_TEST(name) \
|
||||
data.base = name; \
|
||||
if (virtTestRun(name, 1, testQemuCaps, &data) < 0) \
|
||||
ret = -1
|
||||
|
||||
DO_TEST("caps_1.5.3-1");
|
||||
|
||||
virObjectUnref(xmlopt);
|
||||
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
VIRT_TEST_MAIN(mymain)
|
Loading…
Reference in New Issue