[libvirt] [PATCHv2 0/2] Test status XML formatting and parsing

Peter Krempa (2): util: buffer: Add support for adding text blocks with indentation tests: qemuxml2xml: Test status XML formatting and parsing src/conf/domain_conf.c | 4 +- src/conf/domain_conf.h | 9 ++++ src/libvirt_private.syms | 3 ++ src/util/virbuffer.c | 29 +++++++++++++ src/util/virbuffer.h | 1 + tests/qemuxml2xmltest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ tests/virbuftest.c | 49 +++++++++++++++++++++ 7 files changed, 204 insertions(+), 2 deletions(-) -- 2.2.2

The current auto-indentation buffer code applies indentation only on complete strings. To allow adding a string containing newlines and having it properly indented this patch adds virBufferAddStr. --- src/libvirt_private.syms | 1 + src/util/virbuffer.c | 29 ++++++++++++++++++++++++++++ src/util/virbuffer.h | 1 + tests/virbuftest.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e60df1..893e181 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1099,6 +1099,7 @@ virBitmapToData; virBufferAdd; virBufferAddBuffer; virBufferAddChar; +virBufferAddStr; virBufferAdjustIndent; virBufferAsprintf; virBufferCheckErrorInternal; diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c index 0089d1b..706dbfa 100644 --- a/src/util/virbuffer.c +++ b/src/util/virbuffer.c @@ -756,3 +756,32 @@ virBufferTrim(virBufferPtr buf, const char *str, int len) buf->use -= len < 0 ? len2 : len; buf->content[buf->use] = '\0'; } + + +/** + * virBufferAddStr: + * @buf: the buffer to append to + * @str: string to append + * + * Appends @str to @buffer. Applies autoindentation on the separate lines of + * @str. + */ +void +virBufferAddStr(virBufferPtr buf, + const char *str) +{ + const char *end; + + if (!buf || !str || buf->error) + return; + + while (*str) { + if ((end = strchr(str, '\n'))) { + virBufferAdd(buf, str, (end - str) + 1); + str = end + 1; + } else { + virBufferAdd(buf, str, -1); + break; + } + } +} diff --git a/src/util/virbuffer.h b/src/util/virbuffer.h index 24e81c7..144a1ba 100644 --- a/src/util/virbuffer.h +++ b/src/util/virbuffer.h @@ -96,5 +96,6 @@ void virBufferAdjustIndent(virBufferPtr buf, int indent); int virBufferGetIndent(const virBuffer *buf, bool dynamic); void virBufferTrim(virBufferPtr buf, const char *trim, int len); +void virBufferAddStr(virBufferPtr buf, const char *str); #endif /* __VIR_BUFFER_H__ */ diff --git a/tests/virbuftest.c b/tests/virbuftest.c index f964feb..21cb18b 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -310,6 +310,43 @@ static int testBufAddBuffer(const void *data ATTRIBUTE_UNUSED) return ret; } +struct testBufAddStrData { + const char *data; + const char *expect; +}; + +static int +testBufAddStr(const void *opaque ATTRIBUTE_UNUSED) +{ + const struct testBufAddStrData *data = opaque; + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *actual; + int ret = -1; + + virBufferAddLit(&buf, "<c>\n"); + virBufferAdjustIndent(&buf, 2); + virBufferAddStr(&buf, data->data); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</c>"); + + if (!(actual = virBufferContentAndReset(&buf))) { + TEST_ERROR("buf is empty"); + goto cleanup; + } + + if (STRNEQ_NULLABLE(actual, data->expect)) { + TEST_ERROR("testBufAddStr(): Strings don't match:\n"); + virtTestDifference(stderr, data->expect, actual); + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(actual); + return ret; +} + static int mymain(void) @@ -330,6 +367,18 @@ mymain(void) DO_TEST("Trim", testBufTrim, 0); DO_TEST("AddBuffer", testBufAddBuffer, 0); +#define DO_TEST_ADD_STR(DATA, EXPECT) \ + do { \ + struct testBufAddStrData info = { DATA, EXPECT }; \ + if (virtTestRun("Buf: AddStr", testBufAddStr, &info) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST_ADD_STR("", "<c>\n</c>"); + DO_TEST_ADD_STR("<a/>", "<c>\n <a/></c>"); + DO_TEST_ADD_STR("<a/>\n", "<c>\n <a/>\n</c>"); + DO_TEST_ADD_STR("<b>\n <a/>\n</b>\n", "<c>\n <b>\n <a/>\n </b>\n</c>"); + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.2.2

Recently we've fixed a bug where the status XML could not be parsed as the parser used absolute path XPath queries. This test enhancement tests all XML files used in the qemu-xml-2-xml test as a part of a status XML snippet to see whether they are parsed correctly. The status XML-2-XML is currently tested in 223 cases with this patch. --- src/conf/domain_conf.c | 4 +- src/conf/domain_conf.h | 9 ++++ src/libvirt_private.syms | 2 + tests/qemuxml2xmltest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 0d4b165..9324de0 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -15580,7 +15580,7 @@ virDomainDefParseNode(xmlDocPtr xml, } -static virDomainObjPtr +virDomainObjPtr virDomainObjParseNode(xmlDocPtr xml, xmlNodePtr root, virCapsPtr caps, @@ -21252,7 +21252,7 @@ virDomainDefFormat(virDomainDefPtr def, unsigned int flags) } -static char * +char * virDomainObjFormat(virDomainXMLOptionPtr xmlopt, virDomainObjPtr obj, unsigned int flags) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bceb2d7..608f61f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2565,6 +2565,12 @@ virDomainDefPtr virDomainDefParseNode(xmlDocPtr doc, virDomainXMLOptionPtr xmlopt, unsigned int expectedVirtTypes, unsigned int flags); +virDomainObjPtr virDomainObjParseNode(xmlDocPtr xml, + xmlNodePtr root, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + unsigned int expectedVirtTypes, + unsigned int flags); virDomainObjPtr virDomainObjParseFile(const char *filename, virCapsPtr caps, virDomainXMLOptionPtr xmlopt, @@ -2580,6 +2586,9 @@ unsigned int virDomainDefFormatConvertXMLFlags(unsigned int flags); char *virDomainDefFormat(virDomainDefPtr def, unsigned int flags); +char *virDomainObjFormat(virDomainXMLOptionPtr xmlopt, + virDomainObjPtr obj, + unsigned int flags); int virDomainDefFormatInternal(virDomainDefPtr def, unsigned int flags, virBufferPtr buf); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 893e181..839702b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -364,6 +364,7 @@ virDomainNostateReasonTypeFromString; virDomainNostateReasonTypeToString; virDomainObjAssignDef; virDomainObjCopyPersistentDef; +virDomainObjFormat; virDomainObjGetMetadata; virDomainObjGetPersistentDef; virDomainObjGetState; @@ -382,6 +383,7 @@ virDomainObjListNumOfDomains; virDomainObjListRemove; virDomainObjListRemoveLocked; virDomainObjNew; +virDomainObjParseNode; virDomainObjSetDefTransient; virDomainObjSetMetadata; virDomainObjSetState; diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index e6d4e6f..817e408 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -106,6 +106,113 @@ testXML2XMLInactive(const void *opaque) } +static const char testStatusXMLPrefix[] = +"<domstatus state='running' reason='booted' pid='3803518'>\n" +" <taint flag='high-privileges'/>\n" +" <monitor path='/var/lib/libvirt/qemu/test.monitor' json='1' type='unix'/>\n" +" <vcpus>\n" +" <vcpu pid='3803519'/>\n" +" </vcpus>\n" +" <qemuCaps>\n" +" <flag name='vnc-colon'/>\n" +" <flag name='no-reboot'/>\n" +" <flag name='drive'/>\n" +" <flag name='name'/>\n" +" <flag name='uuid'/>\n" +" <flag name='vnet-hdr'/>\n" +" <flag name='qxl.vgamem_mb'/>\n" +" <flag name='qxl-vga.vgamem_mb'/>\n" +" <flag name='pc-dimm'/>\n" +" </qemuCaps>\n" +" <devices>\n" +" <device alias='balloon0'/>\n" +" <device alias='video0'/>\n" +" <device alias='serial0'/>\n" +" <device alias='net0'/>\n" +" <device alias='usb'/>\n" +" </devices>\n"; + +static const char testStatusXMLSuffix[] = +"</domstatus>\n"; + + +static int +testCompareStatusXMLToXMLFiles(const void *opaque) +{ + const struct testInfo *data = opaque; + virBuffer buf = VIR_BUFFER_INITIALIZER; + xmlDocPtr xml = NULL; + virDomainObjPtr obj = NULL; + char *expect = NULL; + char *actual = NULL; + char *source = NULL; + int ret = -1; + int keepBlanksDefault = xmlKeepBlanksDefault(0); + + /* construct faked source status XML */ + virBufferAdd(&buf, testStatusXMLPrefix, -1); + virBufferAdjustIndent(&buf, 2); + virBufferAddStr(&buf, data->inFile); + virBufferAdjustIndent(&buf, -2); + virBufferAdd(&buf, testStatusXMLSuffix, -1); + + if (!(source = virBufferContentAndReset(&buf))) { + fprintf(stderr, "Failed to create the source XML"); + goto cleanup; + } + + /* construct the expect string */ + virBufferAdd(&buf, testStatusXMLPrefix, -1); + virBufferAdjustIndent(&buf, 2); + virBufferAddStr(&buf, data->outActiveFile); + virBufferAdjustIndent(&buf, -2); + virBufferAdd(&buf, testStatusXMLSuffix, -1); + + if (!(expect = virBufferContentAndReset(&buf))) { + fprintf(stderr, "Failed to create the expect XML"); + goto cleanup; + } + + /* parse the fake source status XML */ + if (!(xml = virXMLParseString(source, "(domain_status_test_XML)")) || + !(obj = virDomainObjParseNode(xml, xmlDocGetRootElement(xml), + driver.caps, driver.xmlopt, + QEMU_EXPECTED_VIRT_TYPES, + VIR_DOMAIN_DEF_PARSE_STATUS | + VIR_DOMAIN_DEF_PARSE_ACTUAL_NET | + VIR_DOMAIN_DEF_PARSE_PCI_ORIG_STATES | + VIR_DOMAIN_DEF_PARSE_CLOCK_ADJUST))) { + fprintf(stderr, "Failed to parse domain status XML:\n%s", source); + goto cleanup; + } + + /* format it back */ + if (!(actual = virDomainObjFormat(driver.xmlopt, obj, + VIR_DOMAIN_DEF_FORMAT_SECURE))) { + fprintf(stderr, "Failed to format domain status XML"); + goto cleanup; + } + + if (STRNEQ(actual, expect)) { + virtTestDifferenceFull(stderr, + expect, data->outActiveName, + actual, data->inName); + goto cleanup; + } + + ret = 0; + + cleanup: + xmlKeepBlanksDefault(keepBlanksDefault); + xmlFreeDoc(xml); + virObjectUnref(obj); + VIR_FREE(expect); + VIR_FREE(actual); + VIR_FREE(source); + return ret; +} + + static void testInfoFree(struct testInfo *info) { @@ -218,6 +325,10 @@ mymain(void) if (virtTestRun("QEMU XML-2-XML-active " name, \ testXML2XMLActive, &info) < 0) \ ret = -1; \ + \ + if (virtTestRun("QEMU XML-2-XML-status " name, \ + testCompareStatusXMLToXMLFiles, &info) < 0) \ + ret = -1; \ } \ testInfoFree(&info); \ } while (0) -- 2.2.2

On Wed, Mar 25, 2015 at 02:05:38PM +0100, Peter Krempa wrote:
Peter Krempa (2): util: buffer: Add support for adding text blocks with indentation tests: qemuxml2xml: Test status XML formatting and parsing
src/conf/domain_conf.c | 4 +- src/conf/domain_conf.h | 9 ++++ src/libvirt_private.syms | 3 ++ src/util/virbuffer.c | 29 +++++++++++++ src/util/virbuffer.h | 1 + tests/qemuxml2xmltest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ tests/virbuftest.c | 49 +++++++++++++++++++++ 7 files changed, 204 insertions(+), 2 deletions(-)
ACK series.

On Wed, Mar 25, 2015 at 14:58:01 +0100, Martin Kletzander wrote:
On Wed, Mar 25, 2015 at 02:05:38PM +0100, Peter Krempa wrote:
Peter Krempa (2): util: buffer: Add support for adding text blocks with indentation tests: qemuxml2xml: Test status XML formatting and parsing
src/conf/domain_conf.c | 4 +- src/conf/domain_conf.h | 9 ++++ src/libvirt_private.syms | 3 ++ src/util/virbuffer.c | 29 +++++++++++++ src/util/virbuffer.h | 1 + tests/qemuxml2xmltest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ tests/virbuftest.c | 49 +++++++++++++++++++++ 7 files changed, 204 insertions(+), 2 deletions(-)
ACK series.
Pushed; Thanks. Peter
participants (2)
-
Martin Kletzander
-
Peter Krempa