[libvirt] [PATCH 24/35] tests: qemublock: Add testing of blockdev JSON property generator

Peter Krempa posted 35 patches 7 years ago
[libvirt] [PATCH 24/35] tests: qemublock: Add testing of blockdev JSON property generator
Posted by Peter Krempa 7 years ago
Add a test infrastructure that will allow testing the JSON object
generator used for generating data to use with blockdev-add.

The resulting disk including the backing chain is validated to conform
to the QAPI schema and the expected output files.

The first test cases make sure that libvirt will not allow nodenames
exceeding 31 chars.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 tests/Makefile.am                                  |   3 +
 tests/qemublocktest.c                              | 227 +++++++++++++++++++++
 .../xml2json/nodename-long-format.xml              |  12 ++
 .../xml2json/nodename-long-protocol.xml            |  12 ++
 4 files changed, 254 insertions(+)
 create mode 100644 tests/qemublocktestdata/xml2json/nodename-long-format.xml
 create mode 100644 tests/qemublocktestdata/xml2json/nodename-long-protocol.xml

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 67850349de..6a61296c44 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -119,6 +119,7 @@ EXTRA_DIST = \
 	oomtrace.pl \
 	qemuagentdata \
 	qemuargv2xmldata \
+	qemublocktestdata \
 	qemucapabilitiesdata \
 	qemucaps2xmldata \
 	qemuhotplugtestcpus \
@@ -657,8 +658,10 @@ qemuhotplugtest_LDADD = libqemumonitortestutils.la $(qemu_LDADDS) $(LDADDS)
 qemublocktest_SOURCES = \
 	qemublocktest.c \
 	testutils.h testutils.c \
+	testutilsqemu.h testutilsqemu.c \
 	$(NULL)
 qemublocktest_LDADD = \
+	libqemumonitortestutils.la \
 	../src/libvirt_conf.la \
 	../src/libvirt_util.la \
 	$(qemu_LDADDS) \
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
index 7eef9f286a..161053a717 100644
--- a/tests/qemublocktest.c
+++ b/tests/qemublocktest.c
@@ -19,10 +19,15 @@
 #include <stdlib.h>

 #include "testutils.h"
+#include "testutilsqemu.h"
+#include "testutilsqemuschema.h"
 #include "virstoragefile.h"
 #include "virstring.h"
 #include "virlog.h"
 #include "qemu/qemu_block.h"
+#include "qemu/qemu_qapi.h"
+
+#include "qemu/qemu_command.h"

 #define VIR_FROM_THIS VIR_FROM_NONE

@@ -113,11 +118,190 @@ testBackingXMLjsonXML(const void *args)
 }


+struct testQemuDiskXMLToJSONData {
+    virQEMUDriverPtr driver;
+    virHashTablePtr schema;
+    virJSONValuePtr schemaroot;
+    const char *name;
+    bool fail;
+
+    virJSONValuePtr *props;
+    size_t nprops;
+
+    virQEMUCapsPtr qemuCaps;
+};
+
+
+static void
+testQemuDiskXMLToPropsClear(struct testQemuDiskXMLToJSONData *data)
+{
+    size_t i;
+
+    for (i = 0; i < data->nprops; i++)
+        virJSONValueFree(data->props[i]);
+
+    data->nprops = 0;
+    VIR_FREE(data->props);
+}
+
+
+static const char *testQemuDiskXMLToJSONPath = abs_srcdir "/qemublocktestdata/xml2json/";
+
+static int
+testQemuDiskXMLToProps(const void *opaque)
+{
+    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
+    virDomainDiskDefPtr disk = NULL;
+    virStorageSourcePtr n;
+    virJSONValuePtr props = NULL;
+    char *xmlpath = NULL;
+    char *xmlstr = NULL;
+    int ret = -1;
+
+    if (virAsprintf(&xmlpath, "%s%s.xml",
+                    testQemuDiskXMLToJSONPath, data->name) < 0)
+        goto cleanup;
+
+    if (virTestLoadFile(xmlpath, &xmlstr) < 0)
+        goto cleanup;
+
+    /* qemu stores node names in the status XML portion */
+    if (!(disk = virDomainDiskDefParse(xmlstr, NULL, data->driver->xmlopt,
+                                       VIR_DOMAIN_DEF_PARSE_STATUS)))
+        goto cleanup;
+
+    if (qemuCheckDiskConfig(disk, data->qemuCaps) < 0 ||
+        qemuDomainDeviceDefValidateDisk(disk, data->qemuCaps) < 0) {
+        VIR_TEST_VERBOSE("invalid configuration for disk\n");
+        goto cleanup;
+    }
+
+    if (qemuDomainPrepareDiskSourceChain(disk, NULL, NULL, data->qemuCaps) < 0)
+        goto cleanup;
+
+    for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
+        if (!(props = qemuBlockStorageSourceGetBlockdevProps(n))) {
+            if (!data->fail) {
+                VIR_TEST_VERBOSE("failed to generate qemu blockdev props\n");
+                goto cleanup;
+            }
+        } else if (data->fail) {
+            VIR_TEST_VERBOSE("qemu blockdev props should have failed\n");
+            goto cleanup;
+        }
+
+        if (VIR_APPEND_ELEMENT(data->props, data->nprops, props) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virDomainDiskDefFree(disk);
+    VIR_FREE(xmlpath);
+    VIR_FREE(xmlstr);
+    return ret;
+}
+
+
+static int
+testQemuDiskXMLToPropsValidateSchema(const void *opaque)
+{
+    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
+    virBuffer debug = VIR_BUFFER_INITIALIZER;
+    char *propsstr = NULL;
+    char *debugmsg = NULL;
+    int ret = 0;
+    size_t i;
+
+    if (data->fail)
+        return EXIT_AM_SKIP;
+
+    for (i = 0; i < data->nprops; i++) {
+        if (testQEMUSchemaValidate(data->props[i], data->schemaroot,
+                                   data->schema, &debug) < 0) {
+            debugmsg = virBufferContentAndReset(&debug);
+            propsstr = virJSONValueToString(data->props[i], true);
+            VIR_TEST_VERBOSE("json does not conform to QAPI schema");
+            VIR_TEST_DEBUG("json:\n%s\ndoes not match schema. Debug output:\n %s",
+                           propsstr, NULLSTR(debugmsg));
+            VIR_FREE(debugmsg);
+            VIR_FREE(propsstr);
+            ret = -1;
+        }
+
+        virBufferFreeAndReset(&debug);
+    }
+    return ret;
+}
+
+
+static int
+testQemuDiskXMLToPropsValidateFile(const void *opaque)
+{
+    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *jsonpath = NULL;
+    char *jsonstr = NULL;
+    char *actual = NULL;
+    int ret = -1;
+    size_t i;
+
+    if (data->fail)
+        return EXIT_AM_SKIP;
+
+    if (virAsprintf(&jsonpath, "%s%s.json",
+                    testQemuDiskXMLToJSONPath, data->name) < 0)
+        goto cleanup;
+
+    for (i = 0; i < data->nprops; i++) {
+        if (!(jsonstr = virJSONValueToString(data->props[i], true)))
+            goto cleanup;
+
+        virBufferAdd(&buf, jsonstr, -1);
+    }
+
+    if (virBufferCheckError(&buf) < 0)
+        goto cleanup;
+
+    actual = virBufferContentAndReset(&buf);
+
+    ret = virTestCompareToFile(actual, jsonpath);
+
+ cleanup:
+    VIR_FREE(jsonpath);
+    VIR_FREE(jsonstr);
+    VIR_FREE(actual);
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
     int ret = 0;
+    virQEMUDriver driver;
     struct testBackingXMLjsonXMLdata xmljsonxmldata;
+    struct testQemuDiskXMLToJSONData diskxmljsondata;
+    char *capslatest_x86_64 = NULL;
+    virQEMUCapsPtr caps_x86_64 = NULL;
+
+    if (qemuTestDriverInit(&driver) < 0)
+        return EXIT_FAILURE;
+
+    diskxmljsondata.driver = &driver;
+
+    if (!(capslatest_x86_64 = testQemuGetLatestCapsForArch(abs_srcdir "/qemucapabilitiesdata",
+                                                           "x86_64", "xml")))
+        return EXIT_FAILURE;
+
+    VIR_TEST_VERBOSE("\nlatest caps x86_64: %s\n", capslatest_x86_64);
+
+    if (!(caps_x86_64 = qemuTestParseCapabilitiesArch(virArchFromString("x86_64"),
+                                                      capslatest_x86_64)))
+        return EXIT_FAILURE;
+
+    diskxmljsondata.qemuCaps = caps_x86_64;

     virTestCounterReset("qemu storage source xml->json->xml ");

@@ -183,6 +367,49 @@ mymain(void)
                          "  <host name='example.com' port='9999'/>\n"
                          "</source>\n");

+#define TEST_DISK_TO_JSON_FULL(nme, fl) \
+    do { \
+        diskxmljsondata.name = nme; \
+        diskxmljsondata.props = NULL; \
+        diskxmljsondata.nprops = 0; \
+        diskxmljsondata.fail = fl; \
+        if (virTestRun("disk xml to props " nme, testQemuDiskXMLToProps, \
+                       &diskxmljsondata) < 0) \
+            ret = -1; \
+        if (virTestRun("disk xml to props validate schema " nme, \
+                       testQemuDiskXMLToPropsValidateSchema, &diskxmljsondata) < 0) \
+            ret = -1; \
+        if (virTestRun("disk xml to props validate file " nme, \
+                       testQemuDiskXMLToPropsValidateFile,  &diskxmljsondata) < 0) \
+            ret = -1; \
+        testQemuDiskXMLToPropsClear(&diskxmljsondata); \
+    } while (0)
+
+#define TEST_DISK_TO_JSON(nme) TEST_DISK_TO_JSON_FULL(nme, false)
+
+    if (!(diskxmljsondata.schema = testQEMUSchemaLoad())) {
+        ret = -1;
+        goto cleanup;
+    }
+
+    if (virQEMUQAPISchemaPathGet("blockdev-add/arg-type",
+                                 diskxmljsondata.schema,
+                                 &diskxmljsondata.schemaroot) < 0 ||
+        !diskxmljsondata.schemaroot) {
+        VIR_TEST_VERBOSE("failed to find schema entry for blockdev-add\n");
+        ret = -1;
+        goto cleanup;
+    }
+
+    TEST_DISK_TO_JSON_FULL("nodename-long-format", true);
+    TEST_DISK_TO_JSON_FULL("nodename-long-protocol", true);
+
+ cleanup:
+    virHashFree(diskxmljsondata.schema);
+    qemuTestDriverFree(&driver);
+    VIR_FREE(capslatest_x86_64);
+    virObjectUnref(caps_x86_64);
+
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }

diff --git a/tests/qemublocktestdata/xml2json/nodename-long-format.xml b/tests/qemublocktestdata/xml2json/nodename-long-format.xml
new file mode 100644
index 0000000000..8fccf850db
--- /dev/null
+++ b/tests/qemublocktestdata/xml2json/nodename-long-format.xml
@@ -0,0 +1,12 @@
+<disk device='disk'>
+  <driver name='qemu' type='raw'/>
+  <source file='/path'>
+    <privateData>
+      <nodenames>
+        <nodename type='storage' name='test2'/>
+        <nodename type='format' name='0123456789ABCDEF0123456789ABCDEF'/>
+      </nodenames>
+    </privateData>
+  </source>
+  <target dev='vda'/>
+</disk>
diff --git a/tests/qemublocktestdata/xml2json/nodename-long-protocol.xml b/tests/qemublocktestdata/xml2json/nodename-long-protocol.xml
new file mode 100644
index 0000000000..e60d988325
--- /dev/null
+++ b/tests/qemublocktestdata/xml2json/nodename-long-protocol.xml
@@ -0,0 +1,12 @@
+<disk device='disk'>
+  <driver name='qemu' type='raw'/>
+  <source file='/path'>
+    <privateData>
+      <nodenames>
+        <nodename type='storage' name='0123456789ABCDEF0123456789ABCDEF0'/>
+        <nodename type='format' name='test1'/>
+      </nodenames>
+    </privateData>
+  </source>
+  <target dev='vda'/>
+</disk>
-- 
2.16.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 24/35] tests: qemublock: Add testing of blockdev JSON property generator
Posted by John Ferlan 7 years ago

On 04/25/2018 11:15 AM, Peter Krempa wrote:
> Add a test infrastructure that will allow testing the JSON object
> generator used for generating data to use with blockdev-add.
> 
> The resulting disk including the backing chain is validated to conform
> to the QAPI schema and the expected output files.
> 
> The first test cases make sure that libvirt will not allow nodenames
> exceeding 31 chars.
> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>  tests/Makefile.am                                  |   3 +
>  tests/qemublocktest.c                              | 227 +++++++++++++++++++++
>  .../xml2json/nodename-long-format.xml              |  12 ++
>  .../xml2json/nodename-long-protocol.xml            |  12 ++
>  4 files changed, 254 insertions(+)
>  create mode 100644 tests/qemublocktestdata/xml2json/nodename-long-format.xml
>  create mode 100644 tests/qemublocktestdata/xml2json/nodename-long-protocol.xml
> 

[...]]

> +struct testQemuDiskXMLToJSONData {
> +    virQEMUDriverPtr driver;
> +    virHashTablePtr schema;
> +    virJSONValuePtr schemaroot;
> +    const char *name;
> +    bool fail;

If there was a const char *expt; which would have at least a subset of
the expected error message, then you'd really know if the failure was
for what you were testing as opposed to some other random failure
(without needing to turn on debug).

Nothing that needs to change for an R-by, but just a random thought as I
ran the test w/ debug mode for the errors:


internal error: node-name '0123456789ABCDEF0123456789ABCDEF' too long
for qemu

and

internal error: node-name '0123456789ABCDEF0123456789ABCDEF0' too long
for qemu

> +
> +    virJSONValuePtr *props;
> +    size_t nprops;
> +
> +    virQEMUCapsPtr qemuCaps;
> +};
> +
> +

[...]

> +static int
> +testQemuDiskXMLToPropsValidateFile(const void *opaque)
> +{
> +    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
> +    char *jsonpath = NULL;
> +    char *jsonstr = NULL;
> +    char *actual = NULL;
> +    int ret = -1;
> +    size_t i;
> +
> +    if (data->fail)
> +        return EXIT_AM_SKIP;
> +
> +    if (virAsprintf(&jsonpath, "%s%s.json",
> +                    testQemuDiskXMLToJSONPath, data->name) < 0)
> +        goto cleanup;
> +
> +    for (i = 0; i < data->nprops; i++) {
> +        if (!(jsonstr = virJSONValueToString(data->props[i], true)))
> +            goto cleanup;
> +
> +        virBufferAdd(&buf, jsonstr, -1);

Coverity informed me @jsonstr would be leaked each time through the
loop.  Probably could just be local to this loop too.

> +    }
> +
> +    if (virBufferCheckError(&buf) < 0)
> +        goto cleanup;
> +
> +    actual = virBufferContentAndReset(&buf);
> +
> +    ret = virTestCompareToFile(actual, jsonpath);
> +
> + cleanup:
> +    VIR_FREE(jsonpath);
> +    VIR_FREE(jsonstr);
> +    VIR_FREE(actual);
> +    return ret;
> +}
> +
> +

Reviewed-by: John Ferlan <jferlan@redhat.com>

John

[...]

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list