[libvirt PATCH 4/4] Add Test driver and testcase for Network Metadata change APIs

K Shiva Kiran shiva_kr at riseup.net
Tue Jul 11 06:47:26 UTC 2023


This commit implements the newly defined Network Metadata Get and
Set APIs into the test driver.
It also adds a new testcase "networkmetadatatest" to test the APIs.

Signed-off-by: K Shiva Kiran <shiva_kr at riseup.net>
---
 src/conf/network_conf.c     |   3 +
 src/test/test_driver.c      |  67 ++++++++
 tests/meson.build           |   1 +
 tests/networkmetadatatest.c | 297 ++++++++++++++++++++++++++++++++++++
 4 files changed, 368 insertions(+)
 create mode 100644 tests/networkmetadatatest.c

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 427635250c..8f39b4ed67 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -2564,6 +2564,9 @@ virNetworkSaveXML(const char *configDir,
     char uuidstr[VIR_UUID_STRING_BUFLEN];
     g_autofree char *configFile = NULL;
 
+    if (!configDir)
+        return 0;
+
     if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
         return -1;
 
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index e7fce053b4..af65c53bfc 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -633,6 +633,25 @@ static int testStoragePoolObjSetDefaults(virStoragePoolObj *obj);
 static int testNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
 static virNetworkObj *testNetworkObjFindByName(testDriver *privconn, const char *name);
 
+static virNetworkObj *
+testNetworkObjFromNetwork(virNetworkPtr network)
+{
+    virNetworkObj *net;
+    testDriver *driver = network->conn->privateData;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+    net = virNetworkObjFindByUUID(driver->networks, network->uuid);
+    if (!net) {
+        virUUIDFormat(network->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_NETWORK,
+                       _("no network with matching uuid '%1$s' (%2$s)"),
+                       uuidstr, network->name);
+    }
+
+    return net;
+}
+
+
 static virDomainObj *
 testDomObjFromDomain(virDomainPtr domain)
 {
@@ -9948,6 +9967,52 @@ testConnectGetAllDomainStats(virConnectPtr conn,
     return ret;
 }
 
+static char *
+testNetworkGetMetadata(virNetworkPtr net,
+                       int type,
+                       const char *uri,
+                       unsigned int flags)
+{
+    virNetworkObj *privnet;
+    char *ret;
+
+    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
+                  VIR_NETWORK_UPDATE_AFFECT_CONFIG, NULL);
+
+    if (!(privnet = testNetworkObjFromNetwork(net)))
+        return NULL;
+
+    ret = virNetworkObjGetMetadata(privnet, type, uri, flags);
+
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
+static int
+testNetworkSetMetadata(virNetworkPtr net,
+                       int type,
+                       const char *metadata,
+                       const char *key,
+                       const char *uri,
+                       unsigned int flags)
+{
+    virNetworkObj *privnet;
+    int ret;
+
+    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
+                  VIR_NETWORK_UPDATE_AFFECT_CONFIG, -1);
+
+    if (!(privnet = testNetworkObjFromNetwork(net)))
+        return -1;
+
+    ret = virNetworkObjSetMetadata(privnet, type, metadata,
+                                   key, uri, NULL,
+                                   NULL, NULL, flags);
+
+    virNetworkObjEndAPI(&privnet);
+    return ret;
+}
+
 /*
  * Test driver
  */
@@ -10141,6 +10206,8 @@ static virNetworkDriver testNetworkDriver = {
     .networkSetAutostart = testNetworkSetAutostart, /* 0.3.2 */
     .networkIsActive = testNetworkIsActive, /* 0.7.3 */
     .networkIsPersistent = testNetworkIsPersistent, /* 0.7.3 */
+    .networkSetMetadata = testNetworkSetMetadata, /* 9.6.0 */
+    .networkGetMetadata = testNetworkGetMetadata, /* 9.6.0 */
 };
 
 static virInterfaceDriver testInterfaceDriver = {
diff --git a/tests/meson.build b/tests/meson.build
index 0082446029..d083548c0a 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -258,6 +258,7 @@ tests += [
   { 'name': 'genericxml2xmltest' },
   { 'name': 'interfacexml2xmltest' },
   { 'name': 'metadatatest' },
+  { 'name': 'networkmetadatatest' },
   { 'name': 'networkxml2xmlupdatetest' },
   { 'name': 'nodedevxml2xmltest' },
   { 'name': 'nwfilterxml2xmltest' },
diff --git a/tests/networkmetadatatest.c b/tests/networkmetadatatest.c
new file mode 100644
index 0000000000..4448472776
--- /dev/null
+++ b/tests/networkmetadatatest.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * 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 "testutils.h"
+
+#include "virerror.h"
+#include "virxml.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+static const char metadata1[] =
+"<derp xmlns:foobar='http://foo.bar/'>\n"
+"  <bar>foobar</bar>\n"
+"  <foo fooish='blurb'>foofoo</foo>\n"
+"  <foobar:baz>zomg</foobar:baz>\n"
+"</derp>";
+
+
+static const char metadata1_ns[] =
+"<herp:derp xmlns:foobar='http://foo.bar/' xmlns:herp='http://herp.derp/'>\n"
+"  <herp:bar>foobar</herp:bar>\n"
+"  <herp:foo fooish='blurb'>foofoo</herp:foo>\n"
+"  <foobar:baz>zomg</foobar:baz>\n"
+"</herp:derp>";
+
+
+static const char metadata2[] =
+"<foo>\n"
+"  <bar>baz</bar>\n"
+"</foo>";
+
+
+static const char metadata2_ns[] =
+"<blurb:foo xmlns:blurb='http://herp.derp/'>\n"
+"  <blurb:bar>baz</blurb:bar>\n"
+"</blurb:foo>";
+
+
+static char *
+getMetadataFromXML(virNetworkPtr net)
+{
+    g_autoptr(xmlDoc) doc = NULL;
+    g_autoptr(xmlXPathContext) ctxt = NULL;
+    xmlNodePtr node;
+
+    g_autofree char *xml = NULL;
+
+    if (!(xml = virNetworkGetXMLDesc(net, 0)))
+        return NULL;
+
+    if (!(doc = virXMLParseStringCtxt(xml, "(network_definition)", &ctxt)))
+        return NULL;
+
+    if (!(node = virXPathNode("//metadata/*", ctxt)))
+        return NULL;
+
+    return virXMLNodeToString(node->doc, node);
+}
+
+
+static void
+metadataXMLConvertApostrophe(char *str)
+{
+    do {
+        if (*str == '\"')
+            *str = '\'';
+    } while ((*++str) != '\0');
+}
+
+
+static bool
+verifyMetadata(virNetworkPtr net,
+               const char *expectXML,
+               const char *expectAPI,
+               const char *uri)
+{
+    g_autofree char *metadataXML = NULL;
+    g_autofree char *metadataAPI = NULL;
+
+    if (!expectAPI) {
+        if ((metadataAPI = virNetworkGetMetadata(net,
+                                                VIR_NETWORK_METADATA_ELEMENT,
+                                                uri, 0))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "expected no metadata in API, but got:\n[%s]",
+                           metadataAPI);
+            return false;
+        }
+    } else {
+        if (!(metadataAPI = virNetworkGetMetadata(net,
+                                                 VIR_NETWORK_METADATA_ELEMENT,
+                                                 uri, 0)))
+            return false;
+
+        metadataXMLConvertApostrophe(metadataAPI);
+
+        if (STRNEQ(metadataAPI, expectAPI)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "XML metadata in API doesn't match expected metadata: "
+                           "expected:\n[%s]\ngot:\n[%s]",
+                           expectAPI, metadataAPI);
+            return false;
+        }
+
+    }
+
+    if (!expectXML) {
+        if ((metadataXML = getMetadataFromXML(net))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "expected no metadata in XML, but got:\n[%s]",
+                           metadataXML);
+            return false;
+        }
+    } else {
+        if (!(metadataXML = getMetadataFromXML(net)))
+            return false;
+
+        metadataXMLConvertApostrophe(metadataXML);
+
+        if (STRNEQ(metadataXML, expectXML)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "XML in dump doesn't match expected metadata: "
+                           "expected:\n[%s]\ngot:\n[%s]",
+                           expectXML, metadataXML);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+struct metadataTest {
+    virConnectPtr conn;
+    virNetworkPtr net;
+
+    const char *data;
+    const char *expect;
+    int type;
+    bool fail;
+};
+
+
+static int
+testAssignMetadata(const void *data)
+{
+    const struct metadataTest *test = data;
+
+    if (virNetworkSetMetadata(test->net, VIR_NETWORK_METADATA_ELEMENT,
+                             metadata1, "herp", "http://herp.derp/", 0) < 0)
+        return -1;
+
+    if (!verifyMetadata(test->net, metadata1_ns, metadata1, "http://herp.derp/"))
+        return -1;
+
+    return 0;
+}
+
+static int
+testRewriteMetadata(const void *data)
+{
+    const struct metadataTest *test = data;
+
+    if (virNetworkSetMetadata(test->net, VIR_NETWORK_METADATA_ELEMENT,
+                             metadata2, "blurb", "http://herp.derp/", 0) < 0)
+        return -1;
+
+    if (!verifyMetadata(test->net, metadata2_ns, metadata2, "http://herp.derp/"))
+        return -1;
+
+    return 0;
+}
+
+static int
+testEraseMetadata(const void *data)
+{
+    const struct metadataTest *test = data;
+
+    if (virNetworkSetMetadata(test->net, VIR_NETWORK_METADATA_ELEMENT,
+                             NULL, NULL, "http://herp.derp/", 0) < 0)
+        return -1;
+
+    if (!verifyMetadata(test->net, NULL, NULL, "http://herp.derp/"))
+        return -1;
+
+    return 0;
+}
+
+static int
+testTextMetadata(const void *data)
+{
+    const struct metadataTest *test = data;
+    g_autofree char *actual = NULL;
+
+    if (virNetworkSetMetadata(test->net, test->type, test->data, NULL, NULL, 0) < 0) {
+        if (test->fail)
+            return 0;
+        return -1;
+    }
+
+    actual = virNetworkGetMetadata(test->net, test->type, NULL, 0);
+
+    if (STRNEQ_NULLABLE(test->expect, actual)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "expected metadata doesn't match actual: "
+                       "expected:'%s'\ngot: '%s'",
+                       NULLSTR(test->data), NULLSTR(actual));
+        return -1;
+    }
+
+    return 0;
+}
+
+#define TEST_TEXT_METADATA(INDEX, TYPE, DATA, EXPECT, FAIL) \
+    do { \
+        test.type = VIR_NETWORK_METADATA_ ## TYPE; \
+        test.data = DATA; \
+        test.expect = EXPECT; \
+        test.fail = FAIL; \
+ \
+        if (virTestRun("text metadata: " #TYPE " " INDEX " ", \
+                       testTextMetadata, &test) < 0) \
+            ret = EXIT_FAILURE; \
+    } while (0)
+
+#define TEST_TITLE(INDEX, DATA) \
+    TEST_TEXT_METADATA(INDEX, TITLE, DATA, DATA, false)
+#define TEST_TITLE_EXPECT(INDEX, DATA, EXPECT) \
+    TEST_TEXT_METADATA(INDEX, TITLE, DATA, EXPECT, false)
+#define TEST_TITLE_FAIL(INDEX, DATA) \
+    TEST_TEXT_METADATA(INDEX, TITLE, DATA, DATA, true)
+#define TEST_DESCR(INDEX, DATA) \
+    TEST_TEXT_METADATA(INDEX, DESCRIPTION, DATA, DATA, false)
+#define TEST_DESCR_EXPECT(INDEX, DATA, EXPECT) \
+    TEST_TEXT_METADATA(INDEX, DESCRIPTION, DATA, EXPECT, false)
+
+static int
+mymain(void)
+{
+    struct metadataTest test = { 0 };
+    int ret = EXIT_SUCCESS;
+
+    if (!(test.conn = virConnectOpen("test:///default")))
+        return EXIT_FAILURE;
+
+    if (!(test.net = virNetworkLookupByName(test.conn, "default"))) {
+        virConnectClose(test.conn);
+        return EXIT_FAILURE;
+    }
+
+    virTestQuiesceLibvirtErrors(false);
+
+    if (virTestRun("Assign metadata ", testAssignMetadata, &test) < 0)
+        ret = EXIT_FAILURE;
+    if (virTestRun("Rewrite Metadata ", testRewriteMetadata, &test) < 0)
+        ret = EXIT_FAILURE;
+    if (virTestRun("Erase metadata ", testEraseMetadata, &test) < 0)
+        ret = EXIT_FAILURE;
+
+    TEST_TITLE("1", "qwert");
+    TEST_TITLE("2", NULL);
+    TEST_TITLE("3", "blah");
+    TEST_TITLE_FAIL("4", "qwe\nrt");
+    TEST_TITLE_EXPECT("5", "", NULL);
+    TEST_TITLE_FAIL("6", "qwert\n");
+    TEST_TITLE_FAIL("7", "\n");
+
+    TEST_DESCR("1", "qwert\nqwert");
+    TEST_DESCR("2", NULL);
+    TEST_DESCR("3", "qwert");
+    TEST_DESCR("4", "\n");
+    TEST_DESCR_EXPECT("5", "", NULL);
+
+    virNetworkFree(test.net);
+    virConnectClose(test.conn);
+
+    return ret;
+}
+
+VIR_TEST_MAIN(mymain)
-- 
2.41.0



More information about the libvir-list mailing list