--- /dev/null
+/*
+ * 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 <unistd.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#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"))