diff --git a/tests/meson.build b/tests/meson.build index ebac2131dc..7e7427bb15 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -448,6 +448,7 @@ if conf.has('WITH_QEMU') { 'name': 'qemuhotplugtest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemumemlocktest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemumigparamstest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, + { 'name': 'qemumigrationcookiexmltest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib, test_file_wrapper_lib ] }, { 'name': 'qemumonitorjsontest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemusecuritytest', 'sources': [ 'qemusecuritytest.c', 'qemusecuritymock.c' ], 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemustatusxml2xmltest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib, test_file_wrapper_lib ] }, diff --git a/tests/qemumigrationcookiexmldata/basic-xml2xml-in.xml b/tests/qemumigrationcookiexmldata/basic-xml2xml-in.xml new file mode 100644 index 0000000000..5722bafe89 --- /dev/null +++ b/tests/qemumigrationcookiexmldata/basic-xml2xml-in.xml @@ -0,0 +1,6 @@ + + upstream + dcf47dbd-46d1-4d5b-b442-262a806a333a + hostname2 + 8b3f4dc4-6a8e-5f9b-94a5-4c35babd8d95 + diff --git a/tests/qemumigrationcookiexmldata/basic-xml2xml-out.xml b/tests/qemumigrationcookiexmldata/basic-xml2xml-out.xml new file mode 100644 index 0000000000..42b351047e --- /dev/null +++ b/tests/qemumigrationcookiexmldata/basic-xml2xml-out.xml @@ -0,0 +1,9 @@ + + upstream + dcf47dbd-46d1-4d5b-b442-262a806a333a + hostname + 4a802f00-4cba-5df6-9679-a08c4c5b577f + + + + diff --git a/tests/qemumigrationcookiexmldata/modern-dom-out-dest.xml b/tests/qemumigrationcookiexmldata/modern-dom-out-dest.xml new file mode 100644 index 0000000000..ba84c65a3d --- /dev/null +++ b/tests/qemumigrationcookiexmldata/modern-dom-out-dest.xml @@ -0,0 +1,12 @@ + + upstream + dcf47dbd-46d1-4d5b-b442-262a806a333a + hostname2 + 8b3f4dc4-6a8e-5f9b-94a5-4c35babd8d95 + + + + + + + diff --git a/tests/qemumigrationcookiexmldata/modern-dom-out-source.xml b/tests/qemumigrationcookiexmldata/modern-dom-out-source.xml new file mode 100644 index 0000000000..ba84c65a3d --- /dev/null +++ b/tests/qemumigrationcookiexmldata/modern-dom-out-source.xml @@ -0,0 +1,12 @@ + + upstream + dcf47dbd-46d1-4d5b-b442-262a806a333a + hostname2 + 8b3f4dc4-6a8e-5f9b-94a5-4c35babd8d95 + + + + + + + diff --git a/tests/qemumigrationcookiexmltest.c b/tests/qemumigrationcookiexmltest.c new file mode 100644 index 0000000000..e492e4b35e --- /dev/null +++ b/tests/qemumigrationcookiexmltest.c @@ -0,0 +1,336 @@ +/* + * 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 + * . + */ + +#include + +#include + +#include +#include + +#include "testutils.h" + +#include "internal.h" +#include "testutilsqemu.h" +#include "configmake.h" + +#include "qemu/qemu_migration_cookie.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +static virQEMUDriver driver; + +static virBuffer testnamebuf = VIR_BUFFER_INITIALIZER; + +static const char * +tn(const char *str, ...) +{ + va_list ap; + + virBufferFreeAndReset(&testnamebuf); + virBufferAdd(&testnamebuf, str, -1); + + va_start(ap, str); + virBufferStrcatVArgs(&testnamebuf, ap); + va_end(ap); + + return virBufferCurrentContent(&testnamebuf); +} + + +struct testQemuMigrationCookieData { + const char *name; + char *inStatus; + virDomainObjPtr vm; + + unsigned int cookiePopulateFlags; + unsigned int cookieParseFlags; + + qemuMigrationParty cookiePopulateParty; + + char *xmlstr; + int xmlstrlen; + char *infile; + char *outfile; +}; + + +static int +testQemuMigrationCookiePopulate(const void *opaque) +{ + struct testQemuMigrationCookieData *data = (struct testQemuMigrationCookieData *) opaque; + g_autoptr(qemuMigrationCookie) cookie = NULL; + + if (!(cookie = qemuMigrationCookieNew(data->vm->def, NULL))) + return -1; + + /* doctor the hostname and uuid, so that the output can be simply used for + * the xml2xmltest where the parser validates UUID match (yuck) */ + g_free(cookie->localHostname); + cookie->localHostname = g_strdup("hostname2"); + + /* uuidgen --sha1 --namespace @dns --name "hostname2" */ + if (virUUIDParse("8b3f4dc4-6a8e-5f9b-94a5-4c35babd8d95", cookie->localHostuuid) < 0) { + VIR_TEST_DEBUG("\nfailed to parse fake UUID"); + return -1; + } + + /* allow re-run for checking both miration parties */ + g_clear_pointer(&data->xmlstr, g_free); + + if (qemuMigrationCookieFormat(cookie, + &driver, + data->vm, + data->cookiePopulateParty, + &data->xmlstr, + &data->xmlstrlen, + data->cookiePopulateFlags) < 0) { + VIR_TEST_DEBUG("\n failed to populate and format qemu migration cookie"); + return -1; + } + + if (virTestCompareToFile(data->xmlstr, data->outfile) < 0) + return -1; + + return 0; +} + + +static int +testQemuMigrationCookieParse(const void *opaque) +{ + struct testQemuMigrationCookieData *data = (struct testQemuMigrationCookieData *) opaque; + qemuDomainObjPrivatePtr priv = data->vm->privateData; + g_auto(virBuffer) actual = VIR_BUFFER_INITIALIZER; + g_autoptr(qemuMigrationCookie) cookie = NULL; + + if (!(cookie = qemuMigrationCookieParse(&driver, + data->vm->def, + NULL, + priv, + data->xmlstr, + data->xmlstrlen, + data->cookieParseFlags))) { + VIR_TEST_DEBUG("\nfailed to parse qemu migration cookie:\n%s\n", data->xmlstr); + return -1; + } + + /* set all flags so that formatter attempts to format everything */ + cookie->flags = ~0; + + if (qemuMigrationCookieXMLFormat(&driver, + priv->qemuCaps, + &actual, + cookie) < 0) { + VIR_TEST_DEBUG("\nfailed to format back qemu migration cookie"); + return -1; + } + + if (virTestCompareToFile(virBufferCurrentContent(&actual), data->outfile) < 0) + return -1; + + return 0; +} + + +static int +testQemuMigrationCookieDomInit(const void *opaque) +{ + struct testQemuMigrationCookieData *data = (struct testQemuMigrationCookieData *) opaque; + + if (!(data->vm = virDomainObjParseFile(data->inStatus, driver.xmlopt, + VIR_DOMAIN_DEF_PARSE_STATUS | + VIR_DOMAIN_DEF_PARSE_ACTUAL_NET | + VIR_DOMAIN_DEF_PARSE_PCI_ORIG_STATES | + VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE | + VIR_DOMAIN_DEF_PARSE_ALLOW_POST_PARSE_FAIL))) { + VIR_TEST_DEBUG("\nfailed to parse status xml'%s'", data->inStatus); + return -1; + } + + return 0; +} + + +static int +testQemuMigrationCookieXMLLoad(const void *opaque) +{ + struct testQemuMigrationCookieData *data = (struct testQemuMigrationCookieData *) opaque; + + if (virTestLoadFile(data->infile, &data->xmlstr) < 0) + return -1; + + data->xmlstrlen = strlen(data->xmlstr) + 1; + + return 0; +} + + +static void +testQemuMigrationCookieDataFree(struct testQemuMigrationCookieData *data) +{ + if (!data) + return; + + g_free(data->xmlstr); + g_free(data->outfile); + g_free(data->infile); + g_free(data->inStatus); + virDomainObjEndAPI(&data->vm); + g_free(data); +} + + +static int +testQemuMigrationCookieDom2XML(const char *namesuffix, + const char *domxml, + unsigned int cookiePopulateFlags, + unsigned int cookieParseFlags) +{ + struct testQemuMigrationCookieData *data = g_new0(struct testQemuMigrationCookieData, 1); + int ret = 0; + + if (cookiePopulateFlags == 0) { + /* flags unsupported by default: + * - lockstate: internals are NULL in tests, causes crash + * - nbd: monitor not present + */ + unsigned int cookiePopulateFlagMask = QEMU_MIGRATION_COOKIE_LOCKSTATE | + QEMU_MIGRATION_COOKIE_NBD; + data->cookiePopulateFlags = ~cookiePopulateFlagMask; + } + + if (cookieParseFlags == 0) + data->cookieParseFlags = ~0; + + data->inStatus = g_strconcat(abs_srcdir, "/", domxml, NULL); + + /* load status XML as domain object */ + + if (virTestRun(tn("qemumigrationcookiedom2xml-load-", namesuffix, NULL), + testQemuMigrationCookieDomInit, data) < 0) + ret = -1; + + /* test dom -> migration cookie conversion for source */ + + data->cookiePopulateParty = QEMU_MIGRATION_SOURCE; + data->outfile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + namesuffix, "-dom-out-source.xml", NULL); + + if (virTestRun(tn("qemumigrationcookiedom2xml-source-populate-", namesuffix, NULL), + testQemuMigrationCookiePopulate, data) < 0) + ret = -1; + + /* test dom -> migration cookie conversion for destination */ + + g_free(data->outfile); + data->cookiePopulateParty = QEMU_MIGRATION_DESTINATION; + data->outfile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + namesuffix, "-dom-out-dest.xml", NULL); + + if (virTestRun(tn("qemumigrationcookiedom2xml-dest-populate-", namesuffix, NULL), + testQemuMigrationCookiePopulate, data) < 0) + ret = -1; + + testQemuMigrationCookieDataFree(data); + + return ret; +} + + +static int +testQemuMigrationCookieXML2XML(const char *name, + const char *statusxml, + unsigned int cookieParseFlags) +{ + struct testQemuMigrationCookieData *data = g_new0(struct testQemuMigrationCookieData, 1); + int ret = 0; + + if (cookieParseFlags == 0) + data->cookieParseFlags = ~0; + + data->inStatus = g_strconcat(abs_srcdir, "/", statusxml, NULL); + data->infile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + name, "-xml2xml-in.xml", NULL); + data->outfile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + name, "-xml2xml-out.xml", NULL); + + if (virTestRun(tn("qemumigrationcookieXML2XML-dom-", name, NULL), + testQemuMigrationCookieDomInit, data) < 0) + ret = -1; + + if (virTestRun(tn("qemumigrationcookieXML2XML-load-", name, NULL), + testQemuMigrationCookieXMLLoad, data) < 0) + ret = -1; + + if (virTestRun(tn("qemumigrationcookieXML2XML-parse-", name, NULL), + testQemuMigrationCookieParse, data) < 0) + ret = -1; + + testQemuMigrationCookieDataFree(data); + + return ret; +} + + +static int +mymain(void) +{ + int ret = 0; + g_autoptr(virQEMUDriverConfig) cfg = NULL; + g_autoptr(GHashTable) capslatest = NULL; + g_autoptr(virConnect) conn = NULL; + + capslatest = testQemuGetLatestCaps(); + if (!capslatest) + return EXIT_FAILURE; + + if (qemuTestDriverInit(&driver) < 0) + return EXIT_FAILURE; + + cfg = virQEMUDriverGetConfig(&driver); + driver.privileged = true; + + if (!(conn = virGetConnect())) + goto cleanup; + + virSetConnectInterface(conn); + virSetConnectNetwork(conn); + virSetConnectNWFilter(conn); + virSetConnectNodeDev(conn); + virSetConnectSecret(conn); + virSetConnectStorage(conn); + + if (testQemuMigrationCookieDom2XML("modern", "qemustatusxml2xmldata/modern-in.xml", 0, 0) < 0) + ret = -1; + + if (testQemuMigrationCookieXML2XML("basic", "qemustatusxml2xmldata/modern-in.xml", 0) < 0) + ret = -1; + + virBufferFreeAndReset(&testnamebuf); + + cleanup: + + qemuTestDriverFree(&driver); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIR_TEST_MAIN_PRELOAD(mymain, + VIR_TEST_MOCK("virpci"), + VIR_TEST_MOCK("virrandom"), + VIR_TEST_MOCK("domaincaps"), + VIR_TEST_MOCK("virhostid"))