libvirt/tests/qemudomainsnapshotxml2xmltest.c
Jiri Denemark 577a1f98fc qemu: Pass correct qemuCaps to virDomainDefParseNode
Since qemuDomainDefPostParse callback requires qemuCaps, we need to make
sure it gets the capabilities stored in the domain's private data if the
domain is running. Passing NULL may cause QEMU capabilities probing to
be triggered in case QEMU binary changed in the meantime. When this
happens while a running domain object is locked, QMP event delivered to
the domain before QEMU capabilities probing finishes will deadlock the
event loop.

Several general snapshot and checkpoint APIs were lazily passing NULL as
the parseOpaque pointer instead of letting their callers pass the right
data. This patch fixes all paths leading to virDomainDefParseNode.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-08-09 13:55:54 +02:00

208 lines
6.1 KiB
C

#include <config.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "testutils.h"
#ifdef WITH_QEMU
# include "internal.h"
# include "qemu/qemu_conf.h"
# include "qemu/qemu_domain.h"
# include "testutilsqemu.h"
# include "virstring.h"
# define VIR_FROM_THIS VIR_FROM_NONE
static virQEMUDriver driver;
enum {
TEST_INTERNAL = 1 << 0, /* Test use of INTERNAL parse/format flag */
TEST_REDEFINE = 1 << 1, /* Test use of REDEFINE parse flag */
TEST_RUNNING = 1 << 2, /* Set snapshot state to running after parse */
};
static int
testCompareXMLToXMLFiles(const char *inxml,
const char *outxml,
const char *uuid,
unsigned int flags)
{
char *inXmlData = NULL;
char *outXmlData = NULL;
char *actual = NULL;
int ret = -1;
unsigned int parseflags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
unsigned int formatflags = VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE;
bool cur = false;
VIR_AUTOUNREF(virDomainSnapshotDefPtr) def = NULL;
if (flags & TEST_INTERNAL) {
parseflags |= VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL;
formatflags |= VIR_DOMAIN_SNAPSHOT_FORMAT_INTERNAL;
}
if (flags & TEST_REDEFINE)
parseflags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
if (virTestLoadFile(inxml, &inXmlData) < 0)
goto cleanup;
if (virTestLoadFile(outxml, &outXmlData) < 0)
goto cleanup;
if (!(def = virDomainSnapshotDefParseString(inXmlData, driver.caps,
driver.xmlopt, NULL, &cur,
parseflags)))
goto cleanup;
if (cur) {
if (!(flags & TEST_INTERNAL))
goto cleanup;
formatflags |= VIR_DOMAIN_SNAPSHOT_FORMAT_CURRENT;
}
if (flags & TEST_RUNNING) {
if (def->state)
goto cleanup;
def->state = VIR_DOMAIN_RUNNING;
}
if (!(actual = virDomainSnapshotDefFormat(uuid, def, driver.caps,
driver.xmlopt,
formatflags)))
goto cleanup;
if (STRNEQ(outXmlData, actual)) {
virTestDifferenceFull(stderr, outXmlData, outxml, actual, inxml);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(inXmlData);
VIR_FREE(outXmlData);
VIR_FREE(actual);
return ret;
}
struct testInfo {
const char *inxml;
const char *outxml;
const char *uuid;
long long creationTime;
unsigned int flags;
};
static long long mocktime;
static int
testSnapshotPostParse(virDomainMomentDefPtr def)
{
if (!mocktime)
return 0;
if (def->creationTime)
return -1;
def->creationTime = mocktime;
if (!def->name &&
virAsprintf(&def->name, "%lld", def->creationTime) < 0)
return -1;
return 0;
}
static int
testCompareXMLToXMLHelper(const void *data)
{
const struct testInfo *info = data;
mocktime = info->creationTime;
return testCompareXMLToXMLFiles(info->inxml, info->outxml, info->uuid,
info->flags);
}
static int
mymain(void)
{
int ret = 0;
if (qemuTestDriverInit(&driver) < 0)
return EXIT_FAILURE;
virDomainXMLOptionSetMomentPostParse(driver.xmlopt,
testSnapshotPostParse);
# define DO_TEST(prefix, name, inpath, outpath, uuid, time, flags) \
do { \
const struct testInfo info = {abs_srcdir "/" inpath "/" name ".xml", \
abs_srcdir "/" outpath "/" name ".xml", \
uuid, time, flags}; \
if (virTestRun("SNAPSHOT XML-2-XML " prefix " " name, \
testCompareXMLToXMLHelper, &info) < 0) \
ret = -1; \
} while (0)
# define DO_TEST_IN(name, uuid) DO_TEST("in->in", name, \
"qemudomainsnapshotxml2xmlin", \
"qemudomainsnapshotxml2xmlin", \
uuid, 0, 0)
# define DO_TEST_OUT(name, uuid, internal) \
DO_TEST("out->out", name, "qemudomainsnapshotxml2xmlout", \
"qemudomainsnapshotxml2xmlout", uuid, 0, internal | TEST_REDEFINE)
# define DO_TEST_INOUT(name, uuid, time, flags) \
DO_TEST("in->out", name, \
"qemudomainsnapshotxml2xmlin",\
"qemudomainsnapshotxml2xmlout",\
uuid, time, flags)
/* Unset or set all envvars here that are copied in qemudBuildCommandLine
* using ADD_ENV_COPY, otherwise these tests may fail due to unexpected
* values for these envvars */
setenv("PATH", "/bin", 1);
DO_TEST_OUT("all_parameters", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8",
TEST_INTERNAL);
DO_TEST_OUT("disk_snapshot_redefine", "c7a5fdbd-edaf-9455-926a-d65c16db1809",
TEST_INTERNAL);
DO_TEST_OUT("full_domain", "c7a5fdbd-edaf-9455-926a-d65c16db1809",
TEST_INTERNAL);
DO_TEST_OUT("noparent_nodescription_noactive", NULL, 0);
DO_TEST_OUT("noparent_nodescription", NULL, TEST_INTERNAL);
DO_TEST_OUT("noparent", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8", 0);
DO_TEST_OUT("metadata", "c7a5fdbd-edaf-9455-926a-d65c16db1809", 0);
DO_TEST_OUT("external_vm_redefine", "c7a5fdbd-edaf-9455-926a-d65c16db1809",
0);
DO_TEST_INOUT("empty", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8",
1386166249, 0);
DO_TEST_INOUT("noparent", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8",
1272917631, TEST_RUNNING);
DO_TEST_INOUT("external_vm", NULL, 1555419243, 0);
DO_TEST_INOUT("disk_snapshot", NULL, 1555419243, 0);
DO_TEST_INOUT("disk_driver_name_null", NULL, 1555419243, 0);
DO_TEST_INOUT("disk-seclabel", "9d37b878-a7cc-9f9a-b78f-49b3abad25a8", 581484660, 0);
DO_TEST_IN("name_and_description", NULL);
DO_TEST_IN("description_only", NULL);
DO_TEST_IN("name_only", NULL);
qemuTestDriverFree(&driver);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
VIR_TEST_MAIN(mymain)
#else
int
main(void)
{
return EXIT_AM_SKIP;
}
#endif /* WITH_QEMU */