tests: Add a test for parsing resolv.conf
authorJakub Hrozek <jhrozek@redhat.com>
Wed, 3 Sep 2014 15:32:27 +0000 (17:32 +0200)
committerMichael Adam <obnox@samba.org>
Tue, 21 Oct 2014 11:39:39 +0000 (13:39 +0200)
Signed-off-by: Jakub Hrozek <jakub.hrozek@gmail.com>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
CMakeLists.txt
tests/CMakeLists.txt [new file with mode: 0644]
tests/test_res_init.c [new file with mode: 0644]

index ab6151d90dcefd0dbcdc112fdd46b1208cca58c2..bcb9b0ca15af3f30d7da00929aec3e43cfa0385b 100644 (file)
@@ -77,8 +77,8 @@ install(
 )
 
 add_subdirectory(doc)
-#if (UNIT_TESTING)
-#    find_package(CMocka REQUIRED)
-#    include(AddCMockaTest)
-#    add_subdirectory(tests)
-#endif (UNIT_TESTING)
+if (UNIT_TESTING)
+    find_package(CMocka REQUIRED)
+    include(AddCMockaTest)
+    add_subdirectory(tests)
+endif (UNIT_TESTING)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..323a768
--- /dev/null
@@ -0,0 +1,31 @@
+project(tests C)
+
+include_directories(
+  ${CMAKE_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}
+  ${CMAKE_SOURCE_DIR}/src
+  ${CMOCKA_INCLUDE_DIR}
+)
+
+set(TESTSUITE_LIBRARIES ${RWRAP_REQUIRED_LIBRARIES} ${CMOCKA_LIBRARY})
+
+set(RWRAP_TESTS
+    test_res_init)
+
+foreach(_RWRAP_TEST ${RWRAP_TESTS})
+    add_cmocka_test(${_RWRAP_TEST} ${_RWRAP_TEST}.c ${TESTSUITE_LIBRARIES})
+
+    if (OSX)
+        set_property(
+            TEST
+                ${_RWRAP_TEST}
+            PROPERTY
+                ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${RESOLV_WRAPPER_LOCATION})
+    else ()
+        set_property(
+            TEST
+                ${_RWRAP_TEST}
+            PROPERTY
+                ENVIRONMENT LD_PRELOAD=${RESOLV_WRAPPER_LOCATION})
+    endif()
+endforeach()
diff --git a/tests/test_res_init.c b/tests/test_res_init.c
new file mode 100644 (file)
index 0000000..0e2d58e
--- /dev/null
@@ -0,0 +1,203 @@
+#include "config.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+
+#define RWRAP_RESOLV_CONF_TMPL "rwrap_resolv_conf_XXXXXX"
+
+struct resolv_conf_test_state {
+       int rc_fd;
+       FILE *resolv_conf;
+       char *resolv_conf_path;
+};
+
+static void setup(void **state)
+{
+       struct resolv_conf_test_state *test_state;
+
+       test_state = malloc(sizeof(struct resolv_conf_test_state));
+       assert_non_null(test_state);
+       test_state->rc_fd = -1;
+       test_state->resolv_conf = NULL;
+
+       test_state->resolv_conf_path = strdup(RWRAP_RESOLV_CONF_TMPL);
+       assert_non_null(test_state->resolv_conf_path);
+       test_state->rc_fd = mkstemp(test_state->resolv_conf_path);
+       assert_non_null(test_state->resolv_conf_path);
+       test_state->resolv_conf = fdopen(test_state->rc_fd, "a");
+       assert_non_null(test_state->resolv_conf);
+
+       *state = test_state;
+}
+
+static void teardown(void **state)
+{
+       struct resolv_conf_test_state *test_state;
+
+       test_state = (struct resolv_conf_test_state *) *state;
+
+       if (test_state == NULL) return;
+
+       if (test_state->resolv_conf) {
+               fclose(test_state->resolv_conf);
+       }
+
+       if (test_state->rc_fd != -1) {
+               close(test_state->rc_fd);
+       }
+
+       if (test_state->resolv_conf_path) {
+               unlink(test_state->resolv_conf_path);
+               free(test_state->resolv_conf_path);
+       }
+
+       free(test_state);
+}
+
+static void test_res_ninit(void **state)
+{
+       struct resolv_conf_test_state *test_state;
+       struct __res_state dnsstate;
+       /*
+        * libc resolver only supports 3 name servers. Make sure the
+        * extra are skipped for both v4 and v6. Also make sure there's
+        * 'too many' nameservers even on platforms where v6 is not
+        * supported.
+        */
+       const char *nameservers[] = {
+               "127.0.0.1",
+               "10.10.10.1",
+               "2607:f8b0:4009:802::1011",
+               "10.10.10.2",
+               "10.10.10.3",
+               "2607:f8b0:4009:802::1012",
+               NULL,
+       };
+       int i;
+       int rv;
+       char straddr[INET6_ADDRSTRLEN] = { '\0' };
+#ifdef HAVE_RESOLV_IPV6_NSADDRS
+       struct sockaddr_in6 *sa6;
+#endif
+
+       test_state = (struct resolv_conf_test_state *) *state;
+
+       /*
+        * Write a valid resolv.conf.
+        * Make sure it's possible to skip comments
+        */
+       fputs("# Hello world\n", test_state->resolv_conf);
+       fputs("; This is resolv_wrapper\n", test_state->resolv_conf);
+       for (i = 0; nameservers[i]; i++) {
+               fputs("nameserver ", test_state->resolv_conf);
+               fputs(nameservers[i], test_state->resolv_conf);
+               fputs("\n", test_state->resolv_conf);
+       }
+       fflush(test_state->resolv_conf);
+
+       rv = setenv("RESOLV_WRAPPER_CONF", test_state->resolv_conf_path, 1);
+       assert_int_equal(rv, 0);
+
+       memset(&dnsstate, 0, sizeof(dnsstate));
+       rv = res_ninit(&dnsstate);
+       unsetenv("RESOLV_WRAPPER_CONF");
+       assert_int_equal(rv, 0);
+
+       /*
+        * Validate the number of parsed name servers.
+        */
+
+       assert_int_equal(dnsstate.nscount + dnsstate._u._ext.nscount, MAXNS);
+
+#ifndef HAVE_RESOLV_IPV6_NSADDRS
+       /*
+        * On platforms that don't support IPv6, the v6 address is skipped
+        * and we end up reading three v4 addresses.
+        */
+       assert_int_equal(dnsstate.nscount, MAXNS);
+#else
+       /*
+        * test we have two v4 and one v6 server
+        *
+        * Note: This test assumes MAXNS == 3, which is the
+        * case on all systems encountered so far.
+        */
+       assert_int_equal(dnsstate.nscount, 2);
+       assert_int_equal(dnsstate._u._ext.nscount, 1);
+#endif /* HAVE_RESOLV_IPV6_NSADDRS */
+
+       /* Validate the servers. */
+
+       /* IPv4 */
+       assert_int_equal(dnsstate.nsaddr_list[0].sin_family, AF_INET);
+       assert_int_equal(dnsstate.nsaddr_list[0].sin_port, htons(53));
+       inet_ntop(AF_INET, &(dnsstate.nsaddr_list[0].sin_addr),
+                 straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[0], straddr);
+
+       assert_int_equal(dnsstate.nsaddr_list[1].sin_family, AF_INET);
+       assert_int_equal(dnsstate.nsaddr_list[1].sin_port, htons(53));
+       inet_ntop(AF_INET, &(dnsstate.nsaddr_list[1].sin_addr),
+                 straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[1], straddr);
+
+#ifndef HAVE_RESOLV_IPV6_NSADDRS
+       /*
+        * On platforms that don't support IPv6, the v6 address is skipped
+        * and we end up reading three v4 addresses.
+        */
+       assert_int_equal(dnsstate.nsaddr_list[2].sin_family, AF_INET);
+       assert_int_equal(dnsstate.nsaddr_list[2].sin_port, htons(53));
+       inet_ntop(AF_INET, &(dnsstate.nsaddr_list[2].sin_addr),
+                 straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[2], straddr);
+#else
+       /* IPv6 */
+       sa6 = dnsstate._u._ext.nsaddrs[0];
+       assert_int_equal(sa6->sin6_family, AF_INET6);
+       assert_int_equal(sa6->sin6_port, htons(53));
+       inet_ntop(AF_INET6, &(sa6->sin6_addr), straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[2], straddr);
+#endif
+}
+
+static void test_res_ninit_enoent(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+
+       (void) state; /* unused */
+
+       rv = setenv("RESOLV_WRAPPER_CONF", "/no/such/file", 1);
+       assert_int_equal(rv, 0);
+
+       /* Just make sure we don't crash, error is fine */
+       memset(&dnsstate, 0, sizeof(dnsstate));
+       rv = res_ninit(&dnsstate);
+       unsetenv("RESOLV_WRAPPER_CONF");
+       assert_int_equal(rv, -1);
+}
+
+int main(void) {
+       int rc;
+
+       const UnitTest tests[] = {
+               unit_test_setup_teardown(test_res_ninit, setup, teardown),
+               unit_test(test_res_ninit_enoent),
+       };
+
+       rc = run_tests(tests);
+       return rc;
+}