[libvirt] [PATCH v2 7/7] nss: Introduce a test

Michal Privoznik mprivozn at redhat.com
Thu Feb 18 14:21:07 UTC 2016


A small test to see how is the nss module working.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 cfg.mk                      |   2 +-
 tests/Makefile.am           |  18 +++++
 tests/nssdata/virbr0.status |  14 ++++
 tests/nssmock.c             | 140 +++++++++++++++++++++++++++++++++
 tests/nsstest.c             | 184 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 357 insertions(+), 1 deletion(-)
 create mode 100644 tests/nssdata/virbr0.status
 create mode 100644 tests/nssmock.c
 create mode 100644 tests/nsstest.c

diff --git a/cfg.mk b/cfg.mk
index 5b864af..6f28eef 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1139,7 +1139,7 @@ exclude_file_name_regexp--sc_copyright_usage = \
   ^COPYING(|\.LESSER)$$
 
 exclude_file_name_regexp--sc_flags_usage = \
-  ^(docs/|src/util/virnetdevtap\.c$$|tests/vir(cgroup|pci|usb)mock\.c$$)
+  ^(docs/|src/util/virnetdevtap\.c$$|tests/(vir(cgroup|pci|usb)|nss)mock\.c$$)
 
 exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \
   ^(src/rpc/gendispatch\.pl$$|tests/)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 90981dc..99ef99f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -108,6 +108,7 @@ EXTRA_DIST =		\
 	nodedevschemadata \
 	nodedevschematest \
 	nodeinfodata     \
+	nssdata \
 	nwfilterschematest \
 	nwfilterxml2firewalldata \
 	nwfilterxml2xmlin \
@@ -190,6 +191,7 @@ test_programs = virshtest sockettest \
 	vircaps2xmltest \
 	virnetdevtest \
 	virtypedparamtest \
+	nsstest \
 	$(NULL)
 
 if WITH_REMOTE
@@ -421,6 +423,7 @@ test_libraries = libshunload.la \
 		virpcimock.la \
 		virnetdevmock.la \
 		nodeinfomock.la \
+		nssmock.la \
 		$(NULL)
 if WITH_QEMU
 test_libraries += libqemumonitortestutils.la \
@@ -1067,6 +1070,21 @@ nodeinfomock_la_CFLAGS = $(AM_CFLAGS)
 nodeinfomock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
 nodeinfomock_la_LIBADD = $(MOCKLIBS_LIBS)
 
+nsstest_SOURCES = \
+	nsstest.c testutils.h testutils.c
+nsstest_CFLAGS = \
+	$(AM_CFLAGS)	\
+	-I$(top_srcdir)/tools/nss
+nsstest_LDADD = \
+	$(LDADDS) \
+	../tools/nss/libnss_libvirt_impl.la
+
+nssmock_la_SOURCES = \
+	nssmock.c
+nssmock_la_CFLAGS = $(AM_CFLAGS)
+nssmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)
+nssmock_la_LIBADD = $(MOCKLIBS_LIBS)
+
 virnetdevtest_SOURCES = \
 	virnetdevtest.c testutils.h testutils.c
 virnetdevtest_CFLAGS = $(AM_CFLAGS) $(LIBNL_CFLAGS)
diff --git a/tests/nssdata/virbr0.status b/tests/nssdata/virbr0.status
new file mode 100644
index 0000000..de5aceb
--- /dev/null
+++ b/tests/nssdata/virbr0.status
@@ -0,0 +1,14 @@
+[
+    {
+        "ip-address": "192.168.122.197",
+        "mac-address": "52:54:00:a4:6f:91",
+        "hostname": "fedora",
+        "expiry-time": 1900000000
+    },
+    {
+        "ip-address": "192.168.122.254",
+        "mac-address": "52:54:00:3a:b5:0c",
+        "hostname": "gentoo",
+        "expiry-time": 2000000000
+    }
+]
diff --git a/tests/nssmock.c b/tests/nssmock.c
new file mode 100644
index 0000000..b4a4260
--- /dev/null
+++ b/tests/nssmock.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 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/>.
+ *
+ * Author: Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#ifdef __linux__
+# include <stdio.h>
+# include <stdlib.h>
+# include <dlfcn.h>
+# include <sys/types.h>
+# include <dirent.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+
+# include "configmake.h"
+# include "internal.h"
+# include "virstring.h"
+# include "viralloc.h"
+
+static int (*realopen)(const char *path, int flags, ...);
+static DIR * (*realopendir)(const char *name);
+
+# define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
+
+# define STDERR(...)                                                    \
+    fprintf(stderr, "%s %zu: ", __FUNCTION__, (size_t) __LINE__);       \
+    fprintf(stderr, __VA_ARGS__);                                       \
+    fprintf(stderr, "\n");                                              \
+
+# define ABORT(...)                                                     \
+    do {                                                                \
+        STDERR(__VA_ARGS__);                                            \
+        abort();                                                        \
+    } while (0)
+
+# define ABORT_OOM()                                                    \
+    ABORT("Out of memory")
+
+/*
+ * Functions to load the symbols and init the environment
+ */
+static void
+init_syms(void)
+{
+    if (realopen)
+        return;
+
+# define LOAD_SYM(name)                                                 \
+    do {                                                                \
+        if (!(real ## name = dlsym(RTLD_NEXT, #name)))                  \
+            ABORT("Cannot find real '%s' symbol\n", #name);             \
+    } while (0)
+
+    LOAD_SYM(open);
+    LOAD_SYM(opendir);
+}
+
+static int
+getrealpath(char **newpath,
+            const char *path)
+{
+    if (STRPREFIX(path, LEASEDIR)) {
+        if (virAsprintfQuiet(newpath, "%s/nssdata/%s",
+                             abs_srcdir,
+                             path + strlen(LEASEDIR)) < 0) {
+            errno = ENOMEM;
+            return -1;
+        }
+    } else {
+        if (VIR_STRDUP_QUIET(*newpath, path) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+int
+open(const char *path, int flags, ...)
+{
+    int ret;
+    char *newpath = NULL;
+
+    init_syms();
+
+    if (STRPREFIX(path, LEASEDIR) &&
+        getrealpath(&newpath, path) < 0)
+        return -1;
+
+    if (flags & O_CREAT) {
+        va_list ap;
+        mode_t mode;
+        va_start(ap, flags);
+        mode = va_arg(ap, mode_t);
+        va_end(ap);
+        ret = realopen(newpath ? newpath : path, flags, mode);
+    } else {
+        ret = realopen(newpath ? newpath : path, flags);
+    }
+
+    VIR_FREE(newpath);
+    return ret;
+}
+
+DIR *
+opendir(const char *path)
+{
+    DIR *ret;
+    char *newpath = NULL;
+
+    init_syms();
+
+    if (STRPREFIX(path, LEASEDIR) &&
+        getrealpath(&newpath, path) < 0)
+        return NULL;
+
+    ret = realopendir(newpath ? newpath : path);
+
+    VIR_FREE(newpath);
+    return ret;
+}
+#else
+/* Nothing to override on non-__linux__ platforms */
+#endif
diff --git a/tests/nsstest.c b/tests/nsstest.c
new file mode 100644
index 0000000..932f9a8
--- /dev/null
+++ b/tests/nsstest.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 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/>.
+ *
+ * Author: Michal Privoznik <mprivozn at redhat.com>
+ */
+
+#include <config.h>
+
+#include "testutils.h"
+
+#ifdef __linux__
+
+# include <stdbool.h>
+# include <arpa/inet.h>
+# include "libvirt_nss.h"
+
+# define VIR_FROM_THIS VIR_FROM_NONE
+
+# define BUF_SIZE 1024
+
+struct testNSSData {
+    const char *hostname;
+    const char *ipAddr;
+};
+
+static int
+testGetHostByName(const void *opaque)
+{
+    const struct testNSSData *data = opaque;
+    const bool existent = data->hostname && data->ipAddr;
+    int ret = -1;
+    struct hostent resolved;
+    char buf[BUF_SIZE] = { 0 };
+    char **addrList;
+    int rv, tmp_errno = 0, tmp_herrno = 0;
+    size_t i;
+
+    if (!data)
+        goto cleanup;
+
+    memset(&resolved, 0, sizeof(resolved));
+
+    rv = _nss_libvirt_gethostbyname_r(data->hostname,
+                                      &resolved,
+                                      buf, sizeof(buf),
+                                      &tmp_errno,
+                                      &tmp_herrno);
+
+    if (rv == NSS_STATUS_TRYAGAIN ||
+        rv == NSS_STATUS_UNAVAIL ||
+        rv == NSS_STATUS_RETURN) {
+        /* Resolving failed in unexpected fashion. */
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "Resolving of %s failed due to internal error",
+                       data->hostname);
+        goto cleanup;
+    } else if (rv == NSS_STATUS_NOTFOUND) {
+        /* Resolving failed. Should it? */
+        if (!existent)
+            ret = 0;
+        else
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "Resolving of %s failed",
+                           data->hostname);
+        goto cleanup;
+    }
+
+    /* Resolving succeeded. Should it? */
+    if (!existent) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "Resolving of %s succeeded but was expected to fail",
+                       data->hostname);
+        goto cleanup;
+    }
+
+    /* Now lets see if resolved address match our expectations. */
+
+    if (!resolved.h_name) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "resolved.h_name empty");
+        goto cleanup;
+    }
+
+    if (resolved.h_addrtype != AF_INET) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "Expected AF_INET (%d) got %d",
+                       AF_INET, resolved.h_addrtype);
+        goto cleanup;
+    }
+
+    if (resolved.h_length != 4) {
+        /* IPv4 addresses are encoded into 4 bytes */
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "Expected 4 bytes long address, got %d",
+                       resolved.h_length);
+        goto cleanup;
+    }
+
+    if (!resolved.h_addr_list) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "resolved.h_addr_list empty");
+        goto cleanup;
+    }
+
+    addrList = resolved.h_addr_list;
+    i = 0;
+    while (*addrList) {
+        virSocketAddr sa;
+        char *ipAddr;
+
+        /* For some reason, virSocketAddrSetIPv4Addr does htonl() conversion.
+         * But the data we already have is in network order. */
+        virSocketAddrSetIPv4Addr(&sa, ntohl(*((uint32_t *) *addrList)));
+
+        if (i == 0) {
+            if (!(ipAddr = virSocketAddrFormat(&sa))) {
+                /* error reported by helper */
+                goto cleanup;
+            }
+            if (STRNEQ(data->ipAddr, ipAddr)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               "Address mismatch. Expected %s got %s",
+                               data->ipAddr, ipAddr);
+                VIR_FREE(ipAddr);
+                goto cleanup;
+            }
+            VIR_FREE(ipAddr);
+        } else {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           "Got more addresses than expected (1)");
+            goto cleanup;
+        }
+
+        addrList++;
+    }
+
+    ret = 0;
+ cleanup:
+    return ret;
+}
+
+static int
+mymain(void)
+{
+    int ret = 0;
+
+# define DO_TEST(name, address)                                 \
+    do {                                                        \
+        struct testNSSData data = {                             \
+            .hostname = name, .ipAddr = address,                \
+        };                                                      \
+        if (virtTestRun(name, testGetHostByName, &data) < 0)    \
+            ret = -1;                                           \
+    } while (0)
+
+    DO_TEST("fedora", "192.168.122.197");
+    DO_TEST("gentoo", "192.168.122.254");
+    DO_TEST("non-existent", NULL);
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/nssmock.so")
+#else
+int
+main(void)
+{
+    return EXIT_AM_SKIP;
+}
+#endif
-- 
2.4.10




More information about the libvir-list mailing list